feat(token-aggregation): reports, PMM quotes, config; Engine X flash vaults

- Expand token-aggregation API (report routes), canonical tokens, pools
- Add flash vault contracts + tests (indexed, DODO cwUSDC, XAUT borrow)
- PMM pools JSON, deploy/export scripts, metamask verified list

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-05-10 12:56:30 -07:00
parent 27f8e3a500
commit 76143a8fe3
67 changed files with 6972 additions and 136 deletions

View File

@@ -26,6 +26,7 @@ export function getDatabasePool(): Pool {
connectionString: process.env.DATABASE_URL,
min: parseInt(process.env.DATABASE_POOL_MIN || '2', 10),
max: parseInt(process.env.DATABASE_POOL_MAX || '10', 10),
connectionTimeoutMillis: parseInt(process.env.DATABASE_CONNECTION_TIMEOUT_MS || '3000', 10),
};
// If connectionString is not provided, use individual config

View File

@@ -19,7 +19,16 @@ export class MarketDataRepository {
return code === '42P01' || (message.includes('relation "') && message.includes('" does not exist'));
}
private shouldUseReadFallback(error: unknown): boolean {
if (this.isMissingRelationError(error)) return true;
if (String(process.env.TOKEN_AGGREGATION_DB_READ_FALLBACK ?? '1').toLowerCase() === '0') return false;
const message = (error as { message?: string })?.message || '';
const code = (error as { code?: string })?.code || '';
return ['ETIMEDOUT', 'ECONNREFUSED', 'ENOTFOUND'].includes(code) || /timeout|connect/i.test(message);
}
async getMarketData(chainId: number, tokenAddress: string): Promise<TokenMarketData | null> {
if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return null;
try {
const result = await this.pool.query(
`SELECT chain_id, token_address, price_usd, price_change_24h, volume_24h, volume_7d, volume_30d,
@@ -49,7 +58,7 @@ export class MarketDataRepository {
lastUpdated: row.last_updated,
};
} catch (error) {
if (this.isMissingRelationError(error)) {
if (this.shouldUseReadFallback(error)) {
return null;
}
throw error;
@@ -99,6 +108,7 @@ export class MarketDataRepository {
}
async getTopTokensByVolume(chainId: number, limit: number = 50): Promise<TokenMarketData[]> {
if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return [];
try {
const result = await this.pool.query(
`SELECT chain_id, token_address, price_usd, price_change_24h, volume_24h, volume_7d, volume_30d,
@@ -125,7 +135,7 @@ export class MarketDataRepository {
lastUpdated: row.last_updated,
}));
} catch (error) {
if (this.isMissingRelationError(error)) {
if (this.shouldUseReadFallback(error)) {
return [];
}
throw error;
@@ -133,6 +143,7 @@ export class MarketDataRepository {
}
async getTopTokensByLiquidity(chainId: number, limit: number = 50): Promise<TokenMarketData[]> {
if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return [];
try {
const result = await this.pool.query(
`SELECT chain_id, token_address, price_usd, price_change_24h, volume_24h, volume_7d, volume_30d,
@@ -159,7 +170,7 @@ export class MarketDataRepository {
lastUpdated: row.last_updated,
}));
} catch (error) {
if (this.isMissingRelationError(error)) {
if (this.shouldUseReadFallback(error)) {
return [];
}
throw error;

View File

@@ -53,7 +53,16 @@ export class PoolRepository {
return code === '42P01' || message.includes('relation "') && message.includes('" does not exist');
}
private shouldUseReadFallback(error: unknown): boolean {
if (this.isMissingRelationError(error)) return true;
if (String(process.env.TOKEN_AGGREGATION_DB_READ_FALLBACK ?? '1').toLowerCase() === '0') return false;
const message = (error as { message?: string })?.message || '';
const code = (error as { code?: string })?.code || '';
return ['ETIMEDOUT', 'ECONNREFUSED', 'ENOTFOUND'].includes(code) || /timeout|connect/i.test(message);
}
async getPool(chainId: number, poolAddress: string): Promise<LiquidityPool | null> {
if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return null;
try {
const result = await this.pool.query(
`SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type,
@@ -70,7 +79,7 @@ export class PoolRepository {
return this.mapRowToPool(result.rows[0]);
} catch (error) {
if (this.isMissingRelationError(error)) {
if (this.shouldUseReadFallback(error)) {
return null;
}
throw error;
@@ -78,6 +87,7 @@ export class PoolRepository {
}
async getPoolsByChain(chainId: number, limit: number = 500): Promise<LiquidityPool[]> {
if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return [];
try {
const result = await this.pool.query(
`SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type,
@@ -91,7 +101,7 @@ export class PoolRepository {
);
return result.rows.map((row) => this.mapRowToPool(row));
} catch (error) {
if (this.isMissingRelationError(error)) {
if (this.shouldUseReadFallback(error)) {
return [];
}
throw error;
@@ -99,6 +109,7 @@ export class PoolRepository {
}
async getPoolsByToken(chainId: number, tokenAddress: string): Promise<LiquidityPool[]> {
if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return [];
try {
const result = await this.pool.query(
`SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type,
@@ -112,7 +123,7 @@ export class PoolRepository {
return result.rows.map((row) => this.mapRowToPool(row));
} catch (error) {
if (this.isMissingRelationError(error)) {
if (this.shouldUseReadFallback(error)) {
return [];
}
throw error;

View File

@@ -46,7 +46,16 @@ export class TokenRepository {
return code === '42P01' || (message.includes('relation "') && message.includes('" does not exist'));
}
private shouldUseReadFallback(error: unknown): boolean {
if (this.isMissingRelationError(error)) return true;
if (String(process.env.TOKEN_AGGREGATION_DB_READ_FALLBACK ?? '1').toLowerCase() === '0') return false;
const message = (error as { message?: string })?.message || '';
const code = (error as { code?: string })?.code || '';
return ['ETIMEDOUT', 'ECONNREFUSED', 'ENOTFOUND'].includes(code) || /timeout|connect/i.test(message);
}
async getToken(chainId: number, address: string): Promise<Token | null> {
if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return null;
try {
const result = await this.pool.query(
`SELECT chain_id, address, name, symbol, decimals, total_supply, logo_url, website_url, description, verified
@@ -73,7 +82,7 @@ export class TokenRepository {
verified: row.verified,
};
} catch (error) {
if (this.isMissingRelationError(error)) {
if (this.shouldUseReadFallback(error)) {
return null;
}
throw error;
@@ -81,6 +90,7 @@ export class TokenRepository {
}
async getTokens(chainId: number, limit: number = 50, offset: number = 0): Promise<Token[]> {
if (String(process.env.TOKEN_AGGREGATION_SKIP_DB_READS ?? '0').toLowerCase() === '1') return [];
try {
const result = await this.pool.query(
`SELECT chain_id, address, name, symbol, decimals, total_supply, logo_url, website_url, description, verified
@@ -104,7 +114,7 @@ export class TokenRepository {
verified: row.verified,
}));
} catch (error) {
if (this.isMissingRelationError(error)) {
if (this.shouldUseReadFallback(error)) {
return [];
}
throw error;