@general-liquidity/gordon-cli 0.75.4 → 0.75.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gordon.js +1189 -13
- package/package.json +1 -1
package/dist/gordon.js
CHANGED
|
@@ -14414,7 +14414,9 @@ async function checkEnvStatus() {
|
|
|
14414
14414
|
KRAKEN_API_SECRET: process.env.KRAKEN_API_SECRET,
|
|
14415
14415
|
BITFINEX_API_KEY: process.env.BITFINEX_API_KEY,
|
|
14416
14416
|
BITFINEX_API_SECRET: process.env.BITFINEX_API_SECRET,
|
|
14417
|
-
HYPERLIQUID_PRIVATE_KEY: process.env.HYPERLIQUID_PRIVATE_KEY
|
|
14417
|
+
HYPERLIQUID_PRIVATE_KEY: process.env.HYPERLIQUID_PRIVATE_KEY,
|
|
14418
|
+
UNISWAP_API_KEY: process.env.UNISWAP_API_KEY,
|
|
14419
|
+
THEGRAPH_API_KEY: process.env.THEGRAPH_API_KEY
|
|
14418
14420
|
};
|
|
14419
14421
|
return {
|
|
14420
14422
|
fileExists: false,
|
|
@@ -14425,6 +14427,8 @@ async function checkEnvStatus() {
|
|
|
14425
14427
|
hasKrakenKeys: !!(keys2.KRAKEN_API_KEY && keys2.KRAKEN_API_SECRET),
|
|
14426
14428
|
hasBitfinexKeys: !!(keys2.BITFINEX_API_KEY && keys2.BITFINEX_API_SECRET),
|
|
14427
14429
|
hasHyperliquidKey: !!keys2.HYPERLIQUID_PRIVATE_KEY,
|
|
14430
|
+
hasUniswapKey: !!keys2.UNISWAP_API_KEY,
|
|
14431
|
+
hasGraphKey: !!keys2.THEGRAPH_API_KEY,
|
|
14428
14432
|
keys: keys2
|
|
14429
14433
|
};
|
|
14430
14434
|
}
|
|
@@ -14445,7 +14449,9 @@ async function checkEnvStatus() {
|
|
|
14445
14449
|
KRAKEN_API_SECRET: parsed.KRAKEN_API_SECRET || process.env.KRAKEN_API_SECRET,
|
|
14446
14450
|
BITFINEX_API_KEY: parsed.BITFINEX_API_KEY || process.env.BITFINEX_API_KEY,
|
|
14447
14451
|
BITFINEX_API_SECRET: parsed.BITFINEX_API_SECRET || process.env.BITFINEX_API_SECRET,
|
|
14448
|
-
HYPERLIQUID_PRIVATE_KEY: parsed.HYPERLIQUID_PRIVATE_KEY || process.env.HYPERLIQUID_PRIVATE_KEY
|
|
14452
|
+
HYPERLIQUID_PRIVATE_KEY: parsed.HYPERLIQUID_PRIVATE_KEY || process.env.HYPERLIQUID_PRIVATE_KEY,
|
|
14453
|
+
UNISWAP_API_KEY: parsed.UNISWAP_API_KEY || process.env.UNISWAP_API_KEY,
|
|
14454
|
+
THEGRAPH_API_KEY: parsed.THEGRAPH_API_KEY || process.env.THEGRAPH_API_KEY
|
|
14449
14455
|
};
|
|
14450
14456
|
return {
|
|
14451
14457
|
fileExists: true,
|
|
@@ -14456,6 +14462,8 @@ async function checkEnvStatus() {
|
|
|
14456
14462
|
hasKrakenKeys: !!(keys.KRAKEN_API_KEY && keys.KRAKEN_API_SECRET),
|
|
14457
14463
|
hasBitfinexKeys: !!(keys.BITFINEX_API_KEY && keys.BITFINEX_API_SECRET),
|
|
14458
14464
|
hasHyperliquidKey: !!keys.HYPERLIQUID_PRIVATE_KEY,
|
|
14465
|
+
hasUniswapKey: !!keys.UNISWAP_API_KEY,
|
|
14466
|
+
hasGraphKey: !!keys.THEGRAPH_API_KEY,
|
|
14459
14467
|
keys
|
|
14460
14468
|
};
|
|
14461
14469
|
}
|
|
@@ -196193,23 +196201,779 @@ var init_client9 = __esm(() => {
|
|
|
196193
196201
|
};
|
|
196194
196202
|
});
|
|
196195
196203
|
|
|
196204
|
+
// src/infra/uniswap/subgraph-types.ts
|
|
196205
|
+
var V3_SUBGRAPH_IDS;
|
|
196206
|
+
var init_subgraph_types = __esm(() => {
|
|
196207
|
+
V3_SUBGRAPH_IDS = {
|
|
196208
|
+
1: "5zvR82QoaXYFyDEKLZ9t6v9adgnptxYpKpSbxtgVENFV",
|
|
196209
|
+
10: "Cghf4LfVqPiFw6fp6Y5X5Ubc8UpmUhSfJL82zwiBFLaj",
|
|
196210
|
+
56: "F85MNzUGYqgSHSHRGgeVMNsdnW1KtZSVgFULumXRZTw2",
|
|
196211
|
+
137: "3hCPRGf4z88VC5rsBKU5AA9FBBq5nF3jbKJG7VZCbhjm",
|
|
196212
|
+
8453: "43Hwfi3dJSoGpyas9VwNoDAv55yjgGrPpNSmbQZArzMG",
|
|
196213
|
+
42161: "FbCGRftH4a3yZugY7TnbYgPJVEv2LvMT6oF1fxPe9aJM",
|
|
196214
|
+
42220: "ESdrTJ3twMwWVoQ1hUE2u7PugEHX3QkenudD6aXCkDQ4",
|
|
196215
|
+
43114: "GVH9h9KZ9CqheUEL93qMbq7QwgoBu32QXQDPR6bev4Eo",
|
|
196216
|
+
81457: "2LHovKznvo8YmKC9ZprPjsYAZDCc4K5q4AYz8s3cnQn1"
|
|
196217
|
+
};
|
|
196218
|
+
});
|
|
196219
|
+
|
|
196220
|
+
// src/infra/uniswap/subgraph.ts
|
|
196221
|
+
class UniswapSubgraph {
|
|
196222
|
+
apiKey;
|
|
196223
|
+
chainId;
|
|
196224
|
+
client;
|
|
196225
|
+
endpointUrl;
|
|
196226
|
+
poolCache = new Cache({ defaultTtl: CACHE_TTL.pool, maxEntries: 100 });
|
|
196227
|
+
dataCache = new Cache({ defaultTtl: CACHE_TTL.candles, maxEntries: 500 });
|
|
196228
|
+
requestCount = 0;
|
|
196229
|
+
lastResetTime = Date.now();
|
|
196230
|
+
throttledCount = 0;
|
|
196231
|
+
circuitState = "closed";
|
|
196232
|
+
consecutiveFailures = 0;
|
|
196233
|
+
circuitOpenedAt = 0;
|
|
196234
|
+
constructor(apiKey, chainId, client) {
|
|
196235
|
+
this.apiKey = apiKey;
|
|
196236
|
+
this.chainId = chainId;
|
|
196237
|
+
this.client = client;
|
|
196238
|
+
const subgraphId = V3_SUBGRAPH_IDS[chainId];
|
|
196239
|
+
this.endpointUrl = subgraphId ? `${GRAPH_GATEWAY}/subgraphs/id/${subgraphId}` : null;
|
|
196240
|
+
}
|
|
196241
|
+
isAvailable() {
|
|
196242
|
+
if (!this.endpointUrl)
|
|
196243
|
+
return false;
|
|
196244
|
+
if (this.circuitState === "open") {
|
|
196245
|
+
if (Date.now() - this.circuitOpenedAt > CIRCUIT_RESET_MS) {
|
|
196246
|
+
this.circuitState = "half-open";
|
|
196247
|
+
return true;
|
|
196248
|
+
}
|
|
196249
|
+
return false;
|
|
196250
|
+
}
|
|
196251
|
+
return true;
|
|
196252
|
+
}
|
|
196253
|
+
async checkRateLimit() {
|
|
196254
|
+
const now2 = Date.now();
|
|
196255
|
+
if (now2 - this.lastResetTime > 60000) {
|
|
196256
|
+
this.requestCount = 0;
|
|
196257
|
+
this.lastResetTime = now2;
|
|
196258
|
+
this.throttledCount = 0;
|
|
196259
|
+
}
|
|
196260
|
+
if (this.requestCount >= RATE_LIMIT.maxPerMinute) {
|
|
196261
|
+
const waitMs = 60000 - (now2 - this.lastResetTime);
|
|
196262
|
+
throw new Error(`Subgraph rate limit reached (${RATE_LIMIT.maxPerMinute}/min). Retry in ${Math.ceil(waitMs / 1000)}s.`);
|
|
196263
|
+
}
|
|
196264
|
+
if (this.requestCount >= RATE_LIMIT.throttleAt) {
|
|
196265
|
+
const delayMs = 500 * (this.requestCount - RATE_LIMIT.throttleAt + 1);
|
|
196266
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
196267
|
+
this.throttledCount++;
|
|
196268
|
+
}
|
|
196269
|
+
}
|
|
196270
|
+
async query(graphql, variables = {}) {
|
|
196271
|
+
if (!this.endpointUrl) {
|
|
196272
|
+
throw new Error(`No V3 subgraph available for chain ${this.chainId}`);
|
|
196273
|
+
}
|
|
196274
|
+
if (this.circuitState === "open" && !this.isAvailable()) {
|
|
196275
|
+
throw new Error("Subgraph circuit breaker is open");
|
|
196276
|
+
}
|
|
196277
|
+
await this.checkRateLimit();
|
|
196278
|
+
this.requestCount++;
|
|
196279
|
+
let lastError = null;
|
|
196280
|
+
for (let attempt = 0;attempt <= MAX_RETRIES3; attempt++) {
|
|
196281
|
+
if (attempt > 0) {
|
|
196282
|
+
const delay5 = BASE_DELAY_MS2 * 2 ** (attempt - 1);
|
|
196283
|
+
await new Promise((r) => setTimeout(r, delay5));
|
|
196284
|
+
}
|
|
196285
|
+
try {
|
|
196286
|
+
const url2 = `${GRAPH_GATEWAY}/${this.apiKey}${this.endpointUrl}`;
|
|
196287
|
+
const res = await fetch(url2, {
|
|
196288
|
+
method: "POST",
|
|
196289
|
+
headers: { "Content-Type": "application/json" },
|
|
196290
|
+
body: JSON.stringify({ query: graphql, variables })
|
|
196291
|
+
});
|
|
196292
|
+
if (res.ok) {
|
|
196293
|
+
const json3 = await res.json();
|
|
196294
|
+
if (json3.errors?.length) {
|
|
196295
|
+
throw new Error(`Subgraph error: ${json3.errors.map((e2) => e2.message).join("; ")}`);
|
|
196296
|
+
}
|
|
196297
|
+
this.consecutiveFailures = 0;
|
|
196298
|
+
if (this.circuitState === "half-open")
|
|
196299
|
+
this.circuitState = "closed";
|
|
196300
|
+
return json3.data;
|
|
196301
|
+
}
|
|
196302
|
+
const errBody = await res.text().catch(() => "");
|
|
196303
|
+
if ([429, 500, 503].includes(res.status) && attempt < MAX_RETRIES3) {
|
|
196304
|
+
if (res.status === 429)
|
|
196305
|
+
this.throttledCount++;
|
|
196306
|
+
lastError = new Error(`Subgraph HTTP ${res.status}: ${errBody}`);
|
|
196307
|
+
continue;
|
|
196308
|
+
}
|
|
196309
|
+
this.onFailure();
|
|
196310
|
+
throw new Error(`Subgraph HTTP ${res.status}: ${errBody}`);
|
|
196311
|
+
} catch (err) {
|
|
196312
|
+
if (err instanceof Error && err.message.startsWith("Subgraph"))
|
|
196313
|
+
throw err;
|
|
196314
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
196315
|
+
if (attempt >= MAX_RETRIES3) {
|
|
196316
|
+
this.onFailure();
|
|
196317
|
+
throw lastError;
|
|
196318
|
+
}
|
|
196319
|
+
}
|
|
196320
|
+
}
|
|
196321
|
+
throw lastError || new Error("Subgraph request failed");
|
|
196322
|
+
}
|
|
196323
|
+
onFailure() {
|
|
196324
|
+
this.consecutiveFailures++;
|
|
196325
|
+
if (this.consecutiveFailures >= CIRCUIT_FAILURE_THRESHOLD) {
|
|
196326
|
+
this.circuitState = "open";
|
|
196327
|
+
this.circuitOpenedAt = Date.now();
|
|
196328
|
+
}
|
|
196329
|
+
}
|
|
196330
|
+
async resolvePool(symbol16) {
|
|
196331
|
+
const cacheKey = `pool:${this.chainId}:${symbol16}`;
|
|
196332
|
+
const cached2 = this.poolCache.get(cacheKey);
|
|
196333
|
+
if (cached2)
|
|
196334
|
+
return cached2;
|
|
196335
|
+
const { tokenIn, tokenOut } = await this.client.resolveSymbol(symbol16);
|
|
196336
|
+
const inLower = tokenIn.toLowerCase();
|
|
196337
|
+
const outLower = tokenOut.toLowerCase();
|
|
196338
|
+
const [t0, t1] = inLower < outLower ? [inLower, outLower] : [outLower, inLower];
|
|
196339
|
+
const isInverted = inLower !== t0;
|
|
196340
|
+
const data = await this.query(`query($t0: String!, $t1: String!) {
|
|
196341
|
+
pools(
|
|
196342
|
+
first: 1
|
|
196343
|
+
where: { token0: $t0, token1: $t1 }
|
|
196344
|
+
orderBy: liquidity
|
|
196345
|
+
orderDirection: desc
|
|
196346
|
+
) {
|
|
196347
|
+
id feeTier liquidity sqrtPrice tick
|
|
196348
|
+
token0Price token1Price
|
|
196349
|
+
totalValueLockedUSD volumeUSD
|
|
196350
|
+
token0 { id symbol name decimals }
|
|
196351
|
+
token1 { id symbol name decimals }
|
|
196352
|
+
}
|
|
196353
|
+
}`, { t0, t1 });
|
|
196354
|
+
if (!data.pools.length) {
|
|
196355
|
+
throw new Error(`No Uniswap V3 pool found for ${symbol16} on chain ${this.chainId}`);
|
|
196356
|
+
}
|
|
196357
|
+
const resolved = { pool: data.pools[0], isInverted };
|
|
196358
|
+
this.poolCache.set(cacheKey, resolved, CACHE_TTL.pool);
|
|
196359
|
+
return resolved;
|
|
196360
|
+
}
|
|
196361
|
+
getPoolPrice(pool, isInverted) {
|
|
196362
|
+
return isInverted ? parseFloat(pool.token1Price) : parseFloat(pool.token0Price);
|
|
196363
|
+
}
|
|
196364
|
+
async getCandles(symbol16, interval, limit) {
|
|
196365
|
+
const { pool, isInverted } = await this.resolvePool(symbol16);
|
|
196366
|
+
const useHourly = ["1m", "5m", "15m", "30m", "1h", "4h"].includes(interval);
|
|
196367
|
+
const intervalSeconds = useHourly ? 3600 : 86400;
|
|
196368
|
+
const start = Math.floor(Date.now() / 1000) - limit * intervalSeconds;
|
|
196369
|
+
const cacheKey = `candle:${this.chainId}:${pool.id}:${interval}:${limit}`;
|
|
196370
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196371
|
+
if (cached2)
|
|
196372
|
+
return cached2;
|
|
196373
|
+
let candles;
|
|
196374
|
+
if (useHourly) {
|
|
196375
|
+
const data = await this.query(`query($pool: String!, $start: Int!, $first: Int!) {
|
|
196376
|
+
poolHourDatas(
|
|
196377
|
+
first: $first
|
|
196378
|
+
where: { pool: $pool, periodStartUnix_gte: $start }
|
|
196379
|
+
orderBy: periodStartUnix
|
|
196380
|
+
orderDirection: asc
|
|
196381
|
+
) {
|
|
196382
|
+
periodStartUnix open high low close
|
|
196383
|
+
volumeUSD volumeToken0 volumeToken1 tvlUSD
|
|
196384
|
+
token0Price token1Price
|
|
196385
|
+
}
|
|
196386
|
+
}`, { pool: pool.id, start, first: Math.min(limit, 1000) });
|
|
196387
|
+
candles = data.poolHourDatas.map((d) => this.mapCandle(d.periodStartUnix, intervalSeconds, d, isInverted));
|
|
196388
|
+
} else {
|
|
196389
|
+
const data = await this.query(`query($pool: String!, $start: Int!, $first: Int!) {
|
|
196390
|
+
poolDayDatas(
|
|
196391
|
+
first: $first
|
|
196392
|
+
where: { pool: $pool, date_gte: $start }
|
|
196393
|
+
orderBy: date
|
|
196394
|
+
orderDirection: asc
|
|
196395
|
+
) {
|
|
196396
|
+
date open high low close
|
|
196397
|
+
volumeUSD volumeToken0 volumeToken1 tvlUSD
|
|
196398
|
+
token0Price token1Price
|
|
196399
|
+
}
|
|
196400
|
+
}`, { pool: pool.id, start, first: Math.min(limit, 1000) });
|
|
196401
|
+
candles = data.poolDayDatas.map((d) => this.mapCandle(d.date, intervalSeconds, d, isInverted));
|
|
196402
|
+
}
|
|
196403
|
+
this.dataCache.set(cacheKey, candles, CACHE_TTL.candles);
|
|
196404
|
+
return candles;
|
|
196405
|
+
}
|
|
196406
|
+
mapCandle(timestamp, intervalSec, d, isInverted) {
|
|
196407
|
+
let open = parseFloat(d.open);
|
|
196408
|
+
let high = parseFloat(d.high);
|
|
196409
|
+
let low = parseFloat(d.low);
|
|
196410
|
+
let close = parseFloat(d.close);
|
|
196411
|
+
if (open === 0 && close === 0) {
|
|
196412
|
+
const price = isInverted ? parseFloat(d.token1Price) : parseFloat(d.token0Price);
|
|
196413
|
+
open = high = low = close = price;
|
|
196414
|
+
} else if (isInverted && open !== 0 && high !== 0 && low !== 0 && close !== 0) {
|
|
196415
|
+
const iOpen = 1 / open;
|
|
196416
|
+
const iHigh = 1 / low;
|
|
196417
|
+
const iLow = 1 / high;
|
|
196418
|
+
const iClose = 1 / close;
|
|
196419
|
+
open = iOpen;
|
|
196420
|
+
high = iHigh;
|
|
196421
|
+
low = iLow;
|
|
196422
|
+
close = iClose;
|
|
196423
|
+
} else if (isInverted) {
|
|
196424
|
+
const price = parseFloat(d.token1Price);
|
|
196425
|
+
if (price !== 0) {
|
|
196426
|
+
open = high = low = close = price;
|
|
196427
|
+
}
|
|
196428
|
+
}
|
|
196429
|
+
return {
|
|
196430
|
+
openTime: timestamp * 1000,
|
|
196431
|
+
open,
|
|
196432
|
+
high,
|
|
196433
|
+
low,
|
|
196434
|
+
close,
|
|
196435
|
+
volume: parseFloat(d.volumeUSD),
|
|
196436
|
+
closeTime: (timestamp + intervalSec) * 1000 - 1
|
|
196437
|
+
};
|
|
196438
|
+
}
|
|
196439
|
+
async get24hrTickers(limit = 100) {
|
|
196440
|
+
const cacheKey = `tickers:${this.chainId}:${limit}`;
|
|
196441
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196442
|
+
if (cached2)
|
|
196443
|
+
return cached2;
|
|
196444
|
+
const fetchLimit = Math.min(limit + 15, 200);
|
|
196445
|
+
const data = await this.query(`query($first: Int!) {
|
|
196446
|
+
tokens(
|
|
196447
|
+
first: $first
|
|
196448
|
+
orderBy: volumeUSD
|
|
196449
|
+
orderDirection: desc
|
|
196450
|
+
where: { volumeUSD_gt: "1000" }
|
|
196451
|
+
) {
|
|
196452
|
+
id symbol name
|
|
196453
|
+
volumeUSD totalValueLockedUSD
|
|
196454
|
+
tokenDayDatas(first: 2, orderBy: date, orderDirection: desc) {
|
|
196455
|
+
date priceUSD volumeUSD
|
|
196456
|
+
open high low close
|
|
196457
|
+
}
|
|
196458
|
+
}
|
|
196459
|
+
}`, { first: fetchLimit });
|
|
196460
|
+
const now2 = Date.now();
|
|
196461
|
+
const tickers = [];
|
|
196462
|
+
for (const token of data.tokens) {
|
|
196463
|
+
if (STABLECOIN_SYMBOLS.has(token.symbol.toUpperCase()))
|
|
196464
|
+
continue;
|
|
196465
|
+
if (token.tokenDayDatas.length === 0)
|
|
196466
|
+
continue;
|
|
196467
|
+
const today = token.tokenDayDatas[0];
|
|
196468
|
+
const yesterday = token.tokenDayDatas[1];
|
|
196469
|
+
const todayPrice = parseFloat(today.priceUSD);
|
|
196470
|
+
const yesterdayPrice = yesterday ? parseFloat(yesterday.priceUSD) : todayPrice;
|
|
196471
|
+
const priceChange = todayPrice - yesterdayPrice;
|
|
196472
|
+
const priceChangePercent = yesterdayPrice !== 0 ? priceChange / yesterdayPrice * 100 : 0;
|
|
196473
|
+
const highPrice = parseFloat(today.high) || todayPrice;
|
|
196474
|
+
const lowPrice = parseFloat(today.low) || todayPrice;
|
|
196475
|
+
tickers.push({
|
|
196476
|
+
symbol: `${token.symbol.toUpperCase()}USDC`,
|
|
196477
|
+
priceChange,
|
|
196478
|
+
priceChangePercent,
|
|
196479
|
+
lastPrice: todayPrice,
|
|
196480
|
+
highPrice,
|
|
196481
|
+
lowPrice,
|
|
196482
|
+
volume: parseFloat(today.volumeUSD),
|
|
196483
|
+
quoteVolume: parseFloat(today.volumeUSD),
|
|
196484
|
+
openTime: today.date * 1000,
|
|
196485
|
+
closeTime: now2
|
|
196486
|
+
});
|
|
196487
|
+
if (tickers.length >= limit)
|
|
196488
|
+
break;
|
|
196489
|
+
}
|
|
196490
|
+
this.dataCache.set(cacheKey, tickers, CACHE_TTL.tickers);
|
|
196491
|
+
return tickers;
|
|
196492
|
+
}
|
|
196493
|
+
async getTopSymbols(n) {
|
|
196494
|
+
const cacheKey = `top:${this.chainId}:${n}`;
|
|
196495
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196496
|
+
if (cached2)
|
|
196497
|
+
return cached2;
|
|
196498
|
+
const fetchN = Math.min(n + 10, 100);
|
|
196499
|
+
const data = await this.query(`query($first: Int!) {
|
|
196500
|
+
tokens(
|
|
196501
|
+
first: $first
|
|
196502
|
+
orderBy: volumeUSD
|
|
196503
|
+
orderDirection: desc
|
|
196504
|
+
where: { volumeUSD_gt: "1000" }
|
|
196505
|
+
) {
|
|
196506
|
+
id symbol
|
|
196507
|
+
}
|
|
196508
|
+
}`, { first: fetchN });
|
|
196509
|
+
const symbols = [];
|
|
196510
|
+
for (const token of data.tokens) {
|
|
196511
|
+
const sym = token.symbol.toUpperCase();
|
|
196512
|
+
if (STABLECOIN_SYMBOLS.has(sym))
|
|
196513
|
+
continue;
|
|
196514
|
+
if (sym === "WETH" || sym === "WBTC") {
|
|
196515
|
+
symbols.push(`${sym.slice(1)}USDC`);
|
|
196516
|
+
} else {
|
|
196517
|
+
symbols.push(`${sym}USDC`);
|
|
196518
|
+
}
|
|
196519
|
+
if (symbols.length >= n)
|
|
196520
|
+
break;
|
|
196521
|
+
}
|
|
196522
|
+
this.dataCache.set(cacheKey, symbols, CACHE_TTL.top);
|
|
196523
|
+
return symbols;
|
|
196524
|
+
}
|
|
196525
|
+
async getTradeHistory(symbol16, limit) {
|
|
196526
|
+
const { pool, isInverted } = await this.resolvePool(symbol16);
|
|
196527
|
+
const cacheKey = `trades:${this.chainId}:${pool.id}:${limit}`;
|
|
196528
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196529
|
+
if (cached2)
|
|
196530
|
+
return cached2;
|
|
196531
|
+
const data = await this.query(`query($pool: String!, $first: Int!) {
|
|
196532
|
+
swaps(
|
|
196533
|
+
first: $first
|
|
196534
|
+
where: { pool: $pool }
|
|
196535
|
+
orderBy: timestamp
|
|
196536
|
+
orderDirection: desc
|
|
196537
|
+
) {
|
|
196538
|
+
id timestamp
|
|
196539
|
+
amount0 amount1 amountUSD
|
|
196540
|
+
sender recipient
|
|
196541
|
+
sqrtPriceX96 tick
|
|
196542
|
+
}
|
|
196543
|
+
}`, { pool: pool.id, first: Math.min(limit, 1000) });
|
|
196544
|
+
const trades = data.swaps.map((swap) => {
|
|
196545
|
+
const amount0 = parseFloat(swap.amount0);
|
|
196546
|
+
const amount1 = parseFloat(swap.amount1);
|
|
196547
|
+
const amountUSD = parseFloat(swap.amountUSD);
|
|
196548
|
+
const baseAmount = isInverted ? amount1 : amount0;
|
|
196549
|
+
const side = baseAmount > 0 ? "SELL" : "BUY";
|
|
196550
|
+
const quantity = Math.abs(baseAmount);
|
|
196551
|
+
const price = amountUSD > 0 && quantity > 0 ? amountUSD / quantity : quantity > 0 ? this.getPoolPrice(pool, isInverted) : 0;
|
|
196552
|
+
return {
|
|
196553
|
+
id: swap.id,
|
|
196554
|
+
orderId: swap.id,
|
|
196555
|
+
symbol: symbol16,
|
|
196556
|
+
side,
|
|
196557
|
+
price,
|
|
196558
|
+
quantity,
|
|
196559
|
+
commission: 0,
|
|
196560
|
+
commissionAsset: "USD",
|
|
196561
|
+
time: parseInt(swap.timestamp, 10) * 1000,
|
|
196562
|
+
isMaker: false
|
|
196563
|
+
};
|
|
196564
|
+
});
|
|
196565
|
+
this.dataCache.set(cacheKey, trades, CACHE_TTL.trades);
|
|
196566
|
+
return trades;
|
|
196567
|
+
}
|
|
196568
|
+
async getPoolData(symbol16) {
|
|
196569
|
+
const { pool, isInverted } = await this.resolvePool(symbol16);
|
|
196570
|
+
const cacheKey = `poolData:${this.chainId}:${pool.id}`;
|
|
196571
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196572
|
+
if (cached2)
|
|
196573
|
+
return cached2;
|
|
196574
|
+
const data = await this.query(`query($id: ID!) {
|
|
196575
|
+
pool(id: $id) {
|
|
196576
|
+
id feeTier liquidity sqrtPrice tick
|
|
196577
|
+
token0Price token1Price
|
|
196578
|
+
totalValueLockedUSD volumeUSD
|
|
196579
|
+
token0 { id symbol name decimals }
|
|
196580
|
+
token1 { id symbol name decimals }
|
|
196581
|
+
}
|
|
196582
|
+
}`, { id: pool.id });
|
|
196583
|
+
if (!data.pool)
|
|
196584
|
+
throw new Error(`Pool ${pool.id} not found`);
|
|
196585
|
+
const result = {
|
|
196586
|
+
price: this.getPoolPrice(data.pool, isInverted),
|
|
196587
|
+
feeTier: parseInt(data.pool.feeTier, 10),
|
|
196588
|
+
tvlUSD: parseFloat(data.pool.totalValueLockedUSD),
|
|
196589
|
+
liquidity: data.pool.liquidity
|
|
196590
|
+
};
|
|
196591
|
+
this.dataCache.set(cacheKey, result, CACHE_TTL.poolData);
|
|
196592
|
+
return result;
|
|
196593
|
+
}
|
|
196594
|
+
async getOrderBook(symbol16) {
|
|
196595
|
+
const { pool, isInverted } = await this.resolvePool(symbol16);
|
|
196596
|
+
const { price, feeTier, tvlUSD } = await this.getPoolData(symbol16);
|
|
196597
|
+
const spreadFraction = feeTier / 1e6;
|
|
196598
|
+
const halfSpread = price * spreadFraction / 2;
|
|
196599
|
+
try {
|
|
196600
|
+
const ticks = await this.getTickLiquidity(symbol16, 10);
|
|
196601
|
+
if (ticks.length > 0) {
|
|
196602
|
+
const freshPool = await this.getPoolData(symbol16);
|
|
196603
|
+
const bids = [];
|
|
196604
|
+
const asks = [];
|
|
196605
|
+
for (const tick of ticks) {
|
|
196606
|
+
const tickIdx = parseInt(tick.tickIdx, 10);
|
|
196607
|
+
const liqNet = parseFloat(tick.liquidityNet);
|
|
196608
|
+
if (liqNet === 0)
|
|
196609
|
+
continue;
|
|
196610
|
+
const tickPrice = isInverted ? parseFloat(tick.price1) : parseFloat(tick.price0);
|
|
196611
|
+
const liquidityScore = Math.abs(liqNet);
|
|
196612
|
+
if (tickPrice <= freshPool.price) {
|
|
196613
|
+
bids.push({ price: tickPrice, quantity: liquidityScore });
|
|
196614
|
+
} else {
|
|
196615
|
+
asks.push({ price: tickPrice, quantity: liquidityScore });
|
|
196616
|
+
}
|
|
196617
|
+
}
|
|
196618
|
+
if (bids.length > 0 || asks.length > 0) {
|
|
196619
|
+
bids.sort((a, b) => b.price - a.price);
|
|
196620
|
+
asks.sort((a, b) => a.price - b.price);
|
|
196621
|
+
return { lastUpdateId: Date.now(), bids, asks };
|
|
196622
|
+
}
|
|
196623
|
+
}
|
|
196624
|
+
} catch {}
|
|
196625
|
+
const depthProxy = tvlUSD / 2;
|
|
196626
|
+
return {
|
|
196627
|
+
lastUpdateId: Date.now(),
|
|
196628
|
+
bids: [{ price: price - halfSpread, quantity: depthProxy / price }],
|
|
196629
|
+
asks: [{ price: price + halfSpread, quantity: depthProxy / price }]
|
|
196630
|
+
};
|
|
196631
|
+
}
|
|
196632
|
+
async getBookTicker(symbol16) {
|
|
196633
|
+
const { price, feeTier, tvlUSD } = await this.getPoolData(symbol16);
|
|
196634
|
+
const spreadFraction = feeTier / 1e6;
|
|
196635
|
+
const halfSpread = price * spreadFraction / 2;
|
|
196636
|
+
const depthProxy = tvlUSD / 2;
|
|
196637
|
+
return {
|
|
196638
|
+
symbol: symbol16,
|
|
196639
|
+
bidPrice: price - halfSpread,
|
|
196640
|
+
bidQty: depthProxy / price,
|
|
196641
|
+
askPrice: price + halfSpread,
|
|
196642
|
+
askQty: depthProxy / price
|
|
196643
|
+
};
|
|
196644
|
+
}
|
|
196645
|
+
async getSpread(symbol16) {
|
|
196646
|
+
const { price, feeTier } = await this.getPoolData(symbol16);
|
|
196647
|
+
const spreadFraction = feeTier / 1e6;
|
|
196648
|
+
const spread = price * spreadFraction;
|
|
196649
|
+
return {
|
|
196650
|
+
spread,
|
|
196651
|
+
spreadPercent: spreadFraction * 100,
|
|
196652
|
+
bidPrice: price - spread / 2,
|
|
196653
|
+
askPrice: price + spread / 2
|
|
196654
|
+
};
|
|
196655
|
+
}
|
|
196656
|
+
async getAvgPrice(symbol16) {
|
|
196657
|
+
const { price } = await this.getPoolData(symbol16);
|
|
196658
|
+
return { mins: 5, price };
|
|
196659
|
+
}
|
|
196660
|
+
async getEthPrice() {
|
|
196661
|
+
const cacheKey = `bundle:${this.chainId}`;
|
|
196662
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196663
|
+
if (cached2 !== undefined)
|
|
196664
|
+
return cached2;
|
|
196665
|
+
const data = await this.query(`{ bundle(id: "1") { id ethPriceUSD } }`);
|
|
196666
|
+
const price = data.bundle ? parseFloat(data.bundle.ethPriceUSD) : NaN;
|
|
196667
|
+
if (isNaN(price) || price <= 0) {
|
|
196668
|
+
throw new Error(`Unable to fetch ETH price from bundle on chain ${this.chainId}`);
|
|
196669
|
+
}
|
|
196670
|
+
this.dataCache.set(cacheKey, price, CACHE_TTL.bundle);
|
|
196671
|
+
return price;
|
|
196672
|
+
}
|
|
196673
|
+
async getFactory() {
|
|
196674
|
+
const cacheKey = `factory:${this.chainId}`;
|
|
196675
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196676
|
+
if (cached2 !== undefined)
|
|
196677
|
+
return cached2;
|
|
196678
|
+
const data = await this.query(`{ factory(id: "1") {
|
|
196679
|
+
id poolCount txCount
|
|
196680
|
+
totalVolumeUSD totalVolumeETH
|
|
196681
|
+
totalFeesUSD totalFeesETH
|
|
196682
|
+
totalValueLockedUSD totalValueLockedETH
|
|
196683
|
+
owner
|
|
196684
|
+
} }`);
|
|
196685
|
+
this.dataCache.set(cacheKey, data.factory, CACHE_TTL.protocol);
|
|
196686
|
+
return data.factory;
|
|
196687
|
+
}
|
|
196688
|
+
async getTokenHourCandles(tokenAddress, limit = 168) {
|
|
196689
|
+
const addr = tokenAddress.toLowerCase();
|
|
196690
|
+
const cacheKey = `tokenHour:${this.chainId}:${addr}:${limit}`;
|
|
196691
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196692
|
+
if (cached2)
|
|
196693
|
+
return cached2;
|
|
196694
|
+
const start = Math.floor(Date.now() / 1000) - limit * 3600;
|
|
196695
|
+
const data = await this.query(`query($token: String!, $start: Int!, $first: Int!) {
|
|
196696
|
+
tokenHourDatas(
|
|
196697
|
+
first: $first
|
|
196698
|
+
where: { token: $token, periodStartUnix_gte: $start }
|
|
196699
|
+
orderBy: periodStartUnix
|
|
196700
|
+
orderDirection: asc
|
|
196701
|
+
) {
|
|
196702
|
+
periodStartUnix
|
|
196703
|
+
open high low close
|
|
196704
|
+
priceUSD volumeUSD feesUSD
|
|
196705
|
+
totalValueLockedUSD
|
|
196706
|
+
token { id }
|
|
196707
|
+
}
|
|
196708
|
+
}`, { token: addr, start, first: Math.min(limit, 1000) });
|
|
196709
|
+
const candles = data.tokenHourDatas.map((d) => {
|
|
196710
|
+
const fallback = parseFloat(d.priceUSD);
|
|
196711
|
+
const openVal = parseFloat(d.open);
|
|
196712
|
+
const highVal = parseFloat(d.high);
|
|
196713
|
+
const lowVal = parseFloat(d.low);
|
|
196714
|
+
const closeVal = parseFloat(d.close);
|
|
196715
|
+
return {
|
|
196716
|
+
openTime: d.periodStartUnix * 1000,
|
|
196717
|
+
open: openVal > 0 ? openVal : fallback,
|
|
196718
|
+
high: highVal > 0 ? highVal : fallback,
|
|
196719
|
+
low: lowVal > 0 ? lowVal : fallback,
|
|
196720
|
+
close: closeVal > 0 ? closeVal : fallback,
|
|
196721
|
+
volume: parseFloat(d.volumeUSD),
|
|
196722
|
+
closeTime: (d.periodStartUnix + 3600) * 1000 - 1
|
|
196723
|
+
};
|
|
196724
|
+
});
|
|
196725
|
+
this.dataCache.set(cacheKey, candles, CACHE_TTL.candles);
|
|
196726
|
+
return candles;
|
|
196727
|
+
}
|
|
196728
|
+
async getTickLiquidity(symbol16, ticksPerSide = 20) {
|
|
196729
|
+
const { pool } = await this.resolvePool(symbol16);
|
|
196730
|
+
const freshData = await this.query(`query($id: ID!) { pool(id: $id) { tick feeTier } }`, { id: pool.id });
|
|
196731
|
+
const currentTick = parseInt(freshData.pool?.tick ?? pool.tick, 10);
|
|
196732
|
+
const feeTier = parseInt(freshData.pool?.feeTier ?? pool.feeTier, 10);
|
|
196733
|
+
const tickSpacing = feeTier === 100 ? 1 : feeTier === 500 ? 10 : feeTier === 3000 ? 60 : feeTier === 1e4 ? 200 : 60;
|
|
196734
|
+
const tickRange = ticksPerSide * tickSpacing;
|
|
196735
|
+
const cacheKey = `ticks:${this.chainId}:${pool.id}:${currentTick}:${ticksPerSide}`;
|
|
196736
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196737
|
+
if (cached2)
|
|
196738
|
+
return cached2;
|
|
196739
|
+
const minTick = currentTick - tickRange;
|
|
196740
|
+
const maxTick = currentTick + tickRange;
|
|
196741
|
+
const data = await this.query(`query($pool: String!, $minTick: BigInt!, $maxTick: BigInt!) {
|
|
196742
|
+
ticks(
|
|
196743
|
+
first: 100
|
|
196744
|
+
where: { pool: $pool, tickIdx_gte: $minTick, tickIdx_lte: $maxTick }
|
|
196745
|
+
orderBy: tickIdx
|
|
196746
|
+
orderDirection: asc
|
|
196747
|
+
) {
|
|
196748
|
+
id tickIdx poolAddress
|
|
196749
|
+
liquidityGross liquidityNet
|
|
196750
|
+
price0 price1
|
|
196751
|
+
volumeToken0 volumeToken1 volumeUSD
|
|
196752
|
+
feesUSD
|
|
196753
|
+
}
|
|
196754
|
+
}`, { pool: pool.id, minTick: minTick.toString(), maxTick: maxTick.toString() });
|
|
196755
|
+
this.dataCache.set(cacheKey, data.ticks, CACHE_TTL.ticks);
|
|
196756
|
+
return data.ticks;
|
|
196757
|
+
}
|
|
196758
|
+
async getMints(symbol16, limit = 50) {
|
|
196759
|
+
const { pool } = await this.resolvePool(symbol16);
|
|
196760
|
+
const cacheKey = `mints:${this.chainId}:${pool.id}:${limit}`;
|
|
196761
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196762
|
+
if (cached2)
|
|
196763
|
+
return cached2;
|
|
196764
|
+
const data = await this.query(`query($pool: String!, $first: Int!) {
|
|
196765
|
+
mints(
|
|
196766
|
+
first: $first
|
|
196767
|
+
where: { pool: $pool }
|
|
196768
|
+
orderBy: timestamp
|
|
196769
|
+
orderDirection: desc
|
|
196770
|
+
) {
|
|
196771
|
+
id timestamp
|
|
196772
|
+
transaction { id timestamp }
|
|
196773
|
+
pool { id }
|
|
196774
|
+
token0 { id symbol name decimals }
|
|
196775
|
+
token1 { id symbol name decimals }
|
|
196776
|
+
owner sender origin
|
|
196777
|
+
amount amount0 amount1 amountUSD
|
|
196778
|
+
tickLower tickUpper logIndex
|
|
196779
|
+
}
|
|
196780
|
+
}`, { pool: pool.id, first: Math.min(limit, 1000) });
|
|
196781
|
+
this.dataCache.set(cacheKey, data.mints, CACHE_TTL.events);
|
|
196782
|
+
return data.mints;
|
|
196783
|
+
}
|
|
196784
|
+
async getBurns(symbol16, limit = 50) {
|
|
196785
|
+
const { pool } = await this.resolvePool(symbol16);
|
|
196786
|
+
const cacheKey = `burns:${this.chainId}:${pool.id}:${limit}`;
|
|
196787
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196788
|
+
if (cached2)
|
|
196789
|
+
return cached2;
|
|
196790
|
+
const data = await this.query(`query($pool: String!, $first: Int!) {
|
|
196791
|
+
burns(
|
|
196792
|
+
first: $first
|
|
196793
|
+
where: { pool: $pool }
|
|
196794
|
+
orderBy: timestamp
|
|
196795
|
+
orderDirection: desc
|
|
196796
|
+
) {
|
|
196797
|
+
id timestamp
|
|
196798
|
+
transaction { id timestamp }
|
|
196799
|
+
pool { id }
|
|
196800
|
+
token0 { id symbol name decimals }
|
|
196801
|
+
token1 { id symbol name decimals }
|
|
196802
|
+
owner origin
|
|
196803
|
+
amount amount0 amount1 amountUSD
|
|
196804
|
+
tickLower tickUpper logIndex
|
|
196805
|
+
}
|
|
196806
|
+
}`, { pool: pool.id, first: Math.min(limit, 1000) });
|
|
196807
|
+
this.dataCache.set(cacheKey, data.burns, CACHE_TTL.events);
|
|
196808
|
+
return data.burns;
|
|
196809
|
+
}
|
|
196810
|
+
async getCollects(symbol16, limit = 50) {
|
|
196811
|
+
const { pool } = await this.resolvePool(symbol16);
|
|
196812
|
+
const cacheKey = `collects:${this.chainId}:${pool.id}:${limit}`;
|
|
196813
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196814
|
+
if (cached2)
|
|
196815
|
+
return cached2;
|
|
196816
|
+
const data = await this.query(`query($pool: String!, $first: Int!) {
|
|
196817
|
+
collects(
|
|
196818
|
+
first: $first
|
|
196819
|
+
where: { pool: $pool }
|
|
196820
|
+
orderBy: timestamp
|
|
196821
|
+
orderDirection: desc
|
|
196822
|
+
) {
|
|
196823
|
+
id timestamp
|
|
196824
|
+
transaction { id timestamp }
|
|
196825
|
+
pool { id }
|
|
196826
|
+
owner
|
|
196827
|
+
amount0 amount1 amountUSD
|
|
196828
|
+
tickLower tickUpper logIndex
|
|
196829
|
+
}
|
|
196830
|
+
}`, { pool: pool.id, first: Math.min(limit, 1000) });
|
|
196831
|
+
this.dataCache.set(cacheKey, data.collects, CACHE_TTL.events);
|
|
196832
|
+
return data.collects;
|
|
196833
|
+
}
|
|
196834
|
+
async getFlashLoans(symbol16, limit = 50) {
|
|
196835
|
+
const { pool } = await this.resolvePool(symbol16);
|
|
196836
|
+
const cacheKey = `flashes:${this.chainId}:${pool.id}:${limit}`;
|
|
196837
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196838
|
+
if (cached2)
|
|
196839
|
+
return cached2;
|
|
196840
|
+
const data = await this.query(`query($pool: String!, $first: Int!) {
|
|
196841
|
+
flashes(
|
|
196842
|
+
first: $first
|
|
196843
|
+
where: { pool: $pool }
|
|
196844
|
+
orderBy: timestamp
|
|
196845
|
+
orderDirection: desc
|
|
196846
|
+
) {
|
|
196847
|
+
id timestamp
|
|
196848
|
+
transaction { id timestamp }
|
|
196849
|
+
pool { id }
|
|
196850
|
+
sender recipient
|
|
196851
|
+
amount0 amount1 amountUSD
|
|
196852
|
+
amount0Paid amount1Paid
|
|
196853
|
+
logIndex
|
|
196854
|
+
}
|
|
196855
|
+
}`, { pool: pool.id, first: Math.min(limit, 1000) });
|
|
196856
|
+
this.dataCache.set(cacheKey, data.flashes, CACHE_TTL.events);
|
|
196857
|
+
return data.flashes;
|
|
196858
|
+
}
|
|
196859
|
+
async getPositions(owner, limit = 50) {
|
|
196860
|
+
const addr = owner.toLowerCase();
|
|
196861
|
+
const cacheKey = `positions:${this.chainId}:${addr}:${limit}`;
|
|
196862
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196863
|
+
if (cached2)
|
|
196864
|
+
return cached2;
|
|
196865
|
+
const data = await this.query(`query($owner: String!, $first: Int!) {
|
|
196866
|
+
positions(
|
|
196867
|
+
first: $first
|
|
196868
|
+
where: { owner: $owner, liquidity_gt: "0" }
|
|
196869
|
+
orderBy: liquidity
|
|
196870
|
+
orderDirection: desc
|
|
196871
|
+
) {
|
|
196872
|
+
id owner
|
|
196873
|
+
pool { id token0 { id symbol name decimals } token1 { id symbol name decimals } }
|
|
196874
|
+
token0 { id symbol name decimals }
|
|
196875
|
+
token1 { id symbol name decimals }
|
|
196876
|
+
tickLower { tickIdx price0 price1 }
|
|
196877
|
+
tickUpper { tickIdx price0 price1 }
|
|
196878
|
+
liquidity
|
|
196879
|
+
depositedToken0 depositedToken1
|
|
196880
|
+
withdrawnToken0 withdrawnToken1
|
|
196881
|
+
collectedFeesToken0 collectedFeesToken1
|
|
196882
|
+
transaction { id timestamp }
|
|
196883
|
+
}
|
|
196884
|
+
}`, { owner: addr, first: Math.min(limit, 1000) });
|
|
196885
|
+
this.dataCache.set(cacheKey, data.positions, CACHE_TTL.positions);
|
|
196886
|
+
return data.positions;
|
|
196887
|
+
}
|
|
196888
|
+
async getPositionSnapshots(positionId, limit = 50) {
|
|
196889
|
+
const cacheKey = `snapshots:${this.chainId}:${positionId}:${limit}`;
|
|
196890
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196891
|
+
if (cached2)
|
|
196892
|
+
return cached2;
|
|
196893
|
+
const data = await this.query(`query($position: String!, $first: Int!) {
|
|
196894
|
+
positionSnapshots(
|
|
196895
|
+
first: $first
|
|
196896
|
+
where: { position: $position }
|
|
196897
|
+
orderBy: timestamp
|
|
196898
|
+
orderDirection: desc
|
|
196899
|
+
) {
|
|
196900
|
+
id owner
|
|
196901
|
+
pool { id }
|
|
196902
|
+
position { id }
|
|
196903
|
+
blockNumber timestamp
|
|
196904
|
+
liquidity
|
|
196905
|
+
depositedToken0 depositedToken1
|
|
196906
|
+
withdrawnToken0 withdrawnToken1
|
|
196907
|
+
collectedFeesToken0 collectedFeesToken1
|
|
196908
|
+
transaction { id }
|
|
196909
|
+
}
|
|
196910
|
+
}`, { position: positionId, first: Math.min(limit, 1000) });
|
|
196911
|
+
this.dataCache.set(cacheKey, data.positionSnapshots, CACHE_TTL.positions);
|
|
196912
|
+
return data.positionSnapshots;
|
|
196913
|
+
}
|
|
196914
|
+
async getProtocolDayData(days = 30) {
|
|
196915
|
+
const cacheKey = `protocol:${this.chainId}:${days}`;
|
|
196916
|
+
const cached2 = this.dataCache.get(cacheKey);
|
|
196917
|
+
if (cached2)
|
|
196918
|
+
return cached2;
|
|
196919
|
+
const start = Math.floor(Date.now() / 1000) - days * 86400;
|
|
196920
|
+
const data = await this.query(`query($start: Int!, $first: Int!) {
|
|
196921
|
+
uniswapDayDatas(
|
|
196922
|
+
first: $first
|
|
196923
|
+
where: { date_gte: $start }
|
|
196924
|
+
orderBy: date
|
|
196925
|
+
orderDirection: asc
|
|
196926
|
+
) {
|
|
196927
|
+
id date
|
|
196928
|
+
volumeETH volumeUSD
|
|
196929
|
+
feesUSD txCount tvlUSD
|
|
196930
|
+
}
|
|
196931
|
+
}`, { start, first: Math.min(days, 1000) });
|
|
196932
|
+
this.dataCache.set(cacheKey, data.uniswapDayDatas, CACHE_TTL.protocol);
|
|
196933
|
+
return data.uniswapDayDatas;
|
|
196934
|
+
}
|
|
196935
|
+
}
|
|
196936
|
+
var GRAPH_GATEWAY = "https://gateway.thegraph.com/api", MAX_RETRIES3 = 3, BASE_DELAY_MS2 = 500, RATE_LIMIT, CIRCUIT_FAILURE_THRESHOLD = 5, CIRCUIT_RESET_MS = 60000, CACHE_TTL, STABLECOIN_SYMBOLS;
|
|
196937
|
+
var init_subgraph = __esm(() => {
|
|
196938
|
+
init_subgraph_types();
|
|
196939
|
+
RATE_LIMIT = { maxPerMinute: 30, throttleAt: 25 };
|
|
196940
|
+
CACHE_TTL = {
|
|
196941
|
+
pool: 30 * 60000,
|
|
196942
|
+
candles: 5 * 60000,
|
|
196943
|
+
tickers: 2 * 60000,
|
|
196944
|
+
top: 5 * 60000,
|
|
196945
|
+
trades: 60000,
|
|
196946
|
+
poolData: 60000,
|
|
196947
|
+
bundle: 60000,
|
|
196948
|
+
ticks: 60000,
|
|
196949
|
+
events: 60000,
|
|
196950
|
+
positions: 5 * 60000,
|
|
196951
|
+
protocol: 5 * 60000
|
|
196952
|
+
};
|
|
196953
|
+
STABLECOIN_SYMBOLS = new Set(["USDC", "USDT", "DAI", "BUSD", "TUSD", "FRAX", "LUSD", "USDP", "GUSD", "PYUSD"]);
|
|
196954
|
+
});
|
|
196955
|
+
|
|
196196
196956
|
// src/infra/uniswap/index.ts
|
|
196197
196957
|
var init_uniswap = __esm(() => {
|
|
196198
196958
|
init_client9();
|
|
196199
196959
|
init_token_list();
|
|
196960
|
+
init_subgraph();
|
|
196961
|
+
init_subgraph_types();
|
|
196200
196962
|
init_types10();
|
|
196201
196963
|
});
|
|
196202
196964
|
|
|
196203
196965
|
// src/infra/exchange/adapters/uniswap.ts
|
|
196204
196966
|
class UniswapAdapter {
|
|
196205
196967
|
client;
|
|
196968
|
+
subgraph;
|
|
196206
196969
|
exchangeId = "uniswap";
|
|
196207
196970
|
displayName = "Uniswap";
|
|
196208
196971
|
localOrders = new Map;
|
|
196209
196972
|
localTrades = new Map;
|
|
196210
196973
|
orderCounter = 0;
|
|
196211
|
-
constructor(apiKey, walletAddress, chainId = 1) {
|
|
196974
|
+
constructor(apiKey, walletAddress, chainId = 1, graphApiKey) {
|
|
196212
196975
|
this.client = new UniswapClient(apiKey, walletAddress, chainId);
|
|
196976
|
+
this.subgraph = graphApiKey ? new UniswapSubgraph(graphApiKey, chainId, this.client) : null;
|
|
196213
196977
|
}
|
|
196214
196978
|
async testConnection() {
|
|
196215
196979
|
return this.client.testConnection();
|
|
@@ -196241,16 +197005,40 @@ class UniswapAdapter {
|
|
|
196241
197005
|
throw new Error("No output amount in quote");
|
|
196242
197006
|
return Number(outputAmount) / 10 ** tokenOutDecimals;
|
|
196243
197007
|
}
|
|
196244
|
-
async getCandles(
|
|
196245
|
-
|
|
197008
|
+
async getCandles(symbol16, interval, limit) {
|
|
197009
|
+
if (!this.subgraph?.isAvailable())
|
|
197010
|
+
return [];
|
|
197011
|
+
try {
|
|
197012
|
+
return await this.subgraph.getCandles(symbol16, interval, limit ?? 50);
|
|
197013
|
+
} catch {
|
|
197014
|
+
return [];
|
|
197015
|
+
}
|
|
196246
197016
|
}
|
|
196247
197017
|
async get24hrTickers() {
|
|
196248
|
-
|
|
197018
|
+
if (!this.subgraph?.isAvailable())
|
|
197019
|
+
return [];
|
|
197020
|
+
try {
|
|
197021
|
+
return await this.subgraph.get24hrTickers();
|
|
197022
|
+
} catch {
|
|
197023
|
+
return [];
|
|
197024
|
+
}
|
|
196249
197025
|
}
|
|
196250
|
-
async getTopSymbols(
|
|
196251
|
-
|
|
197026
|
+
async getTopSymbols(n) {
|
|
197027
|
+
if (!this.subgraph?.isAvailable()) {
|
|
197028
|
+
return ["ETHUSDC", "WBTCUSDC", "ARBUSDC", "LINKUSDC", "UNIUSDC"];
|
|
197029
|
+
}
|
|
197030
|
+
try {
|
|
197031
|
+
return await this.subgraph.getTopSymbols(n);
|
|
197032
|
+
} catch {
|
|
197033
|
+
return ["ETHUSDC", "WBTCUSDC", "ARBUSDC", "LINKUSDC", "UNIUSDC"];
|
|
197034
|
+
}
|
|
196252
197035
|
}
|
|
196253
197036
|
async getOrderBook(symbol16, _limit) {
|
|
197037
|
+
if (this.subgraph?.isAvailable()) {
|
|
197038
|
+
try {
|
|
197039
|
+
return await this.subgraph.getOrderBook(symbol16);
|
|
197040
|
+
} catch {}
|
|
197041
|
+
}
|
|
196254
197042
|
const price = await this.getPrice(symbol16);
|
|
196255
197043
|
const spread = price * 0.003;
|
|
196256
197044
|
return {
|
|
@@ -196260,6 +197048,11 @@ class UniswapAdapter {
|
|
|
196260
197048
|
};
|
|
196261
197049
|
}
|
|
196262
197050
|
async getBookTicker(symbol16) {
|
|
197051
|
+
if (this.subgraph?.isAvailable()) {
|
|
197052
|
+
try {
|
|
197053
|
+
return await this.subgraph.getBookTicker(symbol16);
|
|
197054
|
+
} catch {}
|
|
197055
|
+
}
|
|
196263
197056
|
const price = await this.getPrice(symbol16);
|
|
196264
197057
|
const spread = price * 0.003;
|
|
196265
197058
|
return {
|
|
@@ -196271,6 +197064,11 @@ class UniswapAdapter {
|
|
|
196271
197064
|
};
|
|
196272
197065
|
}
|
|
196273
197066
|
async getSpread(symbol16) {
|
|
197067
|
+
if (this.subgraph?.isAvailable()) {
|
|
197068
|
+
try {
|
|
197069
|
+
return await this.subgraph.getSpread(symbol16);
|
|
197070
|
+
} catch {}
|
|
197071
|
+
}
|
|
196274
197072
|
const price = await this.getPrice(symbol16);
|
|
196275
197073
|
const spread = price * 0.003;
|
|
196276
197074
|
return {
|
|
@@ -196281,6 +197079,11 @@ class UniswapAdapter {
|
|
|
196281
197079
|
};
|
|
196282
197080
|
}
|
|
196283
197081
|
async getAvgPrice(symbol16) {
|
|
197082
|
+
if (this.subgraph?.isAvailable()) {
|
|
197083
|
+
try {
|
|
197084
|
+
return await this.subgraph.getAvgPrice(symbol16);
|
|
197085
|
+
} catch {}
|
|
197086
|
+
}
|
|
196284
197087
|
const price = await this.getPrice(symbol16);
|
|
196285
197088
|
return { mins: 5, price };
|
|
196286
197089
|
}
|
|
@@ -196395,8 +197198,18 @@ class UniswapAdapter {
|
|
|
196395
197198
|
return false;
|
|
196396
197199
|
}
|
|
196397
197200
|
}
|
|
196398
|
-
async getTradeHistory(symbol16,
|
|
196399
|
-
|
|
197201
|
+
async getTradeHistory(symbol16, limit) {
|
|
197202
|
+
const local = this.localTrades.get(symbol16) || [];
|
|
197203
|
+
if (!this.subgraph?.isAvailable())
|
|
197204
|
+
return local;
|
|
197205
|
+
try {
|
|
197206
|
+
const onChain = await this.subgraph.getTradeHistory(symbol16, limit ?? 50);
|
|
197207
|
+
const localIds = new Set(local.map((t2) => t2.id));
|
|
197208
|
+
const deduped = onChain.filter((t2) => !localIds.has(t2.id));
|
|
197209
|
+
return [...local, ...deduped].slice(0, limit ?? 50);
|
|
197210
|
+
} catch {
|
|
197211
|
+
return local;
|
|
197212
|
+
}
|
|
196400
197213
|
}
|
|
196401
197214
|
async getOrderHistory(symbol16, _limit) {
|
|
196402
197215
|
return Array.from(this.localOrders.values()).filter((o) => o.symbol === symbol16);
|
|
@@ -196430,6 +197243,7 @@ class UniswapAdapter {
|
|
|
196430
197243
|
}
|
|
196431
197244
|
var init_uniswap2 = __esm(() => {
|
|
196432
197245
|
init_uniswap();
|
|
197246
|
+
init_subgraph();
|
|
196433
197247
|
init_types10();
|
|
196434
197248
|
});
|
|
196435
197249
|
|
|
@@ -196498,7 +197312,7 @@ var init_factory = __esm(() => {
|
|
|
196498
197312
|
if (!credentials.apiKey) {
|
|
196499
197313
|
throw new Error("Uniswap requires an API key from developers.uniswap.org");
|
|
196500
197314
|
}
|
|
196501
|
-
exchange = new UniswapAdapter(credentials.apiKey, credentials.walletPrivateKey || credentials.apiSecret, 1);
|
|
197315
|
+
exchange = new UniswapAdapter(credentials.apiKey, credentials.walletPrivateKey || credentials.apiSecret, 1, process.env.THEGRAPH_API_KEY);
|
|
196502
197316
|
break;
|
|
196503
197317
|
default:
|
|
196504
197318
|
throw new Error(`No adapter available for exchange: ${exchangeId}`);
|
|
@@ -1120715,6 +1121529,348 @@ ${formatted.join(`
|
|
|
1120715
1121529
|
};
|
|
1120716
1121530
|
});
|
|
1120717
1121531
|
|
|
1121532
|
+
// src/infra/agents/tools/uniswap-data.ts
|
|
1121533
|
+
function getSubgraph(execContext) {
|
|
1121534
|
+
const ctx = getGordonContext(execContext);
|
|
1121535
|
+
if (!ctx?.exchange)
|
|
1121536
|
+
return { error: "Exchange client not connected." };
|
|
1121537
|
+
if (ctx.exchange.exchangeId !== "uniswap")
|
|
1121538
|
+
return { error: "This tool is only available on Uniswap." };
|
|
1121539
|
+
const subgraph = ctx.exchange.subgraph;
|
|
1121540
|
+
if (!subgraph?.isAvailable())
|
|
1121541
|
+
return { error: "Uniswap subgraph not available. Set THEGRAPH_API_KEY." };
|
|
1121542
|
+
return { subgraph };
|
|
1121543
|
+
}
|
|
1121544
|
+
var getPoolTickLiquidityTool, getLiquidityEventsTool, getPoolFlashEventsTool, getLpPositionsTool, getProtocolOverviewTool, getFeeCollectionsTool, uniswapDataTools;
|
|
1121545
|
+
var init_uniswap_data = __esm(() => {
|
|
1121546
|
+
init_tools();
|
|
1121547
|
+
init_zod();
|
|
1121548
|
+
init_types8();
|
|
1121549
|
+
getPoolTickLiquidityTool = createTool({
|
|
1121550
|
+
id: "get_pool_tick_liquidity",
|
|
1121551
|
+
description: "Get real liquidity distribution around the current price for a Uniswap pool. " + "Shows actual bid/ask depth from on-chain tick data \u2014 much more accurate than TVL proxy. " + "Use for order book depth analysis, slippage estimation, and liquidity gap detection.",
|
|
1121552
|
+
inputSchema: exports_external.object({
|
|
1121553
|
+
symbol: exports_external.string().describe("Trading pair (e.g., 'ETHUSDC', 'UNIUSDC')"),
|
|
1121554
|
+
ticksPerSide: exports_external.number().min(1).max(50).default(20).describe("Number of tick spaces on each side of current price")
|
|
1121555
|
+
}),
|
|
1121556
|
+
outputSchema: exports_external.object({
|
|
1121557
|
+
symbol: exports_external.string().optional(),
|
|
1121558
|
+
currentTick: exports_external.number().optional(),
|
|
1121559
|
+
tickCount: exports_external.number().optional(),
|
|
1121560
|
+
ticks: exports_external.array(exports_external.object({
|
|
1121561
|
+
tickIdx: exports_external.number(),
|
|
1121562
|
+
price: exports_external.number(),
|
|
1121563
|
+
liquidityNet: exports_external.number(),
|
|
1121564
|
+
liquidityGross: exports_external.number(),
|
|
1121565
|
+
volumeUSD: exports_external.number()
|
|
1121566
|
+
})).optional(),
|
|
1121567
|
+
error: exports_external.string().optional()
|
|
1121568
|
+
}),
|
|
1121569
|
+
execute: async ({ symbol: symbol16, ticksPerSide }, execContext) => {
|
|
1121570
|
+
const result = getSubgraph(execContext);
|
|
1121571
|
+
if ("error" in result)
|
|
1121572
|
+
return result;
|
|
1121573
|
+
try {
|
|
1121574
|
+
const pool = await result.subgraph.resolvePool(symbol16);
|
|
1121575
|
+
const ticks = await result.subgraph.getTickLiquidity(symbol16, ticksPerSide);
|
|
1121576
|
+
return {
|
|
1121577
|
+
symbol: symbol16,
|
|
1121578
|
+
currentTick: parseInt(pool.pool.tick, 10),
|
|
1121579
|
+
tickCount: ticks.length,
|
|
1121580
|
+
ticks: ticks.map((t3) => ({
|
|
1121581
|
+
tickIdx: parseInt(t3.tickIdx, 10),
|
|
1121582
|
+
price: parseFloat(pool.isInverted ? t3.price1 : t3.price0),
|
|
1121583
|
+
liquidityNet: parseFloat(t3.liquidityNet),
|
|
1121584
|
+
liquidityGross: parseFloat(t3.liquidityGross),
|
|
1121585
|
+
volumeUSD: parseFloat(t3.volumeUSD)
|
|
1121586
|
+
}))
|
|
1121587
|
+
};
|
|
1121588
|
+
} catch (error48) {
|
|
1121589
|
+
return { error: `Failed to get tick liquidity: ${error48.message}` };
|
|
1121590
|
+
}
|
|
1121591
|
+
}
|
|
1121592
|
+
});
|
|
1121593
|
+
getLiquidityEventsTool = createTool({
|
|
1121594
|
+
id: "get_liquidity_events",
|
|
1121595
|
+
description: "Get recent liquidity additions (mints) and removals (burns) for a Uniswap pool. " + "Large mints signal confidence; large burns may signal exit. " + "Use for detecting smart money flows, liquidity rug risk, and LP sentiment.",
|
|
1121596
|
+
inputSchema: exports_external.object({
|
|
1121597
|
+
symbol: exports_external.string().describe("Trading pair (e.g., 'ETHUSDC', 'UNIUSDC')"),
|
|
1121598
|
+
limit: exports_external.number().min(1).max(100).default(20).describe("Number of events per type")
|
|
1121599
|
+
}),
|
|
1121600
|
+
outputSchema: exports_external.object({
|
|
1121601
|
+
symbol: exports_external.string().optional(),
|
|
1121602
|
+
mints: exports_external.array(exports_external.object({
|
|
1121603
|
+
timestamp: exports_external.number(),
|
|
1121604
|
+
amountUSD: exports_external.number(),
|
|
1121605
|
+
amount0: exports_external.number(),
|
|
1121606
|
+
amount1: exports_external.number(),
|
|
1121607
|
+
owner: exports_external.string(),
|
|
1121608
|
+
tickLower: exports_external.number(),
|
|
1121609
|
+
tickUpper: exports_external.number()
|
|
1121610
|
+
})).optional(),
|
|
1121611
|
+
burns: exports_external.array(exports_external.object({
|
|
1121612
|
+
timestamp: exports_external.number(),
|
|
1121613
|
+
amountUSD: exports_external.number(),
|
|
1121614
|
+
amount0: exports_external.number(),
|
|
1121615
|
+
amount1: exports_external.number(),
|
|
1121616
|
+
owner: exports_external.string(),
|
|
1121617
|
+
tickLower: exports_external.number(),
|
|
1121618
|
+
tickUpper: exports_external.number()
|
|
1121619
|
+
})).optional(),
|
|
1121620
|
+
netFlowUSD: exports_external.number().optional(),
|
|
1121621
|
+
error: exports_external.string().optional()
|
|
1121622
|
+
}),
|
|
1121623
|
+
execute: async ({ symbol: symbol16, limit }, execContext) => {
|
|
1121624
|
+
const result = getSubgraph(execContext);
|
|
1121625
|
+
if ("error" in result)
|
|
1121626
|
+
return result;
|
|
1121627
|
+
try {
|
|
1121628
|
+
const [mints, burns] = await Promise.all([
|
|
1121629
|
+
result.subgraph.getMints(symbol16, limit),
|
|
1121630
|
+
result.subgraph.getBurns(symbol16, limit)
|
|
1121631
|
+
]);
|
|
1121632
|
+
const mintFlow = mints.reduce((sum, m) => sum + parseFloat(m.amountUSD), 0);
|
|
1121633
|
+
const burnFlow = burns.reduce((sum, b) => sum + parseFloat(b.amountUSD), 0);
|
|
1121634
|
+
return {
|
|
1121635
|
+
symbol: symbol16,
|
|
1121636
|
+
mints: mints.map((m) => ({
|
|
1121637
|
+
timestamp: parseInt(m.timestamp, 10) * 1000,
|
|
1121638
|
+
amountUSD: parseFloat(m.amountUSD),
|
|
1121639
|
+
amount0: parseFloat(m.amount0),
|
|
1121640
|
+
amount1: parseFloat(m.amount1),
|
|
1121641
|
+
owner: m.owner,
|
|
1121642
|
+
tickLower: parseInt(m.tickLower, 10),
|
|
1121643
|
+
tickUpper: parseInt(m.tickUpper, 10)
|
|
1121644
|
+
})),
|
|
1121645
|
+
burns: burns.map((b) => ({
|
|
1121646
|
+
timestamp: parseInt(b.timestamp, 10) * 1000,
|
|
1121647
|
+
amountUSD: parseFloat(b.amountUSD),
|
|
1121648
|
+
amount0: parseFloat(b.amount0),
|
|
1121649
|
+
amount1: parseFloat(b.amount1),
|
|
1121650
|
+
owner: b.owner,
|
|
1121651
|
+
tickLower: parseInt(b.tickLower, 10),
|
|
1121652
|
+
tickUpper: parseInt(b.tickUpper, 10)
|
|
1121653
|
+
})),
|
|
1121654
|
+
netFlowUSD: mintFlow - burnFlow
|
|
1121655
|
+
};
|
|
1121656
|
+
} catch (error48) {
|
|
1121657
|
+
return { error: `Failed to get liquidity events: ${error48.message}` };
|
|
1121658
|
+
}
|
|
1121659
|
+
}
|
|
1121660
|
+
});
|
|
1121661
|
+
getPoolFlashEventsTool = createTool({
|
|
1121662
|
+
id: "get_pool_flash_events",
|
|
1121663
|
+
description: "Get recent flash loan events for a Uniswap pool. " + "Flash loans can indicate arbitrage activity or potential manipulation. " + "Large or frequent flash loans around a token may signal price instability.",
|
|
1121664
|
+
inputSchema: exports_external.object({
|
|
1121665
|
+
symbol: exports_external.string().describe("Trading pair (e.g., 'ETHUSDC')"),
|
|
1121666
|
+
limit: exports_external.number().min(1).max(100).default(20).describe("Number of events to return")
|
|
1121667
|
+
}),
|
|
1121668
|
+
outputSchema: exports_external.object({
|
|
1121669
|
+
symbol: exports_external.string().optional(),
|
|
1121670
|
+
count: exports_external.number().optional(),
|
|
1121671
|
+
totalAmountUSD: exports_external.number().optional(),
|
|
1121672
|
+
events: exports_external.array(exports_external.object({
|
|
1121673
|
+
timestamp: exports_external.number(),
|
|
1121674
|
+
amountUSD: exports_external.number(),
|
|
1121675
|
+
amount0: exports_external.number(),
|
|
1121676
|
+
amount1: exports_external.number(),
|
|
1121677
|
+
amount0Paid: exports_external.number(),
|
|
1121678
|
+
amount1Paid: exports_external.number(),
|
|
1121679
|
+
sender: exports_external.string()
|
|
1121680
|
+
})).optional(),
|
|
1121681
|
+
error: exports_external.string().optional()
|
|
1121682
|
+
}),
|
|
1121683
|
+
execute: async ({ symbol: symbol16, limit }, execContext) => {
|
|
1121684
|
+
const result = getSubgraph(execContext);
|
|
1121685
|
+
if ("error" in result)
|
|
1121686
|
+
return result;
|
|
1121687
|
+
try {
|
|
1121688
|
+
const flashes = await result.subgraph.getFlashLoans(symbol16, limit);
|
|
1121689
|
+
const totalUSD = flashes.reduce((sum, f2) => sum + parseFloat(f2.amountUSD), 0);
|
|
1121690
|
+
return {
|
|
1121691
|
+
symbol: symbol16,
|
|
1121692
|
+
count: flashes.length,
|
|
1121693
|
+
totalAmountUSD: totalUSD,
|
|
1121694
|
+
events: flashes.map((f2) => ({
|
|
1121695
|
+
timestamp: parseInt(f2.timestamp, 10) * 1000,
|
|
1121696
|
+
amountUSD: parseFloat(f2.amountUSD),
|
|
1121697
|
+
amount0: parseFloat(f2.amount0),
|
|
1121698
|
+
amount1: parseFloat(f2.amount1),
|
|
1121699
|
+
amount0Paid: parseFloat(f2.amount0Paid),
|
|
1121700
|
+
amount1Paid: parseFloat(f2.amount1Paid),
|
|
1121701
|
+
sender: f2.sender
|
|
1121702
|
+
}))
|
|
1121703
|
+
};
|
|
1121704
|
+
} catch (error48) {
|
|
1121705
|
+
return { error: `Failed to get flash events: ${error48.message}` };
|
|
1121706
|
+
}
|
|
1121707
|
+
}
|
|
1121708
|
+
});
|
|
1121709
|
+
getLpPositionsTool = createTool({
|
|
1121710
|
+
id: "get_lp_positions",
|
|
1121711
|
+
description: "Get active Uniswap V3 LP positions for a wallet address. " + "Shows pools, price ranges, liquidity amounts, deposited/withdrawn tokens, and collected fees. " + "Use for portfolio monitoring of LP positions.",
|
|
1121712
|
+
inputSchema: exports_external.object({
|
|
1121713
|
+
owner: exports_external.string().describe("Wallet address (0x...)"),
|
|
1121714
|
+
limit: exports_external.number().min(1).max(100).default(20).describe("Max positions to return")
|
|
1121715
|
+
}),
|
|
1121716
|
+
outputSchema: exports_external.object({
|
|
1121717
|
+
owner: exports_external.string().optional(),
|
|
1121718
|
+
positionCount: exports_external.number().optional(),
|
|
1121719
|
+
positions: exports_external.array(exports_external.object({
|
|
1121720
|
+
id: exports_external.string(),
|
|
1121721
|
+
pool: exports_external.string(),
|
|
1121722
|
+
token0: exports_external.string(),
|
|
1121723
|
+
token1: exports_external.string(),
|
|
1121724
|
+
tickLower: exports_external.number(),
|
|
1121725
|
+
tickUpper: exports_external.number(),
|
|
1121726
|
+
liquidity: exports_external.string(),
|
|
1121727
|
+
depositedToken0: exports_external.number(),
|
|
1121728
|
+
depositedToken1: exports_external.number(),
|
|
1121729
|
+
withdrawnToken0: exports_external.number(),
|
|
1121730
|
+
withdrawnToken1: exports_external.number(),
|
|
1121731
|
+
collectedFeesToken0: exports_external.number(),
|
|
1121732
|
+
collectedFeesToken1: exports_external.number()
|
|
1121733
|
+
})).optional(),
|
|
1121734
|
+
error: exports_external.string().optional()
|
|
1121735
|
+
}),
|
|
1121736
|
+
execute: async ({ owner, limit }, execContext) => {
|
|
1121737
|
+
const result = getSubgraph(execContext);
|
|
1121738
|
+
if ("error" in result)
|
|
1121739
|
+
return result;
|
|
1121740
|
+
try {
|
|
1121741
|
+
const positions = await result.subgraph.getPositions(owner, limit);
|
|
1121742
|
+
return {
|
|
1121743
|
+
owner,
|
|
1121744
|
+
positionCount: positions.length,
|
|
1121745
|
+
positions: positions.map((p) => ({
|
|
1121746
|
+
id: p.id,
|
|
1121747
|
+
pool: p.pool.id,
|
|
1121748
|
+
token0: `${p.token0.symbol} (${p.token0.id.slice(0, 10)}...)`,
|
|
1121749
|
+
token1: `${p.token1.symbol} (${p.token1.id.slice(0, 10)}...)`,
|
|
1121750
|
+
tickLower: parseInt(p.tickLower.tickIdx, 10),
|
|
1121751
|
+
tickUpper: parseInt(p.tickUpper.tickIdx, 10),
|
|
1121752
|
+
liquidity: p.liquidity,
|
|
1121753
|
+
depositedToken0: parseFloat(p.depositedToken0),
|
|
1121754
|
+
depositedToken1: parseFloat(p.depositedToken1),
|
|
1121755
|
+
withdrawnToken0: parseFloat(p.withdrawnToken0),
|
|
1121756
|
+
withdrawnToken1: parseFloat(p.withdrawnToken1),
|
|
1121757
|
+
collectedFeesToken0: parseFloat(p.collectedFeesToken0),
|
|
1121758
|
+
collectedFeesToken1: parseFloat(p.collectedFeesToken1)
|
|
1121759
|
+
}))
|
|
1121760
|
+
};
|
|
1121761
|
+
} catch (error48) {
|
|
1121762
|
+
return { error: `Failed to get LP positions: ${error48.message}` };
|
|
1121763
|
+
}
|
|
1121764
|
+
}
|
|
1121765
|
+
});
|
|
1121766
|
+
getProtocolOverviewTool = createTool({
|
|
1121767
|
+
id: "get_uniswap_protocol_overview",
|
|
1121768
|
+
description: "Get Uniswap V3 protocol-wide metrics: ETH/USD price, total pools, total volume, " + "total fees, TVL, and recent daily data. Use for protocol health assessment, " + "DeFi market overview, and macro trend analysis.",
|
|
1121769
|
+
inputSchema: exports_external.object({
|
|
1121770
|
+
days: exports_external.number().min(1).max(90).default(7).describe("Number of days of daily data to include")
|
|
1121771
|
+
}),
|
|
1121772
|
+
outputSchema: exports_external.object({
|
|
1121773
|
+
ethPriceUSD: exports_external.number().optional(),
|
|
1121774
|
+
factory: exports_external.object({
|
|
1121775
|
+
poolCount: exports_external.number(),
|
|
1121776
|
+
totalVolumeUSD: exports_external.number(),
|
|
1121777
|
+
totalFeesUSD: exports_external.number(),
|
|
1121778
|
+
totalValueLockedUSD: exports_external.number()
|
|
1121779
|
+
}).optional(),
|
|
1121780
|
+
dailyData: exports_external.array(exports_external.object({
|
|
1121781
|
+
date: exports_external.number(),
|
|
1121782
|
+
volumeUSD: exports_external.number(),
|
|
1121783
|
+
feesUSD: exports_external.number(),
|
|
1121784
|
+
tvlUSD: exports_external.number(),
|
|
1121785
|
+
txCount: exports_external.number()
|
|
1121786
|
+
})).optional(),
|
|
1121787
|
+
error: exports_external.string().optional()
|
|
1121788
|
+
}),
|
|
1121789
|
+
execute: async ({ days }, execContext) => {
|
|
1121790
|
+
const result = getSubgraph(execContext);
|
|
1121791
|
+
if ("error" in result)
|
|
1121792
|
+
return result;
|
|
1121793
|
+
try {
|
|
1121794
|
+
const [ethPrice, factory6, dayData] = await Promise.all([
|
|
1121795
|
+
result.subgraph.getEthPrice(),
|
|
1121796
|
+
result.subgraph.getFactory(),
|
|
1121797
|
+
result.subgraph.getProtocolDayData(days)
|
|
1121798
|
+
]);
|
|
1121799
|
+
return {
|
|
1121800
|
+
ethPriceUSD: ethPrice,
|
|
1121801
|
+
factory: factory6 ? {
|
|
1121802
|
+
poolCount: parseInt(factory6.poolCount, 10),
|
|
1121803
|
+
totalVolumeUSD: parseFloat(factory6.totalVolumeUSD),
|
|
1121804
|
+
totalFeesUSD: parseFloat(factory6.totalFeesUSD),
|
|
1121805
|
+
totalValueLockedUSD: parseFloat(factory6.totalValueLockedUSD)
|
|
1121806
|
+
} : undefined,
|
|
1121807
|
+
dailyData: dayData.map((d) => ({
|
|
1121808
|
+
date: d.date * 1000,
|
|
1121809
|
+
volumeUSD: parseFloat(d.volumeUSD),
|
|
1121810
|
+
feesUSD: parseFloat(d.feesUSD),
|
|
1121811
|
+
tvlUSD: parseFloat(d.tvlUSD),
|
|
1121812
|
+
txCount: parseInt(d.txCount, 10)
|
|
1121813
|
+
}))
|
|
1121814
|
+
};
|
|
1121815
|
+
} catch (error48) {
|
|
1121816
|
+
return { error: `Failed to get protocol overview: ${error48.message}` };
|
|
1121817
|
+
}
|
|
1121818
|
+
}
|
|
1121819
|
+
});
|
|
1121820
|
+
getFeeCollectionsTool = createTool({
|
|
1121821
|
+
id: "get_fee_collections",
|
|
1121822
|
+
description: "Get recent fee collection events for a Uniswap pool. " + "Shows when LPs harvest their earned fees. Useful for tracking LP profitability " + "and identifying wallets actively managing their positions.",
|
|
1121823
|
+
inputSchema: exports_external.object({
|
|
1121824
|
+
symbol: exports_external.string().describe("Trading pair (e.g., 'ETHUSDC')"),
|
|
1121825
|
+
limit: exports_external.number().min(1).max(100).default(20).describe("Number of events to return")
|
|
1121826
|
+
}),
|
|
1121827
|
+
outputSchema: exports_external.object({
|
|
1121828
|
+
symbol: exports_external.string().optional(),
|
|
1121829
|
+
count: exports_external.number().optional(),
|
|
1121830
|
+
totalFeesUSD: exports_external.number().optional(),
|
|
1121831
|
+
events: exports_external.array(exports_external.object({
|
|
1121832
|
+
timestamp: exports_external.number(),
|
|
1121833
|
+
amountUSD: exports_external.number(),
|
|
1121834
|
+
amount0: exports_external.number(),
|
|
1121835
|
+
amount1: exports_external.number(),
|
|
1121836
|
+
owner: exports_external.string()
|
|
1121837
|
+
})).optional(),
|
|
1121838
|
+
error: exports_external.string().optional()
|
|
1121839
|
+
}),
|
|
1121840
|
+
execute: async ({ symbol: symbol16, limit }, execContext) => {
|
|
1121841
|
+
const result = getSubgraph(execContext);
|
|
1121842
|
+
if ("error" in result)
|
|
1121843
|
+
return result;
|
|
1121844
|
+
try {
|
|
1121845
|
+
const collects = await result.subgraph.getCollects(symbol16, limit);
|
|
1121846
|
+
const totalUSD = collects.reduce((sum, c) => sum + parseFloat(c.amountUSD), 0);
|
|
1121847
|
+
return {
|
|
1121848
|
+
symbol: symbol16,
|
|
1121849
|
+
count: collects.length,
|
|
1121850
|
+
totalFeesUSD: totalUSD,
|
|
1121851
|
+
events: collects.map((c) => ({
|
|
1121852
|
+
timestamp: parseInt(c.timestamp, 10) * 1000,
|
|
1121853
|
+
amountUSD: parseFloat(c.amountUSD),
|
|
1121854
|
+
amount0: parseFloat(c.amount0),
|
|
1121855
|
+
amount1: parseFloat(c.amount1),
|
|
1121856
|
+
owner: c.owner
|
|
1121857
|
+
}))
|
|
1121858
|
+
};
|
|
1121859
|
+
} catch (error48) {
|
|
1121860
|
+
return { error: `Failed to get fee collections: ${error48.message}` };
|
|
1121861
|
+
}
|
|
1121862
|
+
}
|
|
1121863
|
+
});
|
|
1121864
|
+
uniswapDataTools = {
|
|
1121865
|
+
get_pool_tick_liquidity: getPoolTickLiquidityTool,
|
|
1121866
|
+
get_liquidity_events: getLiquidityEventsTool,
|
|
1121867
|
+
get_pool_flash_events: getPoolFlashEventsTool,
|
|
1121868
|
+
get_lp_positions: getLpPositionsTool,
|
|
1121869
|
+
get_uniswap_protocol_overview: getProtocolOverviewTool,
|
|
1121870
|
+
get_fee_collections: getFeeCollectionsTool
|
|
1121871
|
+
};
|
|
1121872
|
+
});
|
|
1121873
|
+
|
|
1120718
1121874
|
// src/infra/agents/tools/position-tracking.ts
|
|
1120719
1121875
|
async function getManager() {
|
|
1120720
1121876
|
return getPositionManager(getEventBus());
|
|
@@ -1127074,6 +1128230,7 @@ var init_tools3 = __esm(async () => {
|
|
|
1127074
1128230
|
init_agentkit_defi();
|
|
1127075
1128231
|
init_base_signals();
|
|
1127076
1128232
|
init_base_indexers();
|
|
1128233
|
+
init_uniswap_data();
|
|
1127077
1128234
|
init_position_tracking();
|
|
1127078
1128235
|
init_risk_gate();
|
|
1127079
1128236
|
init_memory_tools();
|
|
@@ -1127125,6 +1128282,7 @@ var init_tools3 = __esm(async () => {
|
|
|
1127125
1128282
|
init_agentkit_defi();
|
|
1127126
1128283
|
init_base_signals();
|
|
1127127
1128284
|
init_base_indexers();
|
|
1128285
|
+
init_uniswap_data();
|
|
1127128
1128286
|
init_position_tracking();
|
|
1127129
1128287
|
init_risk_gate();
|
|
1127130
1128288
|
init_memory_tools();
|
|
@@ -1127180,6 +1128338,7 @@ var init_tools3 = __esm(async () => {
|
|
|
1127180
1128338
|
...agentKitDefiTools,
|
|
1127181
1128339
|
...baseSignalTools,
|
|
1127182
1128340
|
...baseIndexerTools,
|
|
1128341
|
+
...uniswapDataTools,
|
|
1127183
1128342
|
...multiModalChartTools,
|
|
1127184
1128343
|
...evalTools,
|
|
1127185
1128344
|
...positionTrackingTools,
|
|
@@ -1127226,6 +1128385,7 @@ var init_tools3 = __esm(async () => {
|
|
|
1127226
1128385
|
agentKitDefi: Object.keys(agentKitDefiTools).length,
|
|
1127227
1128386
|
baseSignals: Object.keys(baseSignalTools).length,
|
|
1127228
1128387
|
baseIndexers: Object.keys(baseIndexerTools).length,
|
|
1128388
|
+
uniswapData: Object.keys(uniswapDataTools).length,
|
|
1127229
1128389
|
multiModalCharts: Object.keys(multiModalChartTools).length,
|
|
1127230
1128390
|
evals: Object.keys(evalTools).length,
|
|
1127231
1128391
|
positionTracking: Object.keys(positionTrackingTools).length,
|
|
@@ -1150499,6 +1151659,8 @@ function getScannerAgent() {
|
|
|
1150499
1151659
|
defillama_search_protocols: instrumentedAgentKitDefiTools.defillama_search_protocols,
|
|
1150500
1151660
|
indexer_top_pools: instrumentedBaseIndexerTools.indexer_top_pools,
|
|
1150501
1151661
|
indexer_aerodrome_pools: instrumentedBaseIndexerTools.indexer_aerodrome_pools,
|
|
1151662
|
+
get_uniswap_protocol_overview: instrumentedUniswapDataTools.get_uniswap_protocol_overview,
|
|
1151663
|
+
get_liquidity_events: instrumentedUniswapDataTools.get_liquidity_events,
|
|
1150502
1151664
|
report_setup: instrumentedPositionTrackingTools.report_setup,
|
|
1150503
1151665
|
...instrumentedMemoryTools,
|
|
1150504
1151666
|
...instrumentedPlaybookTools,
|
|
@@ -1150542,6 +1151704,11 @@ function getAnalystAgent() {
|
|
|
1150542
1151704
|
defillama_get_protocol: instrumentedAgentKitDefiTools.defillama_get_protocol,
|
|
1150543
1151705
|
defillama_get_token_prices: instrumentedAgentKitDefiTools.defillama_get_token_prices,
|
|
1150544
1151706
|
indexer_pool_stats: instrumentedBaseIndexerTools.indexer_pool_stats,
|
|
1151707
|
+
get_pool_tick_liquidity: instrumentedUniswapDataTools.get_pool_tick_liquidity,
|
|
1151708
|
+
get_liquidity_events: instrumentedUniswapDataTools.get_liquidity_events,
|
|
1151709
|
+
get_pool_flash_events: instrumentedUniswapDataTools.get_pool_flash_events,
|
|
1151710
|
+
get_fee_collections: instrumentedUniswapDataTools.get_fee_collections,
|
|
1151711
|
+
get_uniswap_protocol_overview: instrumentedUniswapDataTools.get_uniswap_protocol_overview,
|
|
1150545
1151712
|
track_base_wallet: instrumentedBaseSignalTools.track_base_wallet,
|
|
1150546
1151713
|
get_base_token_holders: instrumentedBaseSignalTools.get_base_token_holders,
|
|
1150547
1151714
|
get_base_dex_pairs: instrumentedBaseSignalTools.get_base_dex_pairs,
|
|
@@ -1150684,6 +1151851,8 @@ function getMonitorAgent() {
|
|
|
1150684
1151851
|
agentkit_get_wallet: instrumentedAgentKitOnchainTools.agentkit_get_wallet,
|
|
1150685
1151852
|
agentkit_get_balance: instrumentedAgentKitOnchainTools.agentkit_get_balance,
|
|
1150686
1151853
|
agentkit_erc20_balance: instrumentedAgentKitOnchainTools.agentkit_erc20_balance,
|
|
1151854
|
+
get_lp_positions: instrumentedUniswapDataTools.get_lp_positions,
|
|
1151855
|
+
get_fee_collections: instrumentedUniswapDataTools.get_fee_collections,
|
|
1150687
1151856
|
...instrumentedSharedContextTools,
|
|
1150688
1151857
|
record_trade_outcome: instrumentedEvalTools.record_trade_outcome,
|
|
1150689
1151858
|
get_performance_report: instrumentedEvalTools.get_performance_report,
|
|
@@ -1150796,7 +1151965,7 @@ function resetAgents() {
|
|
|
1150796
1151965
|
_agents = {};
|
|
1150797
1151966
|
_subAgentMemory = null;
|
|
1150798
1151967
|
}
|
|
1150799
|
-
var DEFAULT_MEMORY_CONFIG, _memoryConfig, instrumentedIndicatorTools, instrumentedExplainTools, instrumentedMarketTools, instrumentedPositionTools, instrumentedSchedulerTools, instrumentedSystemTools, instrumentedEarnTools, instrumentedChartTools, instrumentedOrderbookTools, instrumentedWalletTools, instrumentedDiscoveryTools, instrumentedHistoryTools, instrumentedAccountTools, instrumentedTradingTools, instrumentedMarketAnalysisTools, instrumentedLiquidationIntelligenceTools, instrumentedRiskManagementTools, instrumentedStrategyTools, instrumentedMetricsTools, instrumentedCompositionTools, instrumentedBacktestTools, instrumentedSharedContextTools, instrumentedParallelAnalysisTools, instrumentedStrategyGenerationTools, instrumentedMultiModalChartTools, instrumentedMarketDataTools, instrumentedPairAnalysisTools, instrumentedAutonomousTools, instrumentedBaseOnchainTools, instrumentedAgentKitOnchainTools, instrumentedAgentKitDefiTools, instrumentedBaseSignalTools, instrumentedBaseIndexerTools, instrumentedEvalTools, instrumentedPositionTrackingTools, instrumentedMemoryTools, instrumentedPlaybookTools, instrumentedPlaybookBacktestTools, instrumentedAuditTools, instrumentedProtocolTools, instrumentedRegimeTools, instrumentedRuntimeTools, instrumentedAdvancedTools, instrumentedCheckRiskTool, WORKING_MEMORY_TEMPLATE = `
|
|
1151968
|
+
var DEFAULT_MEMORY_CONFIG, _memoryConfig, instrumentedIndicatorTools, instrumentedExplainTools, instrumentedMarketTools, instrumentedPositionTools, instrumentedSchedulerTools, instrumentedSystemTools, instrumentedEarnTools, instrumentedChartTools, instrumentedOrderbookTools, instrumentedWalletTools, instrumentedDiscoveryTools, instrumentedHistoryTools, instrumentedAccountTools, instrumentedTradingTools, instrumentedMarketAnalysisTools, instrumentedLiquidationIntelligenceTools, instrumentedRiskManagementTools, instrumentedStrategyTools, instrumentedMetricsTools, instrumentedCompositionTools, instrumentedBacktestTools, instrumentedSharedContextTools, instrumentedParallelAnalysisTools, instrumentedStrategyGenerationTools, instrumentedMultiModalChartTools, instrumentedMarketDataTools, instrumentedPairAnalysisTools, instrumentedAutonomousTools, instrumentedBaseOnchainTools, instrumentedAgentKitOnchainTools, instrumentedAgentKitDefiTools, instrumentedBaseSignalTools, instrumentedBaseIndexerTools, instrumentedUniswapDataTools, instrumentedEvalTools, instrumentedPositionTrackingTools, instrumentedMemoryTools, instrumentedPlaybookTools, instrumentedPlaybookBacktestTools, instrumentedAuditTools, instrumentedProtocolTools, instrumentedRegimeTools, instrumentedRuntimeTools, instrumentedAdvancedTools, instrumentedCheckRiskTool, WORKING_MEMORY_TEMPLATE = `
|
|
1150800
1151969
|
# Trader Profile
|
|
1150801
1151970
|
|
|
1150802
1151971
|
## Personal Info
|
|
@@ -1151443,6 +1152612,7 @@ var init_agents = __esm(async () => {
|
|
|
1151443
1152612
|
instrumentedAgentKitDefiTools = withToolsMetrics(agentKitDefiTools);
|
|
1151444
1152613
|
instrumentedBaseSignalTools = withToolsMetrics(baseSignalTools);
|
|
1151445
1152614
|
instrumentedBaseIndexerTools = withToolsMetrics(baseIndexerTools);
|
|
1152615
|
+
instrumentedUniswapDataTools = withToolsMetrics(uniswapDataTools);
|
|
1151446
1152616
|
instrumentedEvalTools = withToolsMetrics(evalTools);
|
|
1151447
1152617
|
instrumentedPositionTrackingTools = withToolsMetrics(positionTrackingTools);
|
|
1151448
1152618
|
instrumentedMemoryTools = withToolsMetrics(memoryTools);
|
|
@@ -1153279,6 +1154449,12 @@ var init_orchestrator = __esm(async () => {
|
|
|
1153279
1154449
|
indexer_top_pools: "Scanner",
|
|
1153280
1154450
|
indexer_pool_stats: "Analyst",
|
|
1153281
1154451
|
indexer_aerodrome_pools: "Scanner",
|
|
1154452
|
+
get_pool_tick_liquidity: "Analyst",
|
|
1154453
|
+
get_liquidity_events: "Scanner",
|
|
1154454
|
+
get_pool_flash_events: "Analyst",
|
|
1154455
|
+
get_lp_positions: "Monitor",
|
|
1154456
|
+
get_uniswap_protocol_overview: "Scanner",
|
|
1154457
|
+
get_fee_collections: "Monitor",
|
|
1153282
1154458
|
scan_base_whale_transfers: "Scanner",
|
|
1153283
1154459
|
scan_base_volume_spikes: "Scanner",
|
|
1153284
1154460
|
scan_base_new_tokens: "Scanner",
|
|
@@ -1162414,7 +1163590,7 @@ var import_react64 = __toESM(require_react(), 1);
|
|
|
1162414
1163590
|
// package.json
|
|
1162415
1163591
|
var package_default2 = {
|
|
1162416
1163592
|
name: "@general-liquidity/gordon-cli",
|
|
1162417
|
-
version: "0.75.
|
|
1163593
|
+
version: "0.75.5",
|
|
1162418
1163594
|
description: "The Frontier Trading Agent",
|
|
1162419
1163595
|
author: "General Liquidity, Inc.",
|
|
1162420
1163596
|
license: "MIT",
|