From 826b1afb9c7f89fea65f124c384c56a072a65562 Mon Sep 17 00:00:00 2001 From: shadrach68 Date: Thu, 18 Jun 2026 16:38:30 +0100 Subject: [PATCH] feat(defi): implement dynamic protocol adapter registry and auto-discovery --- src/defi/defi/defi.controller.ts | 17 +++++++ src/defi/defi/defi.module.ts | 31 +++++++++++- src/defi/defi/protocols/protocol-registry.ts | 51 +++++++++----------- 3 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/defi/defi/defi.controller.ts b/src/defi/defi/defi.controller.ts index bacb500..c4dafae 100644 --- a/src/defi/defi/defi.controller.ts +++ b/src/defi/defi/defi.controller.ts @@ -37,6 +37,7 @@ import { import { JwtAuthGuard } from "src/core/auth/jwt.guard"; import { User } from "src/core/user/entities/user.entity"; import { CurrentUser } from "src/core/auth/decorators"; +import { ProtocolRegistry, ProtocolAdapterMetadata } from "./protocols/protocol-registry"; @Controller("defi") @UseGuards(JwtAuthGuard) @@ -46,8 +47,24 @@ export class DeFiController { private yieldOptimizationService: YieldOptimizationService, private riskAssessmentService: RiskAssessmentService, private transactionOptimizationService: TransactionOptimizationService, + private protocolRegistry: ProtocolRegistry, ) {} + // ==================== Protocols ==================== + + @Get("protocols") + getAvailableProtocols(): ProtocolAdapterMetadata[] { + return this.protocolRegistry.getAllAdapters().map((adapter) => ({ + name: adapter.name, + supportedChains: adapter.supportedChains, + capabilities: [ + ...(typeof adapter.borrow === "function" ? ["borrow"] : []), + ...(typeof adapter.stake === "function" ? ["stake"] : []), + ...(typeof adapter.getSwapRoute === "function" ? ["swap"] : []), + ], + })); + } + // ==================== Portfolio Management ==================== @Get("portfolio/summary") diff --git a/src/defi/defi/defi.module.ts b/src/defi/defi/defi.module.ts index 58d2f99..71a0fb2 100644 --- a/src/defi/defi/defi.module.ts +++ b/src/defi/defi/defi.module.ts @@ -1,6 +1,7 @@ -import { Module } from "@nestjs/common"; +import { Module, OnModuleInit } from "@nestjs/common"; import { TypeOrmModule } from "@nestjs/typeorm"; import { BullModule } from "@nestjs/bull"; +import { DiscoveryModule, DiscoveryService } from "@nestjs/core"; // Entities import { DeFiPosition } from "./entities/defi-position.entity"; @@ -19,6 +20,7 @@ import { TransactionOptimizationService } from "./services/transaction-optimizat import { AaveAdapter } from "./protocols/aave.adapter"; import { CompoundAdapter } from "./protocols/compound.adapter"; import { ProtocolRegistry } from "./protocols/protocol-registry"; +import { ProtocolAdapter } from "./protocols/protocol-adapter.interface"; // Controller import { DeFiController } from "./defi.controller"; @@ -87,6 +89,7 @@ import { TradeLockService } from "./trade-lock.service"; }, }, ), + DiscoveryModule, ], providers: [ // Protocol Adapters @@ -111,4 +114,28 @@ import { TradeLockService } from "./trade-lock.service"; TradeLockService, ], }) -export class DeFiModule {} +export class DeFiModule implements OnModuleInit { + constructor( + private readonly protocolRegistry: ProtocolRegistry, + private readonly discoveryService: DiscoveryService, + ) {} + + onModuleInit() { + // Auto-discover and register all protocol adapters + const providers = this.discoveryService.getProviders(); + + providers.forEach((wrapper) => { + const instance = wrapper.instance; + if ( + instance && + typeof instance === "object" && + "name" in instance && + "supportedChains" in instance && + typeof instance.getPosition === "function" && + wrapper.metatype?.name?.endsWith("Adapter") + ) { + this.protocolRegistry.register(instance as ProtocolAdapter); + } + }); + } +} diff --git a/src/defi/defi/protocols/protocol-registry.ts b/src/defi/defi/protocols/protocol-registry.ts index 7670576..308fd9a 100644 --- a/src/defi/defi/protocols/protocol-registry.ts +++ b/src/defi/defi/protocols/protocol-registry.ts @@ -1,33 +1,33 @@ import { Injectable, Logger } from "@nestjs/common"; import { ProtocolAdapter } from "./protocol-adapter.interface"; -import { AaveAdapter } from "./aave.adapter"; -import { CompoundAdapter } from "./compound.adapter"; -import { DeFiProtocol } from "../entities/defi-position.entity"; + +export interface ProtocolAdapterMetadata { + name: string; + supportedChains: string[]; + capabilities: string[]; +} @Injectable() export class ProtocolRegistry { - private logger = new Logger("ProtocolRegistry"); - private adapters: Map = new Map(); - - constructor( - private aaveAdapter: AaveAdapter, - private compoundAdapter: CompoundAdapter, - ) { - this.registerAdapters(); - } + private readonly logger = new Logger(ProtocolRegistry.name); + private readonly adapters: Map = new Map(); + + constructor() {} - private registerAdapters() { - this.adapters.set(DeFiProtocol.AAVE, this.aaveAdapter); - this.adapters.set(DeFiProtocol.COMPOUND, this.compoundAdapter); - // Additional adapters would be registered here - // this.adapters.set(DeFiProtocol.YEARN, new YearnAdapter()); - // this.adapters.set(DeFiProtocol.LIDO, new LidoAdapter()); + register(adapter: ProtocolAdapter) { + if (this.adapters.has(adapter.name)) { + this.logger.warn( + `Protocol adapter ${adapter.name} is already registered. Overwriting.`, + ); + } + this.adapters.set(adapter.name, adapter); + this.logger.log(`Registered protocol adapter: ${adapter.name}`); } - getAdapter(protocol: DeFiProtocol): ProtocolAdapter { - const adapter = this.adapters.get(protocol); + getAdapter(protocolName: string): ProtocolAdapter { + const adapter = this.adapters.get(protocolName); if (!adapter) { - throw new Error(`Protocol adapter not found: ${protocol}`); + throw new Error(`Protocol adapter not found: ${protocolName}`); } return adapter; } @@ -36,8 +36,8 @@ export class ProtocolRegistry { return Array.from(this.adapters.values()); } - isProtocolSupported(protocol: DeFiProtocol): boolean { - return this.adapters.has(protocol); + isProtocolSupported(protocolName: string): boolean { + return this.adapters.has(protocolName); } getSupportedProtocols(): string[] { @@ -55,9 +55,4 @@ export class ProtocolRegistry { return supportingAdapters; } - - registerAdapter(protocol: DeFiProtocol, adapter: ProtocolAdapter) { - this.logger.log(`Registering adapter for protocol: ${protocol}`); - this.adapters.set(protocol, adapter); - } }