@exagent/agent 0.1.29 → 0.1.31
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/chunk-27UBREN6.mjs +5536 -0
- package/dist/chunk-4NASRDHJ.mjs +5536 -0
- package/dist/chunk-IMJPVALR.mjs +5477 -0
- package/dist/cli.js +115 -20
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +115 -20
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -118,6 +118,7 @@ var TOKEN_DECIMALS = {
|
|
|
118
118
|
// SKI
|
|
119
119
|
};
|
|
120
120
|
var decimalsCache = {};
|
|
121
|
+
var symbolCache = {};
|
|
121
122
|
function getTokenDecimals(address) {
|
|
122
123
|
const key = address.toLowerCase();
|
|
123
124
|
const known = TOKEN_DECIMALS[key];
|
|
@@ -127,26 +128,43 @@ function getTokenDecimals(address) {
|
|
|
127
128
|
console.warn(`Unknown token decimals for ${address}, defaulting to 18. Call fetchTokenDecimals() first for accuracy.`);
|
|
128
129
|
return 18;
|
|
129
130
|
}
|
|
131
|
+
function getTokenSymbol(address) {
|
|
132
|
+
return symbolCache[address.toLowerCase()];
|
|
133
|
+
}
|
|
130
134
|
async function fetchTokenDecimals(client, address) {
|
|
131
135
|
const key = address.toLowerCase();
|
|
132
136
|
const known = TOKEN_DECIMALS[key];
|
|
133
137
|
if (known !== void 0) return known;
|
|
134
138
|
const cached = decimalsCache[key];
|
|
135
139
|
if (cached !== void 0) return cached;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
140
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
141
|
+
try {
|
|
142
|
+
const [decimals, symbol] = await Promise.all([
|
|
143
|
+
client.readContract({
|
|
144
|
+
address,
|
|
145
|
+
abi: import_viem.erc20Abi,
|
|
146
|
+
functionName: "decimals"
|
|
147
|
+
}),
|
|
148
|
+
client.readContract({
|
|
149
|
+
address,
|
|
150
|
+
abi: import_viem.erc20Abi,
|
|
151
|
+
functionName: "symbol"
|
|
152
|
+
}).catch(() => void 0)
|
|
153
|
+
// symbol is optional — some tokens don't have it
|
|
154
|
+
]);
|
|
155
|
+
const result = Number(decimals);
|
|
156
|
+
decimalsCache[key] = result;
|
|
157
|
+
if (symbol) symbolCache[key] = String(symbol);
|
|
158
|
+
return result;
|
|
159
|
+
} catch {
|
|
160
|
+
if (attempt === 0) {
|
|
161
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
149
164
|
}
|
|
165
|
+
console.warn(`Failed to fetch decimals for ${address} after 2 attempts, defaulting to 18`);
|
|
166
|
+
decimalsCache[key] = 18;
|
|
167
|
+
return 18;
|
|
150
168
|
}
|
|
151
169
|
var TOKEN_TO_COINGECKO = {
|
|
152
170
|
[NATIVE_ETH.toLowerCase()]: "ethereum",
|
|
@@ -359,6 +377,46 @@ var MarketDataService = class {
|
|
|
359
377
|
} catch {
|
|
360
378
|
}
|
|
361
379
|
}
|
|
380
|
+
const stillMissing = tokenAddresses.filter(
|
|
381
|
+
(addr) => !prices[addr.toLowerCase()]
|
|
382
|
+
);
|
|
383
|
+
if (stillMissing.length > 0) {
|
|
384
|
+
const batches = [];
|
|
385
|
+
for (let i = 0; i < stillMissing.length; i += 30) {
|
|
386
|
+
batches.push(stillMissing.slice(i, i + 30));
|
|
387
|
+
}
|
|
388
|
+
for (const batch of batches) {
|
|
389
|
+
try {
|
|
390
|
+
const addrs = batch.join(",");
|
|
391
|
+
const dsResponse = await fetch(
|
|
392
|
+
`https://api.dexscreener.com/tokens/v1/base/${addrs}`,
|
|
393
|
+
{ signal: AbortSignal.timeout(5e3) }
|
|
394
|
+
);
|
|
395
|
+
if (dsResponse.ok) {
|
|
396
|
+
const pairs = await dsResponse.json();
|
|
397
|
+
const bestPrices = {};
|
|
398
|
+
for (const pair of pairs || []) {
|
|
399
|
+
if (!pair.priceUsd || !pair.baseToken?.address) continue;
|
|
400
|
+
const addr = pair.baseToken.address.toLowerCase();
|
|
401
|
+
const price = parseFloat(pair.priceUsd);
|
|
402
|
+
const liq = pair.liquidity?.usd || 0;
|
|
403
|
+
if (price > 0 && (!bestPrices[addr] || liq > bestPrices[addr].liquidity)) {
|
|
404
|
+
bestPrices[addr] = { price, liquidity: liq };
|
|
405
|
+
if (pair.baseToken.symbol && !symbolCache[addr]) {
|
|
406
|
+
symbolCache[addr] = pair.baseToken.symbol;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
for (const [addr, { price }] of Object.entries(bestPrices)) {
|
|
411
|
+
prices[addr] = price;
|
|
412
|
+
const sym = symbolCache[addr] || addr.slice(0, 10);
|
|
413
|
+
console.log(`DexScreener price for ${sym}: $${price}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
} catch {
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
362
420
|
if (Object.keys(prices).length > 0) {
|
|
363
421
|
this.cachedPrices = prices;
|
|
364
422
|
}
|
|
@@ -368,7 +426,8 @@ var MarketDataService = class {
|
|
|
368
426
|
}
|
|
369
427
|
for (const addr of tokenAddresses) {
|
|
370
428
|
if (!prices[addr.toLowerCase()]) {
|
|
371
|
-
|
|
429
|
+
const sym = symbolCache[addr.toLowerCase()];
|
|
430
|
+
console.warn(`No price available for ${sym ? `${sym} (${addr})` : addr} \u2014 CoinGecko, DeFi Llama, and DexScreener all returned nothing`);
|
|
372
431
|
prices[addr.toLowerCase()] = 0;
|
|
373
432
|
}
|
|
374
433
|
}
|
|
@@ -535,7 +594,7 @@ var PositionTracker = class {
|
|
|
535
594
|
} else {
|
|
536
595
|
this.positions[token] = {
|
|
537
596
|
token,
|
|
538
|
-
symbol: TOKEN_SYMBOLS[token],
|
|
597
|
+
symbol: TOKEN_SYMBOLS[token] || getTokenSymbol(token),
|
|
539
598
|
entryPrice: priceUSD,
|
|
540
599
|
averageEntryPrice: priceUSD,
|
|
541
600
|
totalCostBasis: costUSD,
|
|
@@ -588,7 +647,7 @@ var PositionTracker = class {
|
|
|
588
647
|
const price = prices[token] || 0;
|
|
589
648
|
this.positions[token] = {
|
|
590
649
|
token,
|
|
591
|
-
symbol: TOKEN_SYMBOLS[token],
|
|
650
|
+
symbol: TOKEN_SYMBOLS[token] || getTokenSymbol(token),
|
|
592
651
|
entryPrice: price,
|
|
593
652
|
averageEntryPrice: price,
|
|
594
653
|
totalCostBasis: amount * price,
|
|
@@ -599,7 +658,7 @@ var PositionTracker = class {
|
|
|
599
658
|
txHashes: []
|
|
600
659
|
};
|
|
601
660
|
if (price > 0) {
|
|
602
|
-
console.log(`Position tracker: detected new holding ${TOKEN_SYMBOLS[token] || token.slice(0, 10)} (${amount.toFixed(4)} units @ $${price.toFixed(4)})`);
|
|
661
|
+
console.log(`Position tracker: detected new holding ${TOKEN_SYMBOLS[token] || getTokenSymbol(token) || token.slice(0, 10)} (${amount.toFixed(4)} units @ $${price.toFixed(4)})`);
|
|
603
662
|
}
|
|
604
663
|
changed = true;
|
|
605
664
|
}
|
|
@@ -3826,7 +3885,7 @@ function loadSecureEnv(basePath, passphrase) {
|
|
|
3826
3885
|
}
|
|
3827
3886
|
|
|
3828
3887
|
// src/index.ts
|
|
3829
|
-
var AGENT_VERSION = "0.1.
|
|
3888
|
+
var AGENT_VERSION = "0.1.31";
|
|
3830
3889
|
|
|
3831
3890
|
// src/relay.ts
|
|
3832
3891
|
var RelayClient = class {
|
|
@@ -4423,6 +4482,10 @@ var AgentRuntime = class {
|
|
|
4423
4482
|
this.config.allowedTokens = void 0;
|
|
4424
4483
|
console.log("Frontier risk universe: all tokens allowed (no restrictions)");
|
|
4425
4484
|
console.log("Frontier risk universe: vault creation is disabled");
|
|
4485
|
+
const trackedCount = this.positionTracker.getPositions().length;
|
|
4486
|
+
if (trackedCount > 0) {
|
|
4487
|
+
console.log(`Auto-tracking ${trackedCount} token(s) from position history`);
|
|
4488
|
+
}
|
|
4426
4489
|
return;
|
|
4427
4490
|
}
|
|
4428
4491
|
const configTokens = this.config.allowedTokens || this.getDefaultTokens();
|
|
@@ -4982,7 +5045,7 @@ var AgentRuntime = class {
|
|
|
4982
5045
|
--- Trading Cycle: ${(/* @__PURE__ */ new Date()).toISOString()} ---`);
|
|
4983
5046
|
this.cycleCount++;
|
|
4984
5047
|
this.lastCycleAt = Date.now();
|
|
4985
|
-
const tokens = this.
|
|
5048
|
+
const tokens = this.getTokensToTrack();
|
|
4986
5049
|
const marketData = await this.marketData.fetchMarketData(this.client.address, tokens);
|
|
4987
5050
|
console.log(`Portfolio value: $${marketData.portfolioValue.toFixed(2)}`);
|
|
4988
5051
|
this.lastPortfolioValue = marketData.portfolioValue;
|
|
@@ -5079,7 +5142,7 @@ var AgentRuntime = class {
|
|
|
5079
5142
|
success: result.success
|
|
5080
5143
|
});
|
|
5081
5144
|
}
|
|
5082
|
-
const postTokens = this.
|
|
5145
|
+
const postTokens = this.getTokensToTrack();
|
|
5083
5146
|
const postTradeData = await this.marketData.fetchMarketData(this.client.address, postTokens);
|
|
5084
5147
|
const marketPnL = postTradeData.portfolioValue - preTradePortfolioValue + totalFeesUSD;
|
|
5085
5148
|
this.riskManager.updatePnL(marketPnL);
|
|
@@ -5222,6 +5285,38 @@ var AgentRuntime = class {
|
|
|
5222
5285
|
getRpcUrl() {
|
|
5223
5286
|
return getRpcUrl();
|
|
5224
5287
|
}
|
|
5288
|
+
/**
|
|
5289
|
+
* Get the full list of tokens to fetch balances/prices for this cycle.
|
|
5290
|
+
* Starts from allowedTokens (or default whitelist), then merges in any tokens
|
|
5291
|
+
* the position tracker knows about — so previously-traded tokens (especially
|
|
5292
|
+
* for Frontier agents trading outside the whitelist) stay visible.
|
|
5293
|
+
*/
|
|
5294
|
+
getTokensToTrack() {
|
|
5295
|
+
const base5 = this.config.allowedTokens || this.getDefaultTokens();
|
|
5296
|
+
const baseSet = new Set(base5.map((t) => t.toLowerCase()));
|
|
5297
|
+
const trackedPositions = this.positionTracker.getPositions();
|
|
5298
|
+
const extras = [];
|
|
5299
|
+
for (const pos of trackedPositions) {
|
|
5300
|
+
if (!baseSet.has(pos.token.toLowerCase())) {
|
|
5301
|
+
extras.push(pos.token);
|
|
5302
|
+
baseSet.add(pos.token.toLowerCase());
|
|
5303
|
+
}
|
|
5304
|
+
}
|
|
5305
|
+
const recentTrades = this.positionTracker.getTradeHistory(20);
|
|
5306
|
+
for (const trade of recentTrades) {
|
|
5307
|
+
for (const addr of [trade.tokenIn, trade.tokenOut]) {
|
|
5308
|
+
const key = addr.toLowerCase();
|
|
5309
|
+
if (key !== NATIVE_ETH.toLowerCase() && !baseSet.has(key)) {
|
|
5310
|
+
extras.push(addr);
|
|
5311
|
+
baseSet.add(key);
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
}
|
|
5315
|
+
if (extras.length > 0) {
|
|
5316
|
+
console.log(`Auto-tracking ${extras.length} additional token(s) from position history`);
|
|
5317
|
+
}
|
|
5318
|
+
return [...base5, ...extras];
|
|
5319
|
+
}
|
|
5225
5320
|
/**
|
|
5226
5321
|
* Default tokens to track.
|
|
5227
5322
|
* These are validated against the on-chain registry's isTradeAllowed() during init —
|
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -339,9 +339,9 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
339
339
|
}>>;
|
|
340
340
|
allowedTokens: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
341
341
|
}, "strip", z.ZodTypeAny, {
|
|
342
|
+
agentId: string | number;
|
|
342
343
|
name: string;
|
|
343
344
|
network: "mainnet";
|
|
344
|
-
agentId: string | number;
|
|
345
345
|
llm: {
|
|
346
346
|
provider: "custom" | "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "ollama";
|
|
347
347
|
temperature: number;
|
|
@@ -388,8 +388,8 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
388
388
|
} | undefined;
|
|
389
389
|
allowedTokens?: string[] | undefined;
|
|
390
390
|
}, {
|
|
391
|
-
name: string;
|
|
392
391
|
agentId: string | number;
|
|
392
|
+
name: string;
|
|
393
393
|
llm: {
|
|
394
394
|
provider: "custom" | "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "ollama";
|
|
395
395
|
model?: string | undefined;
|
|
@@ -892,6 +892,13 @@ declare class AgentRuntime {
|
|
|
892
892
|
* Get RPC URL from environment or default
|
|
893
893
|
*/
|
|
894
894
|
private getRpcUrl;
|
|
895
|
+
/**
|
|
896
|
+
* Get the full list of tokens to fetch balances/prices for this cycle.
|
|
897
|
+
* Starts from allowedTokens (or default whitelist), then merges in any tokens
|
|
898
|
+
* the position tracker knows about — so previously-traded tokens (especially
|
|
899
|
+
* for Frontier agents trading outside the whitelist) stay visible.
|
|
900
|
+
*/
|
|
901
|
+
private getTokensToTrack;
|
|
895
902
|
/**
|
|
896
903
|
* Default tokens to track.
|
|
897
904
|
* These are validated against the on-chain registry's isTradeAllowed() during init —
|
|
@@ -2107,6 +2114,6 @@ declare function decryptEnvFile(encPath: string, passphrase: string): Record<str
|
|
|
2107
2114
|
declare function loadSecureEnv(basePath: string, passphrase?: string): boolean;
|
|
2108
2115
|
|
|
2109
2116
|
/** @exagent/agent package version — update alongside package.json */
|
|
2110
|
-
declare const AGENT_VERSION = "0.1.
|
|
2117
|
+
declare const AGENT_VERSION = "0.1.31";
|
|
2111
2118
|
|
|
2112
2119
|
export { AGENT_VERSION, type AccountSummary, type AgentConfig, AgentConfigSchema, type AgentMode, AgentRuntime, type AgentStatusPayload, AnthropicAdapter, BaseLLMAdapter, type CommandType, DeepSeekAdapter, FileStore, type FillCallback, type FundingCallback, type FundingPayment, GoogleAdapter, GroqAdapter, HYPERLIQUID_DOMAIN, HyperliquidClient, HyperliquidSigner, HyperliquidWebSocket, type LLMAdapter, type LLMConfig, LLMConfigSchema, type LLMMessage, type LLMMetadata, type LLMProvider, LLMProviderSchema, type LLMResponse, type LiquidationCallback, type MarketData, MarketDataService, type MessageLevel, type MessageType, MistralAdapter, OllamaAdapter, type OnboardingStatus, OpenAIAdapter, OrderManager, type OrderResult, type PerpAction, type PerpConfig$1 as PerpConfig, PerpConfigSchema, type PerpFill, type PerpMarketData, PerpOnboarding, type PerpPosition, type PerpStrategyFunction, PerpTradeRecorder, type PerpTradeSignal, type PerpConfig as PerpTradingConfig, PositionManager, type PositionSummary, PositionTracker, type RecordPerpTradeParams, RelayClient, type RelayCommand, type RelayConfig$1 as RelayConfig, RelayConfigSchema, RiskManager, type RiskState, type RiskUniverse, RiskUniverseSchema, type RuntimeConfig, STRATEGY_TEMPLATES, type StrategyContext, type StrategyFunction, type StrategyStore, type StrategyTemplate, TogetherAdapter, type TrackedPosition, TradeExecutor, type TradeRecord, type TradeSignal, type TradingConfig, TradingConfigSchema, type VaultConfig, VaultConfigSchema, VaultManager, type VaultManagerConfig, type VaultPolicy, VaultPolicySchema, type VaultStatus, createLLMAdapter, createSampleConfig, decryptEnvFile, encryptEnvFile, fillHashToBytes32, fillOidToBytes32, getAllStrategyTemplates, getNextNonce, getStrategyTemplate, loadConfig, loadSecureEnv, loadStrategy, validateConfig, validateStrategy };
|
package/dist/index.d.ts
CHANGED
|
@@ -339,9 +339,9 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
339
339
|
}>>;
|
|
340
340
|
allowedTokens: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
341
341
|
}, "strip", z.ZodTypeAny, {
|
|
342
|
+
agentId: string | number;
|
|
342
343
|
name: string;
|
|
343
344
|
network: "mainnet";
|
|
344
|
-
agentId: string | number;
|
|
345
345
|
llm: {
|
|
346
346
|
provider: "custom" | "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "ollama";
|
|
347
347
|
temperature: number;
|
|
@@ -388,8 +388,8 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
388
388
|
} | undefined;
|
|
389
389
|
allowedTokens?: string[] | undefined;
|
|
390
390
|
}, {
|
|
391
|
-
name: string;
|
|
392
391
|
agentId: string | number;
|
|
392
|
+
name: string;
|
|
393
393
|
llm: {
|
|
394
394
|
provider: "custom" | "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "ollama";
|
|
395
395
|
model?: string | undefined;
|
|
@@ -892,6 +892,13 @@ declare class AgentRuntime {
|
|
|
892
892
|
* Get RPC URL from environment or default
|
|
893
893
|
*/
|
|
894
894
|
private getRpcUrl;
|
|
895
|
+
/**
|
|
896
|
+
* Get the full list of tokens to fetch balances/prices for this cycle.
|
|
897
|
+
* Starts from allowedTokens (or default whitelist), then merges in any tokens
|
|
898
|
+
* the position tracker knows about — so previously-traded tokens (especially
|
|
899
|
+
* for Frontier agents trading outside the whitelist) stay visible.
|
|
900
|
+
*/
|
|
901
|
+
private getTokensToTrack;
|
|
895
902
|
/**
|
|
896
903
|
* Default tokens to track.
|
|
897
904
|
* These are validated against the on-chain registry's isTradeAllowed() during init —
|
|
@@ -2107,6 +2114,6 @@ declare function decryptEnvFile(encPath: string, passphrase: string): Record<str
|
|
|
2107
2114
|
declare function loadSecureEnv(basePath: string, passphrase?: string): boolean;
|
|
2108
2115
|
|
|
2109
2116
|
/** @exagent/agent package version — update alongside package.json */
|
|
2110
|
-
declare const AGENT_VERSION = "0.1.
|
|
2117
|
+
declare const AGENT_VERSION = "0.1.31";
|
|
2111
2118
|
|
|
2112
2119
|
export { AGENT_VERSION, type AccountSummary, type AgentConfig, AgentConfigSchema, type AgentMode, AgentRuntime, type AgentStatusPayload, AnthropicAdapter, BaseLLMAdapter, type CommandType, DeepSeekAdapter, FileStore, type FillCallback, type FundingCallback, type FundingPayment, GoogleAdapter, GroqAdapter, HYPERLIQUID_DOMAIN, HyperliquidClient, HyperliquidSigner, HyperliquidWebSocket, type LLMAdapter, type LLMConfig, LLMConfigSchema, type LLMMessage, type LLMMetadata, type LLMProvider, LLMProviderSchema, type LLMResponse, type LiquidationCallback, type MarketData, MarketDataService, type MessageLevel, type MessageType, MistralAdapter, OllamaAdapter, type OnboardingStatus, OpenAIAdapter, OrderManager, type OrderResult, type PerpAction, type PerpConfig$1 as PerpConfig, PerpConfigSchema, type PerpFill, type PerpMarketData, PerpOnboarding, type PerpPosition, type PerpStrategyFunction, PerpTradeRecorder, type PerpTradeSignal, type PerpConfig as PerpTradingConfig, PositionManager, type PositionSummary, PositionTracker, type RecordPerpTradeParams, RelayClient, type RelayCommand, type RelayConfig$1 as RelayConfig, RelayConfigSchema, RiskManager, type RiskState, type RiskUniverse, RiskUniverseSchema, type RuntimeConfig, STRATEGY_TEMPLATES, type StrategyContext, type StrategyFunction, type StrategyStore, type StrategyTemplate, TogetherAdapter, type TrackedPosition, TradeExecutor, type TradeRecord, type TradeSignal, type TradingConfig, TradingConfigSchema, type VaultConfig, VaultConfigSchema, VaultManager, type VaultManagerConfig, type VaultPolicy, VaultPolicySchema, type VaultStatus, createLLMAdapter, createSampleConfig, decryptEnvFile, encryptEnvFile, fillHashToBytes32, fillOidToBytes32, getAllStrategyTemplates, getNextNonce, getStrategyTemplate, loadConfig, loadSecureEnv, loadStrategy, validateConfig, validateStrategy };
|
package/dist/index.js
CHANGED
|
@@ -171,6 +171,7 @@ var TOKEN_DECIMALS = {
|
|
|
171
171
|
// SKI
|
|
172
172
|
};
|
|
173
173
|
var decimalsCache = {};
|
|
174
|
+
var symbolCache = {};
|
|
174
175
|
function getTokenDecimals(address) {
|
|
175
176
|
const key = address.toLowerCase();
|
|
176
177
|
const known = TOKEN_DECIMALS[key];
|
|
@@ -180,26 +181,43 @@ function getTokenDecimals(address) {
|
|
|
180
181
|
console.warn(`Unknown token decimals for ${address}, defaulting to 18. Call fetchTokenDecimals() first for accuracy.`);
|
|
181
182
|
return 18;
|
|
182
183
|
}
|
|
184
|
+
function getTokenSymbol(address) {
|
|
185
|
+
return symbolCache[address.toLowerCase()];
|
|
186
|
+
}
|
|
183
187
|
async function fetchTokenDecimals(client, address) {
|
|
184
188
|
const key = address.toLowerCase();
|
|
185
189
|
const known = TOKEN_DECIMALS[key];
|
|
186
190
|
if (known !== void 0) return known;
|
|
187
191
|
const cached = decimalsCache[key];
|
|
188
192
|
if (cached !== void 0) return cached;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
193
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
194
|
+
try {
|
|
195
|
+
const [decimals, symbol] = await Promise.all([
|
|
196
|
+
client.readContract({
|
|
197
|
+
address,
|
|
198
|
+
abi: import_viem.erc20Abi,
|
|
199
|
+
functionName: "decimals"
|
|
200
|
+
}),
|
|
201
|
+
client.readContract({
|
|
202
|
+
address,
|
|
203
|
+
abi: import_viem.erc20Abi,
|
|
204
|
+
functionName: "symbol"
|
|
205
|
+
}).catch(() => void 0)
|
|
206
|
+
// symbol is optional — some tokens don't have it
|
|
207
|
+
]);
|
|
208
|
+
const result = Number(decimals);
|
|
209
|
+
decimalsCache[key] = result;
|
|
210
|
+
if (symbol) symbolCache[key] = String(symbol);
|
|
211
|
+
return result;
|
|
212
|
+
} catch {
|
|
213
|
+
if (attempt === 0) {
|
|
214
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
202
217
|
}
|
|
218
|
+
console.warn(`Failed to fetch decimals for ${address} after 2 attempts, defaulting to 18`);
|
|
219
|
+
decimalsCache[key] = 18;
|
|
220
|
+
return 18;
|
|
203
221
|
}
|
|
204
222
|
var TOKEN_TO_COINGECKO = {
|
|
205
223
|
[NATIVE_ETH.toLowerCase()]: "ethereum",
|
|
@@ -412,6 +430,46 @@ var MarketDataService = class {
|
|
|
412
430
|
} catch {
|
|
413
431
|
}
|
|
414
432
|
}
|
|
433
|
+
const stillMissing = tokenAddresses.filter(
|
|
434
|
+
(addr) => !prices[addr.toLowerCase()]
|
|
435
|
+
);
|
|
436
|
+
if (stillMissing.length > 0) {
|
|
437
|
+
const batches = [];
|
|
438
|
+
for (let i = 0; i < stillMissing.length; i += 30) {
|
|
439
|
+
batches.push(stillMissing.slice(i, i + 30));
|
|
440
|
+
}
|
|
441
|
+
for (const batch of batches) {
|
|
442
|
+
try {
|
|
443
|
+
const addrs = batch.join(",");
|
|
444
|
+
const dsResponse = await fetch(
|
|
445
|
+
`https://api.dexscreener.com/tokens/v1/base/${addrs}`,
|
|
446
|
+
{ signal: AbortSignal.timeout(5e3) }
|
|
447
|
+
);
|
|
448
|
+
if (dsResponse.ok) {
|
|
449
|
+
const pairs = await dsResponse.json();
|
|
450
|
+
const bestPrices = {};
|
|
451
|
+
for (const pair of pairs || []) {
|
|
452
|
+
if (!pair.priceUsd || !pair.baseToken?.address) continue;
|
|
453
|
+
const addr = pair.baseToken.address.toLowerCase();
|
|
454
|
+
const price = parseFloat(pair.priceUsd);
|
|
455
|
+
const liq = pair.liquidity?.usd || 0;
|
|
456
|
+
if (price > 0 && (!bestPrices[addr] || liq > bestPrices[addr].liquidity)) {
|
|
457
|
+
bestPrices[addr] = { price, liquidity: liq };
|
|
458
|
+
if (pair.baseToken.symbol && !symbolCache[addr]) {
|
|
459
|
+
symbolCache[addr] = pair.baseToken.symbol;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
for (const [addr, { price }] of Object.entries(bestPrices)) {
|
|
464
|
+
prices[addr] = price;
|
|
465
|
+
const sym = symbolCache[addr] || addr.slice(0, 10);
|
|
466
|
+
console.log(`DexScreener price for ${sym}: $${price}`);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
} catch {
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
415
473
|
if (Object.keys(prices).length > 0) {
|
|
416
474
|
this.cachedPrices = prices;
|
|
417
475
|
}
|
|
@@ -421,7 +479,8 @@ var MarketDataService = class {
|
|
|
421
479
|
}
|
|
422
480
|
for (const addr of tokenAddresses) {
|
|
423
481
|
if (!prices[addr.toLowerCase()]) {
|
|
424
|
-
|
|
482
|
+
const sym = symbolCache[addr.toLowerCase()];
|
|
483
|
+
console.warn(`No price available for ${sym ? `${sym} (${addr})` : addr} \u2014 CoinGecko, DeFi Llama, and DexScreener all returned nothing`);
|
|
425
484
|
prices[addr.toLowerCase()] = 0;
|
|
426
485
|
}
|
|
427
486
|
}
|
|
@@ -588,7 +647,7 @@ var PositionTracker = class {
|
|
|
588
647
|
} else {
|
|
589
648
|
this.positions[token] = {
|
|
590
649
|
token,
|
|
591
|
-
symbol: TOKEN_SYMBOLS[token],
|
|
650
|
+
symbol: TOKEN_SYMBOLS[token] || getTokenSymbol(token),
|
|
592
651
|
entryPrice: priceUSD,
|
|
593
652
|
averageEntryPrice: priceUSD,
|
|
594
653
|
totalCostBasis: costUSD,
|
|
@@ -641,7 +700,7 @@ var PositionTracker = class {
|
|
|
641
700
|
const price = prices[token] || 0;
|
|
642
701
|
this.positions[token] = {
|
|
643
702
|
token,
|
|
644
|
-
symbol: TOKEN_SYMBOLS[token],
|
|
703
|
+
symbol: TOKEN_SYMBOLS[token] || getTokenSymbol(token),
|
|
645
704
|
entryPrice: price,
|
|
646
705
|
averageEntryPrice: price,
|
|
647
706
|
totalCostBasis: amount * price,
|
|
@@ -652,7 +711,7 @@ var PositionTracker = class {
|
|
|
652
711
|
txHashes: []
|
|
653
712
|
};
|
|
654
713
|
if (price > 0) {
|
|
655
|
-
console.log(`Position tracker: detected new holding ${TOKEN_SYMBOLS[token] || token.slice(0, 10)} (${amount.toFixed(4)} units @ $${price.toFixed(4)})`);
|
|
714
|
+
console.log(`Position tracker: detected new holding ${TOKEN_SYMBOLS[token] || getTokenSymbol(token) || token.slice(0, 10)} (${amount.toFixed(4)} units @ $${price.toFixed(4)})`);
|
|
656
715
|
}
|
|
657
716
|
changed = true;
|
|
658
717
|
}
|
|
@@ -4325,6 +4384,10 @@ var AgentRuntime = class {
|
|
|
4325
4384
|
this.config.allowedTokens = void 0;
|
|
4326
4385
|
console.log("Frontier risk universe: all tokens allowed (no restrictions)");
|
|
4327
4386
|
console.log("Frontier risk universe: vault creation is disabled");
|
|
4387
|
+
const trackedCount = this.positionTracker.getPositions().length;
|
|
4388
|
+
if (trackedCount > 0) {
|
|
4389
|
+
console.log(`Auto-tracking ${trackedCount} token(s) from position history`);
|
|
4390
|
+
}
|
|
4328
4391
|
return;
|
|
4329
4392
|
}
|
|
4330
4393
|
const configTokens = this.config.allowedTokens || this.getDefaultTokens();
|
|
@@ -4884,7 +4947,7 @@ var AgentRuntime = class {
|
|
|
4884
4947
|
--- Trading Cycle: ${(/* @__PURE__ */ new Date()).toISOString()} ---`);
|
|
4885
4948
|
this.cycleCount++;
|
|
4886
4949
|
this.lastCycleAt = Date.now();
|
|
4887
|
-
const tokens = this.
|
|
4950
|
+
const tokens = this.getTokensToTrack();
|
|
4888
4951
|
const marketData = await this.marketData.fetchMarketData(this.client.address, tokens);
|
|
4889
4952
|
console.log(`Portfolio value: $${marketData.portfolioValue.toFixed(2)}`);
|
|
4890
4953
|
this.lastPortfolioValue = marketData.portfolioValue;
|
|
@@ -4981,7 +5044,7 @@ var AgentRuntime = class {
|
|
|
4981
5044
|
success: result.success
|
|
4982
5045
|
});
|
|
4983
5046
|
}
|
|
4984
|
-
const postTokens = this.
|
|
5047
|
+
const postTokens = this.getTokensToTrack();
|
|
4985
5048
|
const postTradeData = await this.marketData.fetchMarketData(this.client.address, postTokens);
|
|
4986
5049
|
const marketPnL = postTradeData.portfolioValue - preTradePortfolioValue + totalFeesUSD;
|
|
4987
5050
|
this.riskManager.updatePnL(marketPnL);
|
|
@@ -5124,6 +5187,38 @@ var AgentRuntime = class {
|
|
|
5124
5187
|
getRpcUrl() {
|
|
5125
5188
|
return getRpcUrl();
|
|
5126
5189
|
}
|
|
5190
|
+
/**
|
|
5191
|
+
* Get the full list of tokens to fetch balances/prices for this cycle.
|
|
5192
|
+
* Starts from allowedTokens (or default whitelist), then merges in any tokens
|
|
5193
|
+
* the position tracker knows about — so previously-traded tokens (especially
|
|
5194
|
+
* for Frontier agents trading outside the whitelist) stay visible.
|
|
5195
|
+
*/
|
|
5196
|
+
getTokensToTrack() {
|
|
5197
|
+
const base5 = this.config.allowedTokens || this.getDefaultTokens();
|
|
5198
|
+
const baseSet = new Set(base5.map((t) => t.toLowerCase()));
|
|
5199
|
+
const trackedPositions = this.positionTracker.getPositions();
|
|
5200
|
+
const extras = [];
|
|
5201
|
+
for (const pos of trackedPositions) {
|
|
5202
|
+
if (!baseSet.has(pos.token.toLowerCase())) {
|
|
5203
|
+
extras.push(pos.token);
|
|
5204
|
+
baseSet.add(pos.token.toLowerCase());
|
|
5205
|
+
}
|
|
5206
|
+
}
|
|
5207
|
+
const recentTrades = this.positionTracker.getTradeHistory(20);
|
|
5208
|
+
for (const trade of recentTrades) {
|
|
5209
|
+
for (const addr of [trade.tokenIn, trade.tokenOut]) {
|
|
5210
|
+
const key = addr.toLowerCase();
|
|
5211
|
+
if (key !== NATIVE_ETH.toLowerCase() && !baseSet.has(key)) {
|
|
5212
|
+
extras.push(addr);
|
|
5213
|
+
baseSet.add(key);
|
|
5214
|
+
}
|
|
5215
|
+
}
|
|
5216
|
+
}
|
|
5217
|
+
if (extras.length > 0) {
|
|
5218
|
+
console.log(`Auto-tracking ${extras.length} additional token(s) from position history`);
|
|
5219
|
+
}
|
|
5220
|
+
return [...base5, ...extras];
|
|
5221
|
+
}
|
|
5127
5222
|
/**
|
|
5128
5223
|
* Default tokens to track.
|
|
5129
5224
|
* These are validated against the on-chain registry's isTradeAllowed() during init —
|
|
@@ -5453,7 +5548,7 @@ function loadSecureEnv(basePath, passphrase) {
|
|
|
5453
5548
|
}
|
|
5454
5549
|
|
|
5455
5550
|
// src/index.ts
|
|
5456
|
-
var AGENT_VERSION = "0.1.
|
|
5551
|
+
var AGENT_VERSION = "0.1.31";
|
|
5457
5552
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5458
5553
|
0 && (module.exports = {
|
|
5459
5554
|
AGENT_VERSION,
|
package/dist/index.mjs
CHANGED