Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
import { ThrottlerModule } from '@nestjs/throttler';
import { TypeOrmModule } from '@nestjs/typeorm';
Expand All @@ -11,15 +10,13 @@ import { TransactionsModule } from './transactions/transactions.module';
import { BenchmarkModule } from './benchmark/benchmark.module';
import { AnalyticsModule } from './analytics/analytics.module';
import { TokenMetadataModule } from './token-metadata/token-metadata.module';
import { FeatureFlagsModule } from './feature-flags/feature-flags.module';
import { BridgeCompareModule } from './bridge-compare/bridge-compare.module';
import { VersionModule } from './version/version.module';
import { GlobalExceptionFilter } from './common/filters/global-exception.filter';
import { ResponseInterceptor } from './common/interceptors/response.interceptor';
import { Transaction } from './transactions/entities/transaction.entity';

@Module({
imports: [
ScheduleModule.forRoot(),
ConfigModule,
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
Expand All @@ -44,8 +41,7 @@ import { Transaction } from './transactions/entities/transaction.entity';
BenchmarkModule,
AnalyticsModule,
TokenMetadataModule,
FeatureFlagsModule,
BridgeCompareModule,
VersionModule,
ThrottlerModule.forRoot([
{
ttl: 60000,
Expand Down
215 changes: 0 additions & 215 deletions apps/api/src/bridge-compare/aggregation.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ import {
RawBridgeQuote,
BridgeProvider,
QuoteRequestParams,
<<<<<<< HEAD:src/bridge-compare/aggregation.service.ts
} from '../interfaces';
import { BridgeStatus } from '../enums';
=======
} from './interfaces';
import { BridgeStatus } from './enums';
>>>>>>> 902330b94c4294029cf45eb84c6121443fbb0427:apps/api/src/bridge-compare/aggregation.service.ts

interface MockQuoteTemplate {
feesUsd: number;
Expand All @@ -28,213 +23,3 @@ export class AggregationService {
name: 'Stargate Finance',
apiBaseUrl: 'https://api.stargate.finance',
supportedChains: [
'ethereum',
'polygon',
'arbitrum',
'optimism',
'binance',
'avalanche',
],
supportedTokens: ['USDC', 'USDT', 'ETH', 'WBTC'],
isActive: true,
},
{
id: 'squid',
name: 'Squid Router',
apiBaseUrl: 'https://api.0xsquid.com',
supportedChains: [
'ethereum',
'polygon',
'arbitrum',
'avalanche',
'stellar',
],
supportedTokens: ['USDC', 'USDT', 'ETH', 'XLM'],
isActive: true,
},
{
id: 'hop',
name: 'Hop Protocol',
apiBaseUrl: 'https://api.hop.exchange',
supportedChains: ['ethereum', 'polygon', 'arbitrum', 'optimism'],
supportedTokens: ['USDC', 'USDT', 'ETH', 'MATIC'],
isActive: true,
},
{
id: 'cbridge',
name: 'cBridge',
apiBaseUrl: 'https://cbridge-prod2.celer.app',
supportedChains: [
'ethereum',
'polygon',
'arbitrum',
'binance',
'avalanche',
],
supportedTokens: ['USDC', 'USDT', 'ETH', 'BNB'],
isActive: true,
},
{
id: 'soroswap',
name: 'Soroswap Bridge',
apiBaseUrl: 'https://api.soroswap.finance',
supportedChains: ['stellar', 'ethereum'],
supportedTokens: ['USDC', 'XLM', 'yXLM'],
isActive: true,
},
];

private readonly MOCK_QUOTE_TEMPLATES: Record<string, MockQuoteTemplate> = {
stargate: {
feesUsd: 0.8,
gasCostUsd: 1.2,
estimatedTimeSeconds: 45,
outputRatio: 0.989,
},
squid: {
feesUsd: 1.1,
gasCostUsd: 0.9,
estimatedTimeSeconds: 30,
outputRatio: 0.992,
},
hop: {
feesUsd: 0.6,
gasCostUsd: 1.5,
estimatedTimeSeconds: 120,
outputRatio: 0.985,
},
cbridge: {
feesUsd: 0.7,
gasCostUsd: 1.3,
estimatedTimeSeconds: 90,
outputRatio: 0.987,
},
soroswap: {
feesUsd: 0.3,
gasCostUsd: 0.2,
estimatedTimeSeconds: 15,
outputRatio: 0.997,
},
};

/**
* Fetch raw quotes from all providers supporting the given route.
* Returns an object with successful quotes and the count of failed providers.
*/
async fetchRawQuotes(params: QuoteRequestParams): Promise<{
quotes: RawBridgeQuote[];
failedProviders: number;
}> {
const eligibleProviders = this.getEligibleProviders(params);

if (!eligibleProviders.length) {
throw new HttpException(
`No bridge providers support the route ${params.sourceToken} from ${params.sourceChain} β†’ ${params.destinationChain}`,
HttpStatus.NOT_FOUND,
);
}

this.logger.log(
`Fetching quotes from ${eligibleProviders.length} providers for ` +
`${params.sourceToken} ${params.sourceChain}β†’${params.destinationChain} amount=${params.amount}`,
);

const results = await Promise.allSettled(
eligibleProviders.map((p) => this.fetchSingleProviderQuote(p, params)),
);

const quotes: RawBridgeQuote[] = [];
let failedProviders = 0;

for (const result of results) {
if (result.status === 'fulfilled') {
quotes.push(result.value);
} else {
failedProviders++;
this.logger.warn(`Provider quote fetch failed: ${result.reason}`);
}
}

if (!quotes.length) {
throw new HttpException(
'All bridge providers failed to respond. Please try again later.',
HttpStatus.SERVICE_UNAVAILABLE,
);
}

return { quotes, failedProviders };
}

/**
* Get active providers that support the requested route.
*/
getEligibleProviders(params: QuoteRequestParams): BridgeProvider[] {
return this.MOCK_PROVIDERS.filter((provider) => {
if (!provider.isActive) return false;
const supportsSourceChain = provider.supportedChains.includes(
params.sourceChain,
);
const supportsDestChain = provider.supportedChains.includes(
params.destinationChain,
);
const supportsToken = provider.supportedTokens.some(
(t) => t.toUpperCase() === params.sourceToken.toUpperCase(),
);
return supportsSourceChain && supportsDestChain && supportsToken;
});
}

/**
* Fetch a quote from a single provider (simulated; real impl uses HttpService).
*/
private async fetchSingleProviderQuote(
provider: BridgeProvider,
params: QuoteRequestParams,
): Promise<RawBridgeQuote> {
// Simulate occasional provider failures (5% chance)
if (Math.random() < 0.05) {
throw new Error(`Provider ${provider.name} returned timeout`);
}

const template = this.MOCK_QUOTE_TEMPLATES[provider.id] ?? {
feesUsd: 1.0,
gasCostUsd: 1.0,
estimatedTimeSeconds: 60,
outputRatio: 0.99,
};

// Scale fees relative to amount
const scaledFees =
template.feesUsd * (1 + Math.log10(Math.max(1, params.amount / 100)));
const scaledGas = template.gasCostUsd;
const outputAmount = params.amount * template.outputRatio;

return {
bridgeId: provider.id,
bridgeName: provider.name,
outputAmount,
feesUsd: parseFloat(scaledFees.toFixed(4)),
gasCostUsd: parseFloat(scaledGas.toFixed(4)),
estimatedTimeSeconds: template.estimatedTimeSeconds,
steps: [
{
protocol: provider.name,
type: 'bridge',
inputAmount: params.amount,
outputAmount,
feeUsd: scaledFees,
},
],
};
}

getAllProviders(): BridgeProvider[] {
return this.MOCK_PROVIDERS;
}

getBridgeStatus(bridgeId: string): BridgeStatus {
const provider = this.MOCK_PROVIDERS.find((p) => p.id === bridgeId);
if (!provider) return BridgeStatus.OFFLINE;
return provider.isActive ? BridgeStatus.ACTIVE : BridgeStatus.OFFLINE;
}
}
45 changes: 45 additions & 0 deletions apps/api/src/version/version.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';

export interface VersionInfo {
/** SDK version string */
version: string;
/** Build number/timestamp */
build?: string;
/** API version */
apiVersion: string;
/** Environment */
environment: string;
/** Timestamp of the response */
timestamp: string;
}

@ApiTags('System')
@Controller()
export class VersionController {
@Get('version')
@ApiOperation({
summary: 'Get SDK and API version information',
description: 'Returns the current SDK version, API version, and environment details. Useful for debugging and compatibility checks.',
})
@ApiResponse({
status: 200,
description: 'Version information retrieved successfully',
example: {
version: '0.0.1',
build: '2024.01.15.120000',
apiVersion: 'v1',
environment: 'development',
timestamp: '2024-01-15T12:00:00.000Z',
},
})
getVersion(): VersionInfo {
return {
version: process.env.npm_package_version || '0.0.1',
build: process.env.BUILD_NUMBER || new Date().toISOString(),
apiVersion: 'v1',
environment: process.env.NODE_ENV || 'development',
timestamp: new Date().toISOString(),
};
}
}
12 changes: 12 additions & 0 deletions apps/api/src/version/version.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Module } from '@nestjs/common';
import { VersionController } from './version.controller';

/**
* Version Module
*
* Provides SDK and API version information endpoints.
*/
@Module({
controllers: [VersionController],
})
export class VersionModule {}
Loading
Loading