feat: restore operator WIP — PMM JSON sync entrypoint, dotenv RPC trim + secrets, pool env alignment
- Resolve stash: merge load_deployment_env path with secure-secrets and CR/LF RPC strip - create-pmm-full-mesh-chain138.sh delegates to sync-chain138-pmm-pools-from-json.sh - env.additions.example: canonical PMM pool defaults (cUSDT/USDT per crosscheck) - Include Chain138 scripts, official mirror deploy scaffolding, and prior staged changes Made-with: Cursor
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { PoolRepository } from '../../database/repositories/pool-repo';
|
||||
import { TokenRepository } from '../../database/repositories/token-repo';
|
||||
import { resolvePoolTokenDisplays } from '../../services/token-display';
|
||||
import {
|
||||
HEATMAP_CHAINS,
|
||||
getRoutesList,
|
||||
@@ -37,12 +38,9 @@ router.get('/heatmap', cacheMiddleware(60 * 1000), async (req: Request, res: Res
|
||||
for (const pool of pools) {
|
||||
const tvl = pool.totalLiquidityUsd || 0;
|
||||
const half = tvl / 2;
|
||||
const token0 = await tokenRepo.getToken(chainId, pool.token0Address);
|
||||
const token1 = await tokenRepo.getToken(chainId, pool.token1Address);
|
||||
const sym0 = token0?.symbol || '';
|
||||
const sym1 = token1?.symbol || '';
|
||||
if (assets.includes(sym0)) symbolToTvl[sym0] = (symbolToTvl[sym0] || 0) + half;
|
||||
if (assets.includes(sym1)) symbolToTvl[sym1] = (symbolToTvl[sym1] || 0) + half;
|
||||
const { token0, token1 } = await resolvePoolTokenDisplays(tokenRepo, chainId, pool.token0Address, pool.token1Address);
|
||||
if (assets.includes(token0.symbol)) symbolToTvl[token0.symbol] = (symbolToTvl[token0.symbol] || 0) + half;
|
||||
if (assets.includes(token1.symbol)) symbolToTvl[token1.symbol] = (symbolToTvl[token1.symbol] || 0) + half;
|
||||
}
|
||||
for (const asset of assets) {
|
||||
const val = metric === 'tvlUsd' ? (symbolToTvl[asset] || 0) : 0;
|
||||
@@ -77,15 +75,14 @@ router.get('/pools', cacheMiddleware(60 * 1000), async (req: Request, res: Respo
|
||||
const pools = await poolRepo.getPoolsByChain(chainId, 500);
|
||||
const list = await Promise.all(
|
||||
pools.map(async (p) => {
|
||||
const token0 = await tokenRepo.getToken(chainId, p.token0Address);
|
||||
const token1 = await tokenRepo.getToken(chainId, p.token1Address);
|
||||
const { token0, token1 } = await resolvePoolTokenDisplays(tokenRepo, chainId, p.token0Address, p.token1Address);
|
||||
return {
|
||||
poolId: `${chainId}:${(p.dexType || 'dodo').toLowerCase()}:${token0?.symbol || p.token0Address}-${token1?.symbol || p.token1Address}:${p.poolAddress}`,
|
||||
poolId: `${chainId}:${(p.dexType || 'dodo').toLowerCase()}:${token0.symbol}-${token1.symbol}:${p.poolAddress}`,
|
||||
chainId: p.chainId,
|
||||
dex: p.dexType,
|
||||
poolAddress: p.poolAddress,
|
||||
token0: { symbol: token0?.symbol || '?', address: p.token0Address },
|
||||
token1: { symbol: token1?.symbol || '?', address: p.token1Address },
|
||||
token0: { symbol: token0.symbol, name: token0.name, address: p.token0Address, source: token0.source },
|
||||
token1: { symbol: token1.symbol, name: token1.name, address: p.token1Address, source: token1.source },
|
||||
liquidity: {
|
||||
tvlUsd: p.totalLiquidityUsd,
|
||||
reserve0: p.reserve0,
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
getCanonicalTokensByChain,
|
||||
getLogoUriForSpec,
|
||||
} from '../../config/canonical-tokens';
|
||||
import { resolvePoolTokenDisplays } from '../../services/token-display';
|
||||
import { getSupportedChainIds } from '../../config/chains';
|
||||
import { cacheMiddleware } from '../middleware/cache';
|
||||
import { fetchRemoteJson } from '../utils/fetch-remote-json';
|
||||
@@ -64,6 +65,20 @@ async function buildTokenReport(chainId: number) {
|
||||
poolRepo.getPoolsByToken(chainId, address),
|
||||
]);
|
||||
|
||||
const resolvedPools = await Promise.all(
|
||||
pools.map(async (p) => {
|
||||
const { token0, token1 } = await resolvePoolTokenDisplays(tokenRepo, chainId, p.token0Address, p.token1Address);
|
||||
return {
|
||||
poolAddress: p.poolAddress,
|
||||
dex: p.dexType,
|
||||
token0,
|
||||
token1,
|
||||
tvl: p.totalLiquidityUsd,
|
||||
volume24h: p.volume24h,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
out.push({
|
||||
chainId,
|
||||
address: address.toLowerCase(),
|
||||
@@ -83,12 +98,14 @@ async function buildTokenReport(chainId: number) {
|
||||
lastUpdated: marketData.lastUpdated?.toISOString() ?? '',
|
||||
}
|
||||
: undefined,
|
||||
pools: pools.map((p) => ({
|
||||
pools: resolvedPools.map((p) => ({
|
||||
poolAddress: p.poolAddress,
|
||||
dex: p.dexType,
|
||||
token0: p.token0Address,
|
||||
token1: p.token1Address,
|
||||
tvl: p.totalLiquidityUsd,
|
||||
dex: p.dex,
|
||||
token0: p.token0.address,
|
||||
token1: p.token1.address,
|
||||
token0Symbol: p.token0.symbol,
|
||||
token1Symbol: p.token1.symbol,
|
||||
tvl: p.tvl,
|
||||
volume24h: p.volume24h,
|
||||
})),
|
||||
fromDb: !!dbToken,
|
||||
|
||||
@@ -7,6 +7,7 @@ import { CoinGeckoAdapter } from '../../adapters/coingecko-adapter';
|
||||
import { CoinMarketCapAdapter } from '../../adapters/cmc-adapter';
|
||||
import { DexScreenerAdapter } from '../../adapters/dexscreener-adapter';
|
||||
import { cacheMiddleware } from '../middleware/cache';
|
||||
import { resolvePoolTokenDisplays } from '../../services/token-display';
|
||||
import { logger } from '../../utils/logger';
|
||||
|
||||
const router: Router = Router();
|
||||
@@ -150,19 +151,34 @@ router.get('/tokens/:address/pools', cacheMiddleware(60 * 1000), async (req: Req
|
||||
const pools = await poolRepo.getPoolsByToken(chainId, address);
|
||||
|
||||
res.json({
|
||||
pools: pools.map((pool) => ({
|
||||
address: pool.poolAddress,
|
||||
dex: pool.dexType,
|
||||
token0: pool.token0Address,
|
||||
token1: pool.token1Address,
|
||||
reserves: {
|
||||
token0: pool.reserve0,
|
||||
token1: pool.reserve1,
|
||||
},
|
||||
tvl: pool.totalLiquidityUsd,
|
||||
volume24h: pool.volume24h,
|
||||
feeTier: pool.feeTier,
|
||||
})),
|
||||
pools: await Promise.all(
|
||||
pools.map(async (pool) => {
|
||||
const { token0, token1 } = await resolvePoolTokenDisplays(tokenRepo, chainId, pool.token0Address, pool.token1Address);
|
||||
return {
|
||||
address: pool.poolAddress,
|
||||
dex: pool.dexType,
|
||||
token0: {
|
||||
address: pool.token0Address,
|
||||
symbol: token0.symbol,
|
||||
name: token0.name,
|
||||
source: token0.source,
|
||||
},
|
||||
token1: {
|
||||
address: pool.token1Address,
|
||||
symbol: token1.symbol,
|
||||
name: token1.name,
|
||||
source: token1.source,
|
||||
},
|
||||
reserves: {
|
||||
token0: pool.reserve0,
|
||||
token1: pool.reserve1,
|
||||
},
|
||||
tvl: pool.totalLiquidityUsd,
|
||||
volume24h: pool.volume24h,
|
||||
feeTier: pool.feeTier,
|
||||
};
|
||||
})
|
||||
),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error fetching pools:', error);
|
||||
@@ -272,8 +288,12 @@ router.get('/pools/:poolAddress', cacheMiddleware(60 * 1000), async (req: Reques
|
||||
pool: {
|
||||
address: pool.poolAddress,
|
||||
dex: pool.dexType,
|
||||
token0: pool.token0Address,
|
||||
token1: pool.token1Address,
|
||||
token0: {
|
||||
address: pool.token0Address,
|
||||
},
|
||||
token1: {
|
||||
address: pool.token1Address,
|
||||
},
|
||||
reserves: {
|
||||
token0: pool.reserve0,
|
||||
token1: pool.reserve1,
|
||||
|
||||
@@ -43,114 +43,159 @@ export class PoolRepository {
|
||||
this.pool = getDatabasePool();
|
||||
}
|
||||
|
||||
async getPool(chainId: number, poolAddress: string): Promise<LiquidityPool | null> {
|
||||
const result = await this.pool.query(
|
||||
`SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type,
|
||||
factory_address, router_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, volume_24h, fee_tier, created_at_block, created_at_timestamp, last_updated
|
||||
FROM liquidity_pools
|
||||
WHERE chain_id = $1 AND pool_address = $2`,
|
||||
[chainId, poolAddress.toLowerCase()]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
private isMissingRelationError(error: unknown): boolean {
|
||||
if (!error || typeof error !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.mapRowToPool(result.rows[0]);
|
||||
const code = (error as { code?: string }).code;
|
||||
const message = (error as { message?: string }).message || '';
|
||||
return code === '42P01' || message.includes('relation "') && message.includes('" does not exist');
|
||||
}
|
||||
|
||||
async getPool(chainId: number, poolAddress: string): Promise<LiquidityPool | null> {
|
||||
try {
|
||||
const result = await this.pool.query(
|
||||
`SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type,
|
||||
factory_address, router_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, volume_24h, fee_tier, created_at_block, created_at_timestamp, last_updated
|
||||
FROM liquidity_pools
|
||||
WHERE chain_id = $1 AND pool_address = $2`,
|
||||
[chainId, poolAddress.toLowerCase()]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.mapRowToPool(result.rows[0]);
|
||||
} catch (error) {
|
||||
if (this.isMissingRelationError(error)) {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getPoolsByChain(chainId: number, limit: number = 500): Promise<LiquidityPool[]> {
|
||||
const result = await this.pool.query(
|
||||
`SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type,
|
||||
factory_address, router_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, volume_24h, fee_tier, created_at_block, created_at_timestamp, last_updated
|
||||
FROM liquidity_pools
|
||||
WHERE chain_id = $1
|
||||
ORDER BY total_liquidity_usd DESC NULLS LAST
|
||||
LIMIT $2`,
|
||||
[chainId, limit]
|
||||
);
|
||||
return result.rows.map((row) => this.mapRowToPool(row));
|
||||
try {
|
||||
const result = await this.pool.query(
|
||||
`SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type,
|
||||
factory_address, router_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, volume_24h, fee_tier, created_at_block, created_at_timestamp, last_updated
|
||||
FROM liquidity_pools
|
||||
WHERE chain_id = $1
|
||||
ORDER BY total_liquidity_usd DESC NULLS LAST
|
||||
LIMIT $2`,
|
||||
[chainId, limit]
|
||||
);
|
||||
return result.rows.map((row) => this.mapRowToPool(row));
|
||||
} catch (error) {
|
||||
if (this.isMissingRelationError(error)) {
|
||||
return [];
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getPoolsByToken(chainId: number, tokenAddress: string): Promise<LiquidityPool[]> {
|
||||
const result = await this.pool.query(
|
||||
`SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type,
|
||||
factory_address, router_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, volume_24h, fee_tier, created_at_block, created_at_timestamp, last_updated
|
||||
FROM liquidity_pools
|
||||
WHERE chain_id = $1 AND (token0_address = $2 OR token1_address = $2)
|
||||
ORDER BY total_liquidity_usd DESC`,
|
||||
[chainId, tokenAddress.toLowerCase()]
|
||||
);
|
||||
try {
|
||||
const result = await this.pool.query(
|
||||
`SELECT id, chain_id, pool_address, token0_address, token1_address, dex_type,
|
||||
factory_address, router_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, volume_24h, fee_tier, created_at_block, created_at_timestamp, last_updated
|
||||
FROM liquidity_pools
|
||||
WHERE chain_id = $1 AND (token0_address = $2 OR token1_address = $2)
|
||||
ORDER BY total_liquidity_usd DESC`,
|
||||
[chainId, tokenAddress.toLowerCase()]
|
||||
);
|
||||
|
||||
return result.rows.map((row) => this.mapRowToPool(row));
|
||||
return result.rows.map((row) => this.mapRowToPool(row));
|
||||
} catch (error) {
|
||||
if (this.isMissingRelationError(error)) {
|
||||
return [];
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async upsertPool(pool: LiquidityPool): Promise<void> {
|
||||
await this.pool.query(
|
||||
`INSERT INTO liquidity_pools (
|
||||
chain_id, pool_address, token0_address, token1_address, dex_type,
|
||||
factory_address, router_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, volume_24h, fee_tier, created_at_block, created_at_timestamp, last_updated
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
|
||||
ON CONFLICT (chain_id, pool_address) DO UPDATE SET
|
||||
token0_address = EXCLUDED.token0_address,
|
||||
token1_address = EXCLUDED.token1_address,
|
||||
dex_type = EXCLUDED.dex_type,
|
||||
factory_address = EXCLUDED.factory_address,
|
||||
router_address = EXCLUDED.router_address,
|
||||
reserve0 = EXCLUDED.reserve0,
|
||||
reserve1 = EXCLUDED.reserve1,
|
||||
reserve0_usd = EXCLUDED.reserve0_usd,
|
||||
reserve1_usd = EXCLUDED.reserve1_usd,
|
||||
total_liquidity_usd = EXCLUDED.total_liquidity_usd,
|
||||
volume_24h = EXCLUDED.volume_24h,
|
||||
fee_tier = EXCLUDED.fee_tier,
|
||||
last_updated = EXCLUDED.last_updated`,
|
||||
[
|
||||
pool.chainId,
|
||||
pool.poolAddress.toLowerCase(),
|
||||
pool.token0Address.toLowerCase(),
|
||||
pool.token1Address.toLowerCase(),
|
||||
pool.dexType,
|
||||
pool.factoryAddress?.toLowerCase(),
|
||||
pool.routerAddress?.toLowerCase(),
|
||||
pool.reserve0,
|
||||
pool.reserve1,
|
||||
pool.reserve0Usd,
|
||||
pool.reserve1Usd,
|
||||
pool.totalLiquidityUsd,
|
||||
pool.volume24h,
|
||||
pool.feeTier,
|
||||
pool.createdAtBlock,
|
||||
pool.createdAtTimestamp,
|
||||
pool.lastUpdated,
|
||||
]
|
||||
);
|
||||
try {
|
||||
await this.pool.query(
|
||||
`INSERT INTO liquidity_pools (
|
||||
chain_id, pool_address, token0_address, token1_address, dex_type,
|
||||
factory_address, router_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, volume_24h, fee_tier, created_at_block, created_at_timestamp, last_updated
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
|
||||
ON CONFLICT (chain_id, pool_address) DO UPDATE SET
|
||||
token0_address = EXCLUDED.token0_address,
|
||||
token1_address = EXCLUDED.token1_address,
|
||||
dex_type = EXCLUDED.dex_type,
|
||||
factory_address = EXCLUDED.factory_address,
|
||||
router_address = EXCLUDED.router_address,
|
||||
reserve0 = EXCLUDED.reserve0,
|
||||
reserve1 = EXCLUDED.reserve1,
|
||||
reserve0_usd = EXCLUDED.reserve0_usd,
|
||||
reserve1_usd = EXCLUDED.reserve1_usd,
|
||||
total_liquidity_usd = EXCLUDED.total_liquidity_usd,
|
||||
volume_24h = EXCLUDED.volume_24h,
|
||||
fee_tier = EXCLUDED.fee_tier,
|
||||
last_updated = EXCLUDED.last_updated`,
|
||||
[
|
||||
pool.chainId,
|
||||
pool.poolAddress.toLowerCase(),
|
||||
pool.token0Address.toLowerCase(),
|
||||
pool.token1Address.toLowerCase(),
|
||||
pool.dexType,
|
||||
pool.factoryAddress?.toLowerCase(),
|
||||
pool.routerAddress?.toLowerCase(),
|
||||
pool.reserve0,
|
||||
pool.reserve1,
|
||||
pool.reserve0Usd,
|
||||
pool.reserve1Usd,
|
||||
pool.totalLiquidityUsd,
|
||||
pool.volume24h,
|
||||
pool.feeTier,
|
||||
pool.createdAtBlock,
|
||||
pool.createdAtTimestamp,
|
||||
pool.lastUpdated,
|
||||
]
|
||||
);
|
||||
} catch (error) {
|
||||
if (this.isMissingRelationError(error)) {
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async addReserveSnapshot(snapshot: PoolReserveSnapshot): Promise<void> {
|
||||
await this.pool.query(
|
||||
`INSERT INTO pool_reserves_history (
|
||||
chain_id, pool_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, block_number, timestamp
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||
[
|
||||
snapshot.chainId,
|
||||
snapshot.poolAddress.toLowerCase(),
|
||||
snapshot.reserve0,
|
||||
snapshot.reserve1,
|
||||
snapshot.reserve0Usd,
|
||||
snapshot.reserve1Usd,
|
||||
snapshot.totalLiquidityUsd,
|
||||
snapshot.blockNumber,
|
||||
snapshot.timestamp,
|
||||
]
|
||||
);
|
||||
try {
|
||||
await this.pool.query(
|
||||
`INSERT INTO pool_reserves_history (
|
||||
chain_id, pool_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, block_number, timestamp
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||
[
|
||||
snapshot.chainId,
|
||||
snapshot.poolAddress.toLowerCase(),
|
||||
snapshot.reserve0,
|
||||
snapshot.reserve1,
|
||||
snapshot.reserve0Usd,
|
||||
snapshot.reserve1Usd,
|
||||
snapshot.totalLiquidityUsd,
|
||||
snapshot.blockNumber,
|
||||
snapshot.timestamp,
|
||||
]
|
||||
);
|
||||
} catch (error) {
|
||||
if (this.isMissingRelationError(error)) {
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getReserveHistory(
|
||||
@@ -160,27 +205,34 @@ export class PoolRepository {
|
||||
to: Date,
|
||||
limit: number = 1000
|
||||
): Promise<PoolReserveSnapshot[]> {
|
||||
const result = await this.pool.query(
|
||||
`SELECT chain_id, pool_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, block_number, timestamp
|
||||
FROM pool_reserves_history
|
||||
WHERE chain_id = $1 AND pool_address = $2 AND timestamp >= $3 AND timestamp <= $4
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT $5`,
|
||||
[chainId, poolAddress.toLowerCase(), from, to, limit]
|
||||
);
|
||||
try {
|
||||
const result = await this.pool.query(
|
||||
`SELECT chain_id, pool_address, reserve0, reserve1, reserve0_usd, reserve1_usd,
|
||||
total_liquidity_usd, block_number, timestamp
|
||||
FROM pool_reserves_history
|
||||
WHERE chain_id = $1 AND pool_address = $2 AND timestamp >= $3 AND timestamp <= $4
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT $5`,
|
||||
[chainId, poolAddress.toLowerCase(), from, to, limit]
|
||||
);
|
||||
|
||||
return result.rows.map((row) => ({
|
||||
chainId: row.chain_id,
|
||||
poolAddress: row.pool_address,
|
||||
reserve0: row.reserve0,
|
||||
reserve1: row.reserve1,
|
||||
reserve0Usd: row.reserve0_usd ? parseFloat(row.reserve0_usd) : undefined,
|
||||
reserve1Usd: row.reserve1_usd ? parseFloat(row.reserve1_usd) : undefined,
|
||||
totalLiquidityUsd: row.total_liquidity_usd ? parseFloat(row.total_liquidity_usd) : undefined,
|
||||
blockNumber: parseInt(row.block_number, 10),
|
||||
timestamp: row.timestamp,
|
||||
}));
|
||||
return result.rows.map((row) => ({
|
||||
chainId: row.chain_id,
|
||||
poolAddress: row.pool_address,
|
||||
reserve0: row.reserve0,
|
||||
reserve1: row.reserve1,
|
||||
reserve0Usd: row.reserve0_usd ? parseFloat(row.reserve0_usd) : undefined,
|
||||
reserve1Usd: row.reserve1_usd ? parseFloat(row.reserve1_usd) : undefined,
|
||||
totalLiquidityUsd: row.total_liquidity_usd ? parseFloat(row.total_liquidity_usd) : undefined,
|
||||
blockNumber: parseInt(row.block_number, 10),
|
||||
timestamp: row.timestamp,
|
||||
}));
|
||||
} catch (error) {
|
||||
if (this.isMissingRelationError(error)) {
|
||||
return [];
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
@@ -161,7 +161,7 @@ export class PoolIndexer {
|
||||
await this.poolRepo.upsertPool(pool);
|
||||
pools.push(pool);
|
||||
} catch (err) {
|
||||
logger.error(`Error indexing DODO PMM pool ${poolAddress}:`, err);
|
||||
logger.warn(`Skipping DODO PMM pool ${poolAddress}; it may have been removed from integration state.`, err);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user