@exagent/agent 0.1.45 → 0.1.47
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-6VBJT53Q.mjs +9838 -0
- package/dist/chunk-7CZNTETL.mjs +9750 -0
- package/dist/chunk-7QMPWDX3.mjs +9750 -0
- package/dist/chunk-ICTDJ7VX.mjs +9879 -0
- package/dist/chunk-PNDPQ22E.mjs +9879 -0
- package/dist/cli.js +195 -27
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +24 -10
- package/dist/index.d.ts +24 -10
- package/dist/index.js +195 -27
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -610,6 +610,30 @@ var MarketDataService = class {
|
|
|
610
610
|
}
|
|
611
611
|
};
|
|
612
612
|
}
|
|
613
|
+
/**
|
|
614
|
+
* Discover all ERC-20 token holdings for a wallet via Blockscout API.
|
|
615
|
+
* Returns token addresses with non-zero balances.
|
|
616
|
+
* Used by Frontier agents to find tokens outside the standard whitelist.
|
|
617
|
+
*/
|
|
618
|
+
async discoverTokenHoldings(walletAddress) {
|
|
619
|
+
try {
|
|
620
|
+
const resp = await fetch(
|
|
621
|
+
`https://base.blockscout.com/api/v2/addresses/${walletAddress}/token-balances`,
|
|
622
|
+
{ signal: AbortSignal.timeout(1e4) }
|
|
623
|
+
);
|
|
624
|
+
if (!resp.ok) return [];
|
|
625
|
+
const data = await resp.json();
|
|
626
|
+
const addresses = [];
|
|
627
|
+
for (const entry of data) {
|
|
628
|
+
if (entry.token?.type === "ERC-20" && entry.value && entry.value !== "0") {
|
|
629
|
+
addresses.push(entry.token.address.toLowerCase());
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return addresses;
|
|
633
|
+
} catch {
|
|
634
|
+
return [];
|
|
635
|
+
}
|
|
636
|
+
}
|
|
613
637
|
/**
|
|
614
638
|
* Check if cached prices are still fresh
|
|
615
639
|
*/
|
|
@@ -2353,16 +2377,25 @@ var TradeExecutor = class {
|
|
|
2353
2377
|
config;
|
|
2354
2378
|
allowedTokens;
|
|
2355
2379
|
configHashFn;
|
|
2356
|
-
|
|
2380
|
+
vaultManager;
|
|
2381
|
+
constructor(client, config, configHashFn, vaultManager) {
|
|
2357
2382
|
this.client = client;
|
|
2358
2383
|
this.config = config;
|
|
2359
2384
|
this.configHashFn = configHashFn;
|
|
2385
|
+
this.vaultManager = vaultManager;
|
|
2360
2386
|
this.allowedTokens = new Set(
|
|
2361
2387
|
(config.allowedTokens || []).map((t) => t.toLowerCase())
|
|
2362
2388
|
);
|
|
2363
2389
|
}
|
|
2364
2390
|
/**
|
|
2365
|
-
*
|
|
2391
|
+
* Set the vault manager (allows wiring after construction)
|
|
2392
|
+
*/
|
|
2393
|
+
setVaultManager(vm) {
|
|
2394
|
+
this.vaultManager = vm;
|
|
2395
|
+
}
|
|
2396
|
+
/**
|
|
2397
|
+
* Execute a single trade signal.
|
|
2398
|
+
* Tries vault trading first if vault exists, falls back to wallet trading.
|
|
2366
2399
|
*/
|
|
2367
2400
|
async execute(signal) {
|
|
2368
2401
|
if (signal.action === "hold") {
|
|
@@ -2375,13 +2408,38 @@ var TradeExecutor = class {
|
|
|
2375
2408
|
return { success: false, error: "Signal exceeds position limits" };
|
|
2376
2409
|
}
|
|
2377
2410
|
const configHash = this.configHashFn?.();
|
|
2378
|
-
const
|
|
2411
|
+
const tradeIntent = {
|
|
2379
2412
|
tokenIn: signal.tokenIn,
|
|
2380
2413
|
tokenOut: signal.tokenOut,
|
|
2381
2414
|
amountIn: signal.amountIn,
|
|
2382
2415
|
maxSlippageBps: this.config.trading?.maxSlippageBps ?? 100,
|
|
2383
2416
|
...configHash && { configHash }
|
|
2384
|
-
}
|
|
2417
|
+
};
|
|
2418
|
+
if (this.vaultManager) {
|
|
2419
|
+
const vaultAddress = await this.vaultManager.getVaultAddress();
|
|
2420
|
+
if (vaultAddress && this.vaultManager.preferVaultTrading) {
|
|
2421
|
+
const routerTrade = await this.client.buildRouterTrade(tradeIntent);
|
|
2422
|
+
if (routerTrade.vaultParams) {
|
|
2423
|
+
console.log(`Attempting vault trade via ${vaultAddress}`);
|
|
2424
|
+
const vaultResult = await this.vaultManager.executeVaultTrade({
|
|
2425
|
+
tokenIn: signal.tokenIn,
|
|
2426
|
+
tokenOut: signal.tokenOut,
|
|
2427
|
+
amountIn: BigInt(signal.amountIn),
|
|
2428
|
+
minAmountOut: BigInt(routerTrade.minAmountOut),
|
|
2429
|
+
vaultParams: routerTrade.vaultParams
|
|
2430
|
+
});
|
|
2431
|
+
if (vaultResult) {
|
|
2432
|
+
if (vaultResult.txHash) {
|
|
2433
|
+
console.log(`Vault trade executed: ${vaultResult.txHash}`);
|
|
2434
|
+
return { success: true, txHash: vaultResult.txHash };
|
|
2435
|
+
}
|
|
2436
|
+
console.error(`Vault trade failed: ${vaultResult.error}`);
|
|
2437
|
+
return { success: false, error: vaultResult.error };
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
const result = await this.client.trade(tradeIntent);
|
|
2385
2443
|
console.log(`Trade executed: ${result.hash}`);
|
|
2386
2444
|
return { success: true, txHash: result.hash };
|
|
2387
2445
|
} catch (error) {
|
|
@@ -2867,9 +2925,10 @@ var VAULT_ABI = [
|
|
|
2867
2925
|
outputs: [{ type: "uint256" }],
|
|
2868
2926
|
stateMutability: "view"
|
|
2869
2927
|
},
|
|
2928
|
+
// TOKEN → base asset (fee from output)
|
|
2870
2929
|
{
|
|
2871
2930
|
type: "function",
|
|
2872
|
-
name: "
|
|
2931
|
+
name: "executeSwap",
|
|
2873
2932
|
inputs: [
|
|
2874
2933
|
{ name: "tokenIn", type: "address" },
|
|
2875
2934
|
{ name: "tokenOut", type: "address" },
|
|
@@ -2877,6 +2936,44 @@ var VAULT_ABI = [
|
|
|
2877
2936
|
{ name: "minAmountOut", type: "uint256" },
|
|
2878
2937
|
{ name: "aggregator", type: "address" },
|
|
2879
2938
|
{ name: "swapData", type: "bytes" },
|
|
2939
|
+
{ name: "feeConvertAggregator", type: "address" },
|
|
2940
|
+
{ name: "feeSwapData", type: "bytes" },
|
|
2941
|
+
{ name: "deadline", type: "uint256" }
|
|
2942
|
+
],
|
|
2943
|
+
outputs: [{ type: "uint256" }],
|
|
2944
|
+
stateMutability: "nonpayable"
|
|
2945
|
+
},
|
|
2946
|
+
// Base asset → TOKEN (fee from input)
|
|
2947
|
+
{
|
|
2948
|
+
type: "function",
|
|
2949
|
+
name: "executeSwapSimple",
|
|
2950
|
+
inputs: [
|
|
2951
|
+
{ name: "tokenIn", type: "address" },
|
|
2952
|
+
{ name: "tokenOut", type: "address" },
|
|
2953
|
+
{ name: "amountIn", type: "uint256" },
|
|
2954
|
+
{ name: "minAmountOut", type: "uint256" },
|
|
2955
|
+
{ name: "target", type: "address" },
|
|
2956
|
+
{ name: "data", type: "bytes" },
|
|
2957
|
+
{ name: "feeConvertAggregator", type: "address" },
|
|
2958
|
+
{ name: "feeSwapData", type: "bytes" },
|
|
2959
|
+
{ name: "deadline", type: "uint256" }
|
|
2960
|
+
],
|
|
2961
|
+
outputs: [{ type: "uint256" }],
|
|
2962
|
+
stateMutability: "nonpayable"
|
|
2963
|
+
},
|
|
2964
|
+
// TOKEN → TOKEN (multi-hop via USDC, fee at midpoint)
|
|
2965
|
+
{
|
|
2966
|
+
type: "function",
|
|
2967
|
+
name: "executeSwapMultiHop",
|
|
2968
|
+
inputs: [
|
|
2969
|
+
{ name: "tokenIn", type: "address" },
|
|
2970
|
+
{ name: "tokenOut", type: "address" },
|
|
2971
|
+
{ name: "amountIn", type: "uint256" },
|
|
2972
|
+
{ name: "minAmountOut", type: "uint256" },
|
|
2973
|
+
{ name: "aggregator1", type: "address" },
|
|
2974
|
+
{ name: "swapData1", type: "bytes" },
|
|
2975
|
+
{ name: "aggregator2", type: "address" },
|
|
2976
|
+
{ name: "swapData2", type: "bytes" },
|
|
2880
2977
|
{ name: "deadline", type: "uint256" }
|
|
2881
2978
|
],
|
|
2882
2979
|
outputs: [{ type: "uint256" }],
|
|
@@ -3142,8 +3239,9 @@ var VaultManager = class {
|
|
|
3142
3239
|
}
|
|
3143
3240
|
}
|
|
3144
3241
|
/**
|
|
3145
|
-
* Execute a trade through the vault
|
|
3146
|
-
*
|
|
3242
|
+
* Execute a trade through the vault using API-provided vaultParams.
|
|
3243
|
+
* Dispatches to the correct vault function based on swapType.
|
|
3244
|
+
* Returns null if vault trading shouldn't be used (no vault, policy disabled).
|
|
3147
3245
|
*/
|
|
3148
3246
|
async executeVaultTrade(params) {
|
|
3149
3247
|
if (!this.preferVaultTrading) {
|
|
@@ -3154,23 +3252,71 @@ var VaultManager = class {
|
|
|
3154
3252
|
return null;
|
|
3155
3253
|
}
|
|
3156
3254
|
const deadline = params.deadline || BigInt(Math.floor(Date.now() / 1e3) + 3600);
|
|
3255
|
+
const { vaultParams } = params;
|
|
3157
3256
|
try {
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3257
|
+
let hash;
|
|
3258
|
+
switch (vaultParams.swapType) {
|
|
3259
|
+
case "swap":
|
|
3260
|
+
hash = await this.walletClient.writeContract({
|
|
3261
|
+
address: vaultAddress,
|
|
3262
|
+
abi: VAULT_ABI,
|
|
3263
|
+
functionName: "executeSwap",
|
|
3264
|
+
args: [
|
|
3265
|
+
params.tokenIn,
|
|
3266
|
+
params.tokenOut,
|
|
3267
|
+
params.amountIn,
|
|
3268
|
+
params.minAmountOut,
|
|
3269
|
+
vaultParams.aggregator,
|
|
3270
|
+
vaultParams.swapData,
|
|
3271
|
+
vaultParams.feeConvertAggregator,
|
|
3272
|
+
vaultParams.feeSwapData,
|
|
3273
|
+
deadline
|
|
3274
|
+
],
|
|
3275
|
+
chain: import_chains2.base,
|
|
3276
|
+
account: this.account
|
|
3277
|
+
});
|
|
3278
|
+
break;
|
|
3279
|
+
case "simple":
|
|
3280
|
+
hash = await this.walletClient.writeContract({
|
|
3281
|
+
address: vaultAddress,
|
|
3282
|
+
abi: VAULT_ABI,
|
|
3283
|
+
functionName: "executeSwapSimple",
|
|
3284
|
+
args: [
|
|
3285
|
+
params.tokenIn,
|
|
3286
|
+
params.tokenOut,
|
|
3287
|
+
params.amountIn,
|
|
3288
|
+
params.minAmountOut,
|
|
3289
|
+
vaultParams.target,
|
|
3290
|
+
vaultParams.data,
|
|
3291
|
+
vaultParams.feeConvertAggregator,
|
|
3292
|
+
vaultParams.feeSwapData,
|
|
3293
|
+
deadline
|
|
3294
|
+
],
|
|
3295
|
+
chain: import_chains2.base,
|
|
3296
|
+
account: this.account
|
|
3297
|
+
});
|
|
3298
|
+
break;
|
|
3299
|
+
case "multihop":
|
|
3300
|
+
hash = await this.walletClient.writeContract({
|
|
3301
|
+
address: vaultAddress,
|
|
3302
|
+
abi: VAULT_ABI,
|
|
3303
|
+
functionName: "executeSwapMultiHop",
|
|
3304
|
+
args: [
|
|
3305
|
+
params.tokenIn,
|
|
3306
|
+
params.tokenOut,
|
|
3307
|
+
params.amountIn,
|
|
3308
|
+
params.minAmountOut,
|
|
3309
|
+
vaultParams.aggregator1,
|
|
3310
|
+
vaultParams.swapData1,
|
|
3311
|
+
vaultParams.aggregator2,
|
|
3312
|
+
vaultParams.swapData2,
|
|
3313
|
+
deadline
|
|
3314
|
+
],
|
|
3315
|
+
chain: import_chains2.base,
|
|
3316
|
+
account: this.account
|
|
3317
|
+
});
|
|
3318
|
+
break;
|
|
3319
|
+
}
|
|
3174
3320
|
return { usedVault: true, txHash: hash };
|
|
3175
3321
|
} catch (error) {
|
|
3176
3322
|
return {
|
|
@@ -7148,6 +7294,8 @@ var AgentRuntime = class {
|
|
|
7148
7294
|
processAlive = true;
|
|
7149
7295
|
riskUniverse = 0;
|
|
7150
7296
|
allowedTokens = /* @__PURE__ */ new Set();
|
|
7297
|
+
/** Frontier token discovery — cached addresses from Blockscout scan */
|
|
7298
|
+
discoveredTokens = [];
|
|
7151
7299
|
strategyContext;
|
|
7152
7300
|
positionTracker;
|
|
7153
7301
|
// Paper trading components (null when not in paper mode)
|
|
@@ -7311,10 +7459,16 @@ var AgentRuntime = class {
|
|
|
7311
7459
|
vaultConfig
|
|
7312
7460
|
});
|
|
7313
7461
|
console.log(`Vault policy: ${vaultConfig.policy}`);
|
|
7462
|
+
if (this.executor) {
|
|
7463
|
+
this.executor.setVaultManager(this.vaultManager);
|
|
7464
|
+
}
|
|
7314
7465
|
const status = await this.vaultManager.getVaultStatus();
|
|
7315
7466
|
if (status.hasVault) {
|
|
7316
7467
|
console.log(`Vault exists: ${status.vaultAddress}`);
|
|
7317
7468
|
console.log(`Vault TVL: ${Number(status.totalAssets) / 1e6} USDC`);
|
|
7469
|
+
if (vaultConfig.preferVaultTrading) {
|
|
7470
|
+
console.log("Vault trading enabled \u2014 trades will execute from vault");
|
|
7471
|
+
}
|
|
7318
7472
|
} else {
|
|
7319
7473
|
console.log("No vault exists for this agent");
|
|
7320
7474
|
if (vaultConfig.policy === "manual") {
|
|
@@ -7749,6 +7903,13 @@ var AgentRuntime = class {
|
|
|
7749
7903
|
console.log("");
|
|
7750
7904
|
this.mode = "idle";
|
|
7751
7905
|
try {
|
|
7906
|
+
if (this.riskUniverse === 4) {
|
|
7907
|
+
const discovered = await this.marketData.discoverTokenHoldings(this.client.address);
|
|
7908
|
+
if (discovered.length > 0) {
|
|
7909
|
+
this.discoveredTokens = discovered;
|
|
7910
|
+
console.log(`Frontier token discovery: ${discovered.length} token(s) found on-chain`);
|
|
7911
|
+
}
|
|
7912
|
+
}
|
|
7752
7913
|
const tokens = this.getTokensToTrack();
|
|
7753
7914
|
const initData = await this.marketData.fetchMarketData(this.client.address, tokens);
|
|
7754
7915
|
void this.positionTracker.syncBalances(initData.balances, initData.prices);
|
|
@@ -8728,8 +8889,9 @@ This exit has been recorded in your trade history and counts toward your total P
|
|
|
8728
8889
|
this.paperPortfolio.save();
|
|
8729
8890
|
} else {
|
|
8730
8891
|
const vaultStatus = await this.vaultManager?.getVaultStatus();
|
|
8731
|
-
if (vaultStatus?.hasVault
|
|
8732
|
-
|
|
8892
|
+
if (vaultStatus?.hasVault) {
|
|
8893
|
+
const via = this.vaultManager?.preferVaultTrading ? "vault" : "wallet";
|
|
8894
|
+
console.log(`Vault active: ${vaultStatus.vaultAddress} (trades execute from ${via})`);
|
|
8733
8895
|
}
|
|
8734
8896
|
const results = await this.executor.executeAll(filteredSignals);
|
|
8735
8897
|
let totalFeesUSD = 0;
|
|
@@ -9101,8 +9263,14 @@ See: https://exagent.io/docs/guides/manual-exit`,
|
|
|
9101
9263
|
}
|
|
9102
9264
|
}
|
|
9103
9265
|
}
|
|
9266
|
+
for (const addr of this.discoveredTokens) {
|
|
9267
|
+
if (!baseSet.has(addr)) {
|
|
9268
|
+
extras.push(addr);
|
|
9269
|
+
baseSet.add(addr);
|
|
9270
|
+
}
|
|
9271
|
+
}
|
|
9104
9272
|
if (extras.length > 0) {
|
|
9105
|
-
console.log(`Auto-tracking ${extras.length} additional token(s) from position
|
|
9273
|
+
console.log(`Auto-tracking ${extras.length} additional token(s) from position/discovery`);
|
|
9106
9274
|
}
|
|
9107
9275
|
const resolver = this.marketData.getResolver();
|
|
9108
9276
|
const allTokens = [...base8, ...extras];
|
|
@@ -9442,7 +9610,7 @@ function loadSecureEnv(basePath, passphrase) {
|
|
|
9442
9610
|
}
|
|
9443
9611
|
|
|
9444
9612
|
// src/index.ts
|
|
9445
|
-
var AGENT_VERSION = "0.1.
|
|
9613
|
+
var AGENT_VERSION = "0.1.47";
|
|
9446
9614
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9447
9615
|
0 && (module.exports = {
|
|
9448
9616
|
AGENT_VERSION,
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exagent/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
4
4
|
"description": "Autonomous trading agent runtime for Exagent",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"clean": "rm -rf dist"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@exagent/sdk": "^0.1.
|
|
32
|
+
"@exagent/sdk": "^0.1.21",
|
|
33
33
|
"@nktkas/hyperliquid": "^0.31.0",
|
|
34
34
|
"@polymarket/clob-client": "^4.0.0",
|
|
35
35
|
"chalk": "^5.3.0",
|