@agether/agether 3.1.4 → 3.3.1
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/package.json +2 -2
- package/src/index.ts +529 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agether/agether",
|
|
3
|
-
"version": "3.1
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "OpenClaw plugin for Agether — onchain credit for AI agents on Ethereum & Base",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"openclaw": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
]
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@agether/sdk": "
|
|
12
|
+
"@agether/sdk": "^2.18.2",
|
|
13
13
|
"axios": "^1.6.0",
|
|
14
14
|
"ethers": "^6.9.0"
|
|
15
15
|
},
|
package/src/index.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
ScoringClient,
|
|
30
30
|
getContractAddresses,
|
|
31
31
|
ChainId,
|
|
32
|
+
AaveClient,
|
|
32
33
|
} from "@agether/sdk";
|
|
33
34
|
|
|
34
35
|
// ─── Constants ────────────────────────────────────────────
|
|
@@ -355,6 +356,19 @@ function createMorphoClient(cfg: PluginConfig): MorphoClient {
|
|
|
355
356
|
}
|
|
356
357
|
|
|
357
358
|
/** @deprecated Use createAgetherClient or createMorphoClient instead */
|
|
359
|
+
function createAaveClient(cfg: PluginConfig): AaveClient {
|
|
360
|
+
const agentId = state.getAgentId(cfg.chainId) || cfg.agentId;
|
|
361
|
+
if (!agentId) {
|
|
362
|
+
throw new Error("agentId not set. Register first with agether_register, then try again.");
|
|
363
|
+
}
|
|
364
|
+
return new AaveClient({
|
|
365
|
+
privateKey: cfg.privateKey,
|
|
366
|
+
rpcUrl: cfg.rpcUrl,
|
|
367
|
+
agentId,
|
|
368
|
+
chainId: cfg.chainId,
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
358
372
|
function createClient(cfg: PluginConfig): MorphoClient {
|
|
359
373
|
return createMorphoClient(cfg);
|
|
360
374
|
}
|
|
@@ -672,7 +686,7 @@ export default function register(api: any) {
|
|
|
672
686
|
// TOOL: morpho_deposit
|
|
673
687
|
// ═══════════════════════════════════════════════════════
|
|
674
688
|
api.registerTool({
|
|
675
|
-
name: "
|
|
689
|
+
name: "morpho_deposit",
|
|
676
690
|
description: "Deposit collateral into Morpho Blue to enable borrowing. Validates balance first.",
|
|
677
691
|
parameters: {
|
|
678
692
|
type: "object",
|
|
@@ -2125,6 +2139,520 @@ export default function register(api: any) {
|
|
|
2125
2139
|
});
|
|
2126
2140
|
|
|
2127
2141
|
|
|
2142
|
+
|
|
2143
|
+
// ═══════════════════════════════════════════════════════
|
|
2144
|
+
// TOOL: morpho_repay_and_withdraw
|
|
2145
|
+
// ═══════════════════════════════════════════════════════
|
|
2146
|
+
api.registerTool({
|
|
2147
|
+
name: "morpho_repay_and_withdraw",
|
|
2148
|
+
description: "Repay all debt and withdraw all collateral from Morpho in one atomic batch. Full position exit.",
|
|
2149
|
+
parameters: {
|
|
2150
|
+
type: "object",
|
|
2151
|
+
properties: {
|
|
2152
|
+
token: { type: "string", description: "Collateral token (optional — auto-detects active position)" },
|
|
2153
|
+
loanToken: { type: "string", description: "Loan token (optional)" },
|
|
2154
|
+
toEoa: { type: "boolean", description: "Send withdrawn collateral to EOA wallet (default: true)" },
|
|
2155
|
+
},
|
|
2156
|
+
},
|
|
2157
|
+
async execute(_id: string, params: { token?: string; loanToken?: string; toEoa?: boolean }) {
|
|
2158
|
+
try {
|
|
2159
|
+
const cfg = getConfig(api);
|
|
2160
|
+
requireChain(cfg);
|
|
2161
|
+
const client = createMorphoClient(cfg);
|
|
2162
|
+
const result = await client.repayAndWithdraw(params.token, params.loanToken, params.toEoa ?? true);
|
|
2163
|
+
const explorer = cfg.chainId === 8453 ? 'https://basescan.org/tx/' : 'https://etherscan.io/tx/';
|
|
2164
|
+
return ok(JSON.stringify({
|
|
2165
|
+
status: "position_closed",
|
|
2166
|
+
repaid: result.repaid,
|
|
2167
|
+
withdrawn: result.withdrawn + ' ' + result.collateralToken,
|
|
2168
|
+
loanToken: result.loanToken,
|
|
2169
|
+
tx: explorer + result.tx,
|
|
2170
|
+
}));
|
|
2171
|
+
} catch (e) { return fail(e); }
|
|
2172
|
+
},
|
|
2173
|
+
});
|
|
2174
|
+
|
|
2175
|
+
// ═══════════════════════════════════════════════════════
|
|
2176
|
+
// AAVE V3 TOOLS
|
|
2177
|
+
// ═══════════════════════════════════════════════════════
|
|
2178
|
+
|
|
2179
|
+
// ═══════════════════════════════════════════════════════
|
|
2180
|
+
// TOOL: aave_markets
|
|
2181
|
+
// ═══════════════════════════════════════════════════════
|
|
2182
|
+
api.registerTool({
|
|
2183
|
+
name: "aave_markets",
|
|
2184
|
+
description: "List Aave V3 reserves with supply/borrow APY, LTV, prices. Shows all available markets on the current chain.",
|
|
2185
|
+
parameters: { type: "object", properties: {} },
|
|
2186
|
+
async execute() {
|
|
2187
|
+
try {
|
|
2188
|
+
const cfg = getConfig(api);
|
|
2189
|
+
requireChain(cfg);
|
|
2190
|
+
const client = createAaveClient(cfg);
|
|
2191
|
+
const reserves = await client.getReserves();
|
|
2192
|
+
|
|
2193
|
+
if (reserves.length === 0) {
|
|
2194
|
+
return ok(JSON.stringify({ status: "no_reserves", message: "No Aave V3 reserves found on this chain." }));
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
const summary = reserves.map(r => ({
|
|
2198
|
+
asset: r.symbol,
|
|
2199
|
+
supplyApy: r.supplyApy.toFixed(2) + '%',
|
|
2200
|
+
borrowApy: r.borrowApy.toFixed(2) + '%',
|
|
2201
|
+
maxLtv: r.ltv.toFixed(0) + '%',
|
|
2202
|
+
liquidationThreshold: r.liquidationThreshold.toFixed(0) + '%',
|
|
2203
|
+
priceUsd: '$' + r.priceUsd.toFixed(2),
|
|
2204
|
+
borrowingEnabled: r.borrowingEnabled,
|
|
2205
|
+
active: r.isActive,
|
|
2206
|
+
}));
|
|
2207
|
+
|
|
2208
|
+
return ok(JSON.stringify({ status: "aave_reserves", chain: cfg.chainId === 8453 ? "Base" : "Ethereum", reserves: summary }));
|
|
2209
|
+
} catch (e) { return fail(e); }
|
|
2210
|
+
},
|
|
2211
|
+
});
|
|
2212
|
+
|
|
2213
|
+
// ═══════════════════════════════════════════════════════
|
|
2214
|
+
// TOOL: aave_status
|
|
2215
|
+
// ═══════════════════════════════════════════════════════
|
|
2216
|
+
api.registerTool({
|
|
2217
|
+
name: "aave_status",
|
|
2218
|
+
description: "Show Aave V3 account overview: total collateral, debt, health factor, and per-asset positions with APY.",
|
|
2219
|
+
parameters: { type: "object", properties: {} },
|
|
2220
|
+
async execute() {
|
|
2221
|
+
try {
|
|
2222
|
+
const cfg = getConfig(api);
|
|
2223
|
+
requireChain(cfg);
|
|
2224
|
+
const client = createAaveClient(cfg);
|
|
2225
|
+
const data = await client.getAccountData();
|
|
2226
|
+
|
|
2227
|
+
return ok(JSON.stringify({
|
|
2228
|
+
status: "aave_account",
|
|
2229
|
+
chain: cfg.chainId === 8453 ? "Base" : "Ethereum",
|
|
2230
|
+
totalCollateralUsd: '$' + data.totalCollateralUsd.toFixed(2),
|
|
2231
|
+
totalDebtUsd: '$' + data.totalDebtUsd.toFixed(2),
|
|
2232
|
+
availableBorrowUsd: '$' + data.availableBorrowUsd.toFixed(2),
|
|
2233
|
+
currentLtv: data.currentLtv.toFixed(2) + '%',
|
|
2234
|
+
liquidationThreshold: data.liquidationThreshold.toFixed(2) + '%',
|
|
2235
|
+
healthFactor: data.healthFactor === Infinity ? 'Safe (no debt)' : data.healthFactor.toFixed(3),
|
|
2236
|
+
positions: data.positions.map(p => ({
|
|
2237
|
+
asset: p.asset,
|
|
2238
|
+
supplied: p.supplied > 0 ? p.supplied.toFixed(6) + ' (' + '$' + p.suppliedUsd.toFixed(2) + ')' : '0',
|
|
2239
|
+
borrowed: p.borrowed > 0 ? p.borrowed.toFixed(6) + ' (' + '$' + p.borrowedUsd.toFixed(2) + ')' : '0',
|
|
2240
|
+
usedAsCollateral: p.usedAsCollateral,
|
|
2241
|
+
supplyApy: p.supplyApy.toFixed(2) + '%',
|
|
2242
|
+
borrowApy: p.borrowApy.toFixed(2) + '%',
|
|
2243
|
+
})),
|
|
2244
|
+
}));
|
|
2245
|
+
} catch (e) { return fail(e); }
|
|
2246
|
+
},
|
|
2247
|
+
});
|
|
2248
|
+
|
|
2249
|
+
// ═══════════════════════════════════════════════════════
|
|
2250
|
+
// TOOL: aave_supply
|
|
2251
|
+
// ═══════════════════════════════════════════════════════
|
|
2252
|
+
api.registerTool({
|
|
2253
|
+
name: "aave_deposit",
|
|
2254
|
+
description: "Deposit an asset to Aave V3 as collateral or to earn yield.",
|
|
2255
|
+
parameters: {
|
|
2256
|
+
type: "object",
|
|
2257
|
+
properties: {
|
|
2258
|
+
token: { type: "string", description: "Token to supply (e.g. 'WETH', 'USDC', 'wstETH')" },
|
|
2259
|
+
amount: { type: "string", description: "Amount to supply" },
|
|
2260
|
+
},
|
|
2261
|
+
required: ["token", "amount"],
|
|
2262
|
+
},
|
|
2263
|
+
async execute(_id: string, params: { token: string; amount: string }) {
|
|
2264
|
+
try {
|
|
2265
|
+
const cfg = getConfig(api);
|
|
2266
|
+
requireChain(cfg);
|
|
2267
|
+
const client = createAaveClient(cfg);
|
|
2268
|
+
const receipt = await client.supply(params.token, params.amount);
|
|
2269
|
+
const explorer = cfg.chainId === 8453 ? 'https://basescan.org/tx/' : 'https://etherscan.io/tx/';
|
|
2270
|
+
|
|
2271
|
+
return ok(JSON.stringify({
|
|
2272
|
+
status: "supplied",
|
|
2273
|
+
token: params.token,
|
|
2274
|
+
amount: params.amount,
|
|
2275
|
+
tx: explorer + receipt.hash,
|
|
2276
|
+
}));
|
|
2277
|
+
} catch (e) { return fail(e); }
|
|
2278
|
+
},
|
|
2279
|
+
});
|
|
2280
|
+
|
|
2281
|
+
// ═══════════════════════════════════════════════════════
|
|
2282
|
+
// TOOL: aave_withdraw
|
|
2283
|
+
// ═══════════════════════════════════════════════════════
|
|
2284
|
+
api.registerTool({
|
|
2285
|
+
name: "aave_withdraw",
|
|
2286
|
+
description: "Withdraw a supplied asset from Aave V3.",
|
|
2287
|
+
parameters: {
|
|
2288
|
+
type: "object",
|
|
2289
|
+
properties: {
|
|
2290
|
+
token: { type: "string", description: "Token to withdraw (e.g. 'WETH', 'USDC')" },
|
|
2291
|
+
amount: { type: "string", description: "Amount to withdraw. Use 'all' for full balance." },
|
|
2292
|
+
},
|
|
2293
|
+
required: ["token", "amount"],
|
|
2294
|
+
},
|
|
2295
|
+
async execute(_id: string, params: { token: string; amount: string }) {
|
|
2296
|
+
try {
|
|
2297
|
+
const cfg = getConfig(api);
|
|
2298
|
+
requireChain(cfg);
|
|
2299
|
+
const client = createAaveClient(cfg);
|
|
2300
|
+
const receipt = await client.withdraw(params.token, params.amount);
|
|
2301
|
+
const explorer = cfg.chainId === 8453 ? 'https://basescan.org/tx/' : 'https://etherscan.io/tx/';
|
|
2302
|
+
|
|
2303
|
+
return ok(JSON.stringify({
|
|
2304
|
+
status: "withdrawn",
|
|
2305
|
+
token: params.token,
|
|
2306
|
+
amount: params.amount,
|
|
2307
|
+
tx: explorer + receipt.hash,
|
|
2308
|
+
}));
|
|
2309
|
+
} catch (e) { return fail(e); }
|
|
2310
|
+
},
|
|
2311
|
+
});
|
|
2312
|
+
|
|
2313
|
+
// ═══════════════════════════════════════════════════════
|
|
2314
|
+
// TOOL: aave_borrow
|
|
2315
|
+
// ═══════════════════════════════════════════════════════
|
|
2316
|
+
api.registerTool({
|
|
2317
|
+
name: "aave_borrow",
|
|
2318
|
+
description: "Borrow an asset from Aave V3 against supplied collateral. Uses variable rate.",
|
|
2319
|
+
parameters: {
|
|
2320
|
+
type: "object",
|
|
2321
|
+
properties: {
|
|
2322
|
+
token: { type: "string", description: "Token to borrow (e.g. 'USDC', 'WETH')" },
|
|
2323
|
+
amount: { type: "string", description: "Amount to borrow" },
|
|
2324
|
+
},
|
|
2325
|
+
required: ["token", "amount"],
|
|
2326
|
+
},
|
|
2327
|
+
async execute(_id: string, params: { token: string; amount: string }) {
|
|
2328
|
+
try {
|
|
2329
|
+
const cfg = getConfig(api);
|
|
2330
|
+
requireChain(cfg);
|
|
2331
|
+
const client = createAaveClient(cfg);
|
|
2332
|
+
const receipt = await client.borrow(params.token, params.amount);
|
|
2333
|
+
const explorer = cfg.chainId === 8453 ? 'https://basescan.org/tx/' : 'https://etherscan.io/tx/';
|
|
2334
|
+
|
|
2335
|
+
return ok(JSON.stringify({
|
|
2336
|
+
status: "borrowed",
|
|
2337
|
+
token: params.token,
|
|
2338
|
+
amount: params.amount,
|
|
2339
|
+
tx: explorer + receipt.hash,
|
|
2340
|
+
}));
|
|
2341
|
+
} catch (e) { return fail(e); }
|
|
2342
|
+
},
|
|
2343
|
+
});
|
|
2344
|
+
|
|
2345
|
+
// ═══════════════════════════════════════════════════════
|
|
2346
|
+
// TOOL: aave_repay
|
|
2347
|
+
// ═══════════════════════════════════════════════════════
|
|
2348
|
+
api.registerTool({
|
|
2349
|
+
name: "aave_repay",
|
|
2350
|
+
description: "Repay borrowed asset on Aave V3. Use amount 'all' to repay full debt.",
|
|
2351
|
+
parameters: {
|
|
2352
|
+
type: "object",
|
|
2353
|
+
properties: {
|
|
2354
|
+
token: { type: "string", description: "Token to repay (e.g. 'USDC', 'WETH')" },
|
|
2355
|
+
amount: { type: "string", description: "Amount to repay. Use 'all' for full debt." },
|
|
2356
|
+
},
|
|
2357
|
+
required: ["token", "amount"],
|
|
2358
|
+
},
|
|
2359
|
+
async execute(_id: string, params: { token: string; amount: string }) {
|
|
2360
|
+
try {
|
|
2361
|
+
const cfg = getConfig(api);
|
|
2362
|
+
requireChain(cfg);
|
|
2363
|
+
const client = createAaveClient(cfg);
|
|
2364
|
+
const receipt = await client.repay(params.token, params.amount);
|
|
2365
|
+
const explorer = cfg.chainId === 8453 ? 'https://basescan.org/tx/' : 'https://etherscan.io/tx/';
|
|
2366
|
+
|
|
2367
|
+
return ok(JSON.stringify({
|
|
2368
|
+
status: "repaid",
|
|
2369
|
+
token: params.token,
|
|
2370
|
+
amount: params.amount,
|
|
2371
|
+
tx: explorer + receipt.hash,
|
|
2372
|
+
}));
|
|
2373
|
+
} catch (e) { return fail(e); }
|
|
2374
|
+
},
|
|
2375
|
+
});
|
|
2376
|
+
|
|
2377
|
+
// ═══════════════════════════════════════════════════════
|
|
2378
|
+
// TOOL: aave_set_collateral
|
|
2379
|
+
// ═══════════════════════════════════════════════════════
|
|
2380
|
+
api.registerTool({
|
|
2381
|
+
name: "aave_set_collateral",
|
|
2382
|
+
description: "Enable or disable a supplied asset as collateral on Aave V3.",
|
|
2383
|
+
parameters: {
|
|
2384
|
+
type: "object",
|
|
2385
|
+
properties: {
|
|
2386
|
+
token: { type: "string", description: "Token to toggle (e.g. 'WETH', 'wstETH')" },
|
|
2387
|
+
enabled: { type: "boolean", description: "true to enable as collateral, false to disable" },
|
|
2388
|
+
},
|
|
2389
|
+
required: ["token", "enabled"],
|
|
2390
|
+
},
|
|
2391
|
+
async execute(_id: string, params: { token: string; enabled: boolean }) {
|
|
2392
|
+
try {
|
|
2393
|
+
const cfg = getConfig(api);
|
|
2394
|
+
requireChain(cfg);
|
|
2395
|
+
const client = createAaveClient(cfg);
|
|
2396
|
+
const receipt = await client.setCollateral(params.token, params.enabled);
|
|
2397
|
+
const explorer = cfg.chainId === 8453 ? 'https://basescan.org/tx/' : 'https://etherscan.io/tx/';
|
|
2398
|
+
|
|
2399
|
+
return ok(JSON.stringify({
|
|
2400
|
+
status: "collateral_updated",
|
|
2401
|
+
token: params.token,
|
|
2402
|
+
enabled: params.enabled,
|
|
2403
|
+
tx: explorer + receipt.hash,
|
|
2404
|
+
}));
|
|
2405
|
+
} catch (e) { return fail(e); }
|
|
2406
|
+
},
|
|
2407
|
+
});
|
|
2408
|
+
|
|
2409
|
+
|
|
2410
|
+
|
|
2411
|
+
// ═══════════════════════════════════════════════════════
|
|
2412
|
+
// TOOL: aave_supply_and_borrow
|
|
2413
|
+
// ═══════════════════════════════════════════════════════
|
|
2414
|
+
api.registerTool({
|
|
2415
|
+
name: "aave_deposit_and_borrow",
|
|
2416
|
+
description: "Deposit collateral and borrow in one atomic batch on Aave V3. Preferred over separate deposit + borrow.",
|
|
2417
|
+
parameters: {
|
|
2418
|
+
type: "object",
|
|
2419
|
+
properties: {
|
|
2420
|
+
supplyToken: { type: "string", description: "Token to supply as collateral (e.g. 'wstETH', 'WETH')" },
|
|
2421
|
+
supplyAmount: { type: "string", description: "Amount to supply" },
|
|
2422
|
+
borrowToken: { type: "string", description: "Token to borrow (e.g. 'USDC', 'WETH')" },
|
|
2423
|
+
borrowAmount: { type: "string", description: "Amount to borrow" },
|
|
2424
|
+
},
|
|
2425
|
+
required: ["supplyToken", "supplyAmount", "borrowToken", "borrowAmount"],
|
|
2426
|
+
},
|
|
2427
|
+
async execute(_id: string, params: { supplyToken: string; supplyAmount: string; borrowToken: string; borrowAmount: string }) {
|
|
2428
|
+
try {
|
|
2429
|
+
const cfg = getConfig(api);
|
|
2430
|
+
requireChain(cfg);
|
|
2431
|
+
const client = createAaveClient(cfg);
|
|
2432
|
+
const receipt = await client.supplyAndBorrow(params.supplyToken, params.supplyAmount, params.borrowToken, params.borrowAmount);
|
|
2433
|
+
const explorer = cfg.chainId === 8453 ? 'https://basescan.org/tx/' : 'https://etherscan.io/tx/';
|
|
2434
|
+
return ok(JSON.stringify({
|
|
2435
|
+
status: "supplied_and_borrowed",
|
|
2436
|
+
supplied: params.supplyAmount + ' ' + params.supplyToken,
|
|
2437
|
+
borrowed: params.borrowAmount + ' ' + params.borrowToken,
|
|
2438
|
+
tx: explorer + receipt.hash,
|
|
2439
|
+
}));
|
|
2440
|
+
} catch (e) { return fail(e); }
|
|
2441
|
+
},
|
|
2442
|
+
});
|
|
2443
|
+
|
|
2444
|
+
// ═══════════════════════════════════════════════════════
|
|
2445
|
+
// TOOL: aave_search
|
|
2446
|
+
// ═══════════════════════════════════════════════════════
|
|
2447
|
+
api.registerTool({
|
|
2448
|
+
name: "aave_search",
|
|
2449
|
+
description: "Search Aave V3 reserves by token name or symbol.",
|
|
2450
|
+
parameters: {
|
|
2451
|
+
type: "object",
|
|
2452
|
+
properties: {
|
|
2453
|
+
token: { type: "string", description: "Token to search for (e.g. 'wstETH', 'USDC')" },
|
|
2454
|
+
},
|
|
2455
|
+
required: ["token"],
|
|
2456
|
+
},
|
|
2457
|
+
async execute(_id: string, params: { token: string }) {
|
|
2458
|
+
try {
|
|
2459
|
+
const cfg = getConfig(api);
|
|
2460
|
+
requireChain(cfg);
|
|
2461
|
+
const client = createAaveClient(cfg);
|
|
2462
|
+
const results = await client.searchReserves(params.token);
|
|
2463
|
+
if (results.length === 0) {
|
|
2464
|
+
return ok(JSON.stringify({ status: "no_results", message: `No Aave reserves match '${params.token}'` }));
|
|
2465
|
+
}
|
|
2466
|
+
return ok(JSON.stringify({
|
|
2467
|
+
status: "search_results",
|
|
2468
|
+
reserves: results.map(r => ({
|
|
2469
|
+
symbol: r.symbol,
|
|
2470
|
+
supplyApy: r.supplyApy.toFixed(2) + '%',
|
|
2471
|
+
borrowApy: r.borrowApy.toFixed(2) + '%',
|
|
2472
|
+
ltv: r.ltv.toFixed(0) + '%',
|
|
2473
|
+
price: '$' + r.priceUsd.toFixed(2),
|
|
2474
|
+
borrowingEnabled: r.borrowingEnabled,
|
|
2475
|
+
})),
|
|
2476
|
+
}));
|
|
2477
|
+
} catch (e) { return fail(e); }
|
|
2478
|
+
},
|
|
2479
|
+
});
|
|
2480
|
+
|
|
2481
|
+
// ═══════════════════════════════════════════════════════
|
|
2482
|
+
// TOOL: aave_borrowing_options
|
|
2483
|
+
// ═══════════════════════════════════════════════════════
|
|
2484
|
+
api.registerTool({
|
|
2485
|
+
name: "aave_borrowing_options",
|
|
2486
|
+
description: "Show what you can borrow on Aave V3. Without args: scans wallet for collateral tokens. With collateral: shows options for that token.",
|
|
2487
|
+
parameters: {
|
|
2488
|
+
type: "object",
|
|
2489
|
+
properties: {
|
|
2490
|
+
collateral: { type: "string", description: "Collateral token to check (optional — omit to scan wallet)" },
|
|
2491
|
+
},
|
|
2492
|
+
},
|
|
2493
|
+
async execute(_id: string, params: { collateral?: string }) {
|
|
2494
|
+
try {
|
|
2495
|
+
const cfg = getConfig(api);
|
|
2496
|
+
requireChain(cfg);
|
|
2497
|
+
const client = createAaveClient(cfg);
|
|
2498
|
+
const options = await client.getBorrowingOptions(params.collateral);
|
|
2499
|
+
if (options.length === 0) {
|
|
2500
|
+
return ok(JSON.stringify({
|
|
2501
|
+
status: "no_options",
|
|
2502
|
+
message: params.collateral
|
|
2503
|
+
? `No Aave collateral options for ${params.collateral}`
|
|
2504
|
+
: "No tokens found in wallet that can be used as Aave collateral",
|
|
2505
|
+
}));
|
|
2506
|
+
}
|
|
2507
|
+
return ok(JSON.stringify({
|
|
2508
|
+
status: "borrowing_options",
|
|
2509
|
+
options: options.map(o => ({
|
|
2510
|
+
collateral: o.collateral,
|
|
2511
|
+
balance: o.collateralBalance.toFixed(6),
|
|
2512
|
+
valueUsd: '$' + o.collateralValueUsd.toFixed(2),
|
|
2513
|
+
maxBorrowUsd: '$' + o.maxBorrowUsd.toFixed(2),
|
|
2514
|
+
borrowableTokens: o.borrowable.map(b => ({
|
|
2515
|
+
token: b.symbol,
|
|
2516
|
+
borrowApy: b.borrowApy.toFixed(2) + '%',
|
|
2517
|
+
price: '$' + b.priceUsd.toFixed(2),
|
|
2518
|
+
})),
|
|
2519
|
+
})),
|
|
2520
|
+
}));
|
|
2521
|
+
} catch (e) { return fail(e); }
|
|
2522
|
+
},
|
|
2523
|
+
});
|
|
2524
|
+
|
|
2525
|
+
// ═══════════════════════════════════════════════════════
|
|
2526
|
+
// TOOL: aave_max_borrowable
|
|
2527
|
+
// ═══════════════════════════════════════════════════════
|
|
2528
|
+
api.registerTool({
|
|
2529
|
+
name: "aave_max_borrowable",
|
|
2530
|
+
description: "Calculate max additional borrowable on Aave V3 given current collateral and debt.",
|
|
2531
|
+
parameters: { type: "object", properties: {} },
|
|
2532
|
+
async execute() {
|
|
2533
|
+
try {
|
|
2534
|
+
const cfg = getConfig(api);
|
|
2535
|
+
requireChain(cfg);
|
|
2536
|
+
const client = createAaveClient(cfg);
|
|
2537
|
+
const data = await client.getMaxBorrowable();
|
|
2538
|
+
return ok(JSON.stringify({
|
|
2539
|
+
status: "max_borrowable",
|
|
2540
|
+
availableBorrowUsd: '$' + data.availableBorrowUsd.toFixed(2),
|
|
2541
|
+
currentLtv: data.currentLtv.toFixed(2) + '%',
|
|
2542
|
+
liquidationThreshold: data.liquidationThreshold.toFixed(2) + '%',
|
|
2543
|
+
totalCollateralUsd: '$' + data.totalCollateralUsd.toFixed(2),
|
|
2544
|
+
totalDebtUsd: '$' + data.totalDebtUsd.toFixed(2),
|
|
2545
|
+
}));
|
|
2546
|
+
} catch (e) { return fail(e); }
|
|
2547
|
+
},
|
|
2548
|
+
});
|
|
2549
|
+
|
|
2550
|
+
// ═══════════════════════════════════════════════════════
|
|
2551
|
+
// TOOL: aave_wallet_tokens
|
|
2552
|
+
// ═══════════════════════════════════════════════════════
|
|
2553
|
+
api.registerTool({
|
|
2554
|
+
name: "aave_wallet_tokens",
|
|
2555
|
+
description: "Scan wallet for tokens that exist as Aave V3 reserves. Shows balances in EOA and AgentAccount.",
|
|
2556
|
+
parameters: { type: "object", properties: {} },
|
|
2557
|
+
async execute() {
|
|
2558
|
+
try {
|
|
2559
|
+
const cfg = getConfig(api);
|
|
2560
|
+
requireChain(cfg);
|
|
2561
|
+
const client = createAaveClient(cfg);
|
|
2562
|
+
const tokens = await client.getWalletTokens();
|
|
2563
|
+
if (tokens.length === 0) {
|
|
2564
|
+
return ok(JSON.stringify({ status: "no_tokens", message: "No Aave-compatible tokens found in wallet." }));
|
|
2565
|
+
}
|
|
2566
|
+
return ok(JSON.stringify({
|
|
2567
|
+
status: "wallet_tokens",
|
|
2568
|
+
tokens: tokens.map(t => ({
|
|
2569
|
+
symbol: t.symbol,
|
|
2570
|
+
eoaBalance: t.eoaBalance.toFixed(6),
|
|
2571
|
+
safeBalance: t.safeBalance.toFixed(6),
|
|
2572
|
+
priceUsd: '$' + t.priceUsd.toFixed(2),
|
|
2573
|
+
totalValueUsd: '$' + t.valueUsd.toFixed(2),
|
|
2574
|
+
canSupply: t.canSupply,
|
|
2575
|
+
canBorrow: t.canBorrow,
|
|
2576
|
+
})),
|
|
2577
|
+
}));
|
|
2578
|
+
} catch (e) { return fail(e); }
|
|
2579
|
+
},
|
|
2580
|
+
});
|
|
2581
|
+
|
|
2582
|
+
// ═══════════════════════════════════════════════════════
|
|
2583
|
+
// TOOL: aave_yield_spread
|
|
2584
|
+
// ═══════════════════════════════════════════════════════
|
|
2585
|
+
api.registerTool({
|
|
2586
|
+
name: "aave_yield_spread",
|
|
2587
|
+
description: "Analyze LST/LRT yield vs Aave V3 borrow rates for carry trades. Live APYs from DeFi Llama.",
|
|
2588
|
+
parameters: {
|
|
2589
|
+
type: "object",
|
|
2590
|
+
properties: {
|
|
2591
|
+
token: { type: "string", description: "Filter by collateral token (optional)" },
|
|
2592
|
+
},
|
|
2593
|
+
},
|
|
2594
|
+
async execute(_id: string, params: { token?: string }) {
|
|
2595
|
+
try {
|
|
2596
|
+
const cfg = getConfig(api);
|
|
2597
|
+
requireChain(cfg);
|
|
2598
|
+
const client = createAaveClient(cfg);
|
|
2599
|
+
const spreads = await client.getYieldSpread();
|
|
2600
|
+
const filtered = params.token
|
|
2601
|
+
? spreads.filter((s: any) => s.collateralToken.toLowerCase() === params.token!.toLowerCase())
|
|
2602
|
+
: spreads;
|
|
2603
|
+
|
|
2604
|
+
if (filtered.length === 0) {
|
|
2605
|
+
return ok(JSON.stringify({ status: "no_lst_markets", message: "No LST carry trade opportunities on Aave." }));
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
return ok(JSON.stringify({
|
|
2609
|
+
status: "aave_yield_spread",
|
|
2610
|
+
markets: filtered.map((s: any) => ({
|
|
2611
|
+
collateral: s.collateralToken,
|
|
2612
|
+
loan: s.loanToken,
|
|
2613
|
+
collateralYield: s.collateralYield + '%',
|
|
2614
|
+
borrowRate: s.borrowRate.toFixed(2) + '%',
|
|
2615
|
+
netSpread: (s.netSpread > 0 ? '+' : '') + s.netSpread.toFixed(2) + '%',
|
|
2616
|
+
profitable: s.profitable ? 'yes' : 'no',
|
|
2617
|
+
maxLeverage: s.maxSafeLeverage + 'x',
|
|
2618
|
+
})),
|
|
2619
|
+
}));
|
|
2620
|
+
} catch (e) { return fail(e); }
|
|
2621
|
+
},
|
|
2622
|
+
});
|
|
2623
|
+
|
|
2624
|
+
// ═══════════════════════════════════════════════════════
|
|
2625
|
+
// TOOL: aave_repay_and_withdraw
|
|
2626
|
+
// ═══════════════════════════════════════════════════════
|
|
2627
|
+
api.registerTool({
|
|
2628
|
+
name: "aave_repay_and_withdraw",
|
|
2629
|
+
description: "Repay all debt and withdraw all collateral from Aave V3 in one atomic batch. Full position exit.",
|
|
2630
|
+
parameters: {
|
|
2631
|
+
type: "object",
|
|
2632
|
+
properties: {
|
|
2633
|
+
repayToken: { type: "string", description: "Token to repay (e.g. 'USDC')" },
|
|
2634
|
+
withdrawToken: { type: "string", description: "Token to withdraw (e.g. 'wstETH')" },
|
|
2635
|
+
},
|
|
2636
|
+
required: ["repayToken", "withdrawToken"],
|
|
2637
|
+
},
|
|
2638
|
+
async execute(_id: string, params: { repayToken: string; withdrawToken: string }) {
|
|
2639
|
+
try {
|
|
2640
|
+
const cfg = getConfig(api);
|
|
2641
|
+
requireChain(cfg);
|
|
2642
|
+
const client = createAaveClient(cfg);
|
|
2643
|
+
const receipt = await client.repayAndWithdraw(params.repayToken, params.withdrawToken);
|
|
2644
|
+
const explorer = cfg.chainId === 8453 ? 'https://basescan.org/tx/' : 'https://etherscan.io/tx/';
|
|
2645
|
+
return ok(JSON.stringify({
|
|
2646
|
+
status: "position_closed",
|
|
2647
|
+
repaid: 'all ' + params.repayToken,
|
|
2648
|
+
withdrawn: 'all ' + params.withdrawToken,
|
|
2649
|
+
tx: explorer + receipt.hash,
|
|
2650
|
+
}));
|
|
2651
|
+
} catch (e) { return fail(e); }
|
|
2652
|
+
},
|
|
2653
|
+
});
|
|
2654
|
+
|
|
2655
|
+
|
|
2128
2656
|
// ═══════════════════════════════════════════════════════
|
|
2129
2657
|
// SLASH COMMANDS (no AI needed)
|
|
2130
2658
|
// ═══════════════════════════════════════════════════════
|