@agether/agether 2.11.0 → 2.12.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/skills/agether/SKILL.md +49 -1
- package/src/index.ts +170 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agether/agether",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.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": "^2.
|
|
12
|
+
"@agether/sdk": "^2.14.0",
|
|
13
13
|
"axios": "^1.6.0",
|
|
14
14
|
"ethers": "^6.9.0"
|
|
15
15
|
},
|
package/skills/agether/SKILL.md
CHANGED
|
@@ -38,7 +38,8 @@ If you don't paste it, the user sees NOTHING. An empty colon ":" with no data af
|
|
|
38
38
|
13. **To get USDC for x402:** call `morpho_deposit_and_borrow` with collateral from your EOA. Do NOT ask the user to send tokens — check your balance first.
|
|
39
39
|
14. **Check health before large actions.** Before borrowing, depositing, or withdrawing significant amounts, call `agether_health` to see current LTV and headroom. This prevents failed transactions.
|
|
40
40
|
15. **Batch awareness:** `morpho_deposit_and_borrow` is a batched operation (deposit + borrow in one tx). Always prefer it over separate `morpho_deposit` then `morpho_borrow` when doing both — it saves gas and is atomic.
|
|
41
|
-
16. **Collateral and loan tokens are dynamic.** Don't hardcode tokens.
|
|
41
|
+
16. **Collateral and loan tokens are dynamic.** Don't hardcode tokens. Use `morpho_search` to find any token by name, `morpho_borrowing_options` to discover what the user can borrow, and `morpho_markets` to list all markets. The SDK searches Morpho's full GraphQL registry — no token is "unsupported" unless it truly has no market.
|
|
42
|
+
17. **Never say "token X is not supported" without searching first.** Always call `morpho_search(token: "X")` before telling the user a token isn't available. The registry has 500+ markets.
|
|
42
43
|
17. **Withdrawals stay in AgentAccount by default.** `morpho_withdraw` and `morpho_withdraw_supply` keep funds in the Safe account unless `toEoa: true` is passed. Use `wallet_withdraw_token` / `wallet_withdraw_eth` to move any token or ETH from AgentAccount to EOA.
|
|
43
44
|
18. **Always show Health Factor when reporting positions.** HF = LLTV / LTV. HF > 1.15 = safe 🟢, HF 1.0–1.15 = warning 🟡, HF ≤ 1.0 = liquidation 🔴. `morpho_status` returns HF per position. Always paste it so the user understands their risk.
|
|
44
45
|
|
|
@@ -135,6 +136,10 @@ Both `agether_set_agent` and `agether_register` save the agentId to config perma
|
|
|
135
136
|
|------|--------|-------------|
|
|
136
137
|
| `morpho_status` | none | Show all Morpho positions — collateral, debt, LTV, **Health Factor** (HF), headroom, risk level per market |
|
|
137
138
|
| `morpho_markets` | `token?`, `loanToken?` | List all Morpho Blue markets — supply/borrow APY, utilization, LLTV, liquidity. Optional collateral or loan token filter. |
|
|
139
|
+
| `morpho_search` | `token`, `asCollateral?`, `asLoanToken?` | **Search Morpho markets by token name** (fuzzy). Use when user asks about a specific token (ezETH, rETH, wstETH, etc.). No hardcoded list — searches full registry. |
|
|
140
|
+
| `morpho_borrowing_options` | `collateral?` | **"What can I borrow?"** Without args: scans wallet for tokens with balance > 0, finds matching collateral markets. With `collateral`: finds all markets for that token. |
|
|
141
|
+
| `morpho_supply_options` | `loanToken` | **"Where can I lend X?"** Shows all markets where the token is the loan asset (user supplies to earn yield). |
|
|
142
|
+
| `morpho_wallet_tokens` | none | **Scan wallet** for all ERC-20 tokens that exist in Morpho markets. Shows every token with balance > 0. |
|
|
138
143
|
| `morpho_max_borrowable` | none | Calculate max additional loan token borrowable given current collateral/debt across all markets |
|
|
139
144
|
| `morpho_deposit` | `amount`, `token` | Deposit collateral from EOA → Morpho (no borrow). Token auto-discovered. |
|
|
140
145
|
| `morpho_deposit_and_borrow` | `collateralAmount`, `token`, `borrowAmount`, `loanToken?` | **PREFERRED** — Deposit + borrow in one batched tx (ERC-7579 batch mode). Supports any loan token. Best for first-time setup. |
|
|
@@ -292,6 +297,49 @@ For supply positions (lent tokens):
|
|
|
292
297
|
3. Suggest optimal strategy based on their holdings
|
|
293
298
|
```
|
|
294
299
|
|
|
300
|
+
### User asks "what can I borrow?" or "what can I do with my tokens?"
|
|
301
|
+
```
|
|
302
|
+
IF user specifies a token (e.g. "what can I borrow with WETH?"):
|
|
303
|
+
→ morpho_borrowing_options(collateral: "WETH")
|
|
304
|
+
→ Shows all markets where WETH is collateral + available loan tokens
|
|
305
|
+
|
|
306
|
+
IF user asks generally ("what can I borrow?"):
|
|
307
|
+
→ morpho_borrowing_options() ← no args = wallet scan mode
|
|
308
|
+
→ Scans wallet for all tokens with balance > 0
|
|
309
|
+
→ For each token, finds markets where it can be collateral
|
|
310
|
+
→ Shows options grouped by collateral token with APYs
|
|
311
|
+
|
|
312
|
+
IF no tokens found in wallet:
|
|
313
|
+
→ Tell user: "Your wallet is empty. Send tokens to <EOA address>"
|
|
314
|
+
→ morpho_markets to show which collateral tokens are accepted
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### User asks "where can I put X as collateral?" or "are there ezETH markets?"
|
|
318
|
+
```
|
|
319
|
+
1. morpho_search(token: "ezETH", asCollateral: true)
|
|
320
|
+
→ Searches Morpho's full registry (not just cached top markets)
|
|
321
|
+
→ Shows all markets where ezETH is collateral
|
|
322
|
+
2. IF no results → "No markets for ezETH on this chain."
|
|
323
|
+
3. IF results → present the markets with APYs, LLTVs, liquidity
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### User asks "what can I supply?" or "where can I lend USDC?"
|
|
327
|
+
```
|
|
328
|
+
1. morpho_supply_options(loanToken: "USDC")
|
|
329
|
+
→ Shows all markets where USDC is the loan token
|
|
330
|
+
→ User supplies USDC to earn yield from borrowers
|
|
331
|
+
2. Present: sorted by supply APY (highest first)
|
|
332
|
+
3. Suggest the most liquid market with best APY
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### User asks "what tokens do I have?" or "what's in my wallet?"
|
|
336
|
+
```
|
|
337
|
+
1. morpho_wallet_tokens() ← scans all ERC-20s from Morpho markets
|
|
338
|
+
→ Returns every token with balance > 0 (symbol + amount + address)
|
|
339
|
+
2. Present the list clearly
|
|
340
|
+
3. Optionally follow up with morpho_borrowing_options() to show what they can do
|
|
341
|
+
```
|
|
342
|
+
|
|
295
343
|
### User asks to check or refresh credit score
|
|
296
344
|
```
|
|
297
345
|
1. IF user says "refresh" / "update" / "get new score":
|
package/src/index.ts
CHANGED
|
@@ -958,6 +958,176 @@ export default function register(api: any) {
|
|
|
958
958
|
},
|
|
959
959
|
});
|
|
960
960
|
|
|
961
|
+
// ═══════════════════════════════════════════════════════
|
|
962
|
+
// TOOL: morpho_search (Morpho GraphQL search — find any token)
|
|
963
|
+
// ═══════════════════════════════════════════════════════
|
|
964
|
+
api.registerTool({
|
|
965
|
+
name: "morpho_search",
|
|
966
|
+
description:
|
|
967
|
+
"Search Morpho markets by token name. Use this when the user asks about a specific token " +
|
|
968
|
+
"(e.g. 'ezETH', 'wstETH', 'rETH', 'cbBTC') to find all markets where it appears. " +
|
|
969
|
+
"No hardcoded list — searches Morpho's full market registry.",
|
|
970
|
+
parameters: {
|
|
971
|
+
type: "object",
|
|
972
|
+
properties: {
|
|
973
|
+
token: { type: "string", description: "Token name or symbol to search for (e.g. 'WETH', 'ezETH', 'wstETH')" },
|
|
974
|
+
asCollateral: { type: "boolean", description: "Only show markets where token is used as collateral (default: false)" },
|
|
975
|
+
asLoanToken: { type: "boolean", description: "Only show markets where token is the loan asset (default: false)" },
|
|
976
|
+
},
|
|
977
|
+
required: ["token"],
|
|
978
|
+
},
|
|
979
|
+
async execute(_id: string, params: { token: string; asCollateral?: boolean; asLoanToken?: boolean }) {
|
|
980
|
+
try {
|
|
981
|
+
const cfg = getConfig(api);
|
|
982
|
+
const client = createMorphoClient(cfg);
|
|
983
|
+
const results = await client.searchMarkets(params.token, {
|
|
984
|
+
asCollateral: params.asCollateral,
|
|
985
|
+
asLoanToken: params.asLoanToken,
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
if (results.length === 0) return ok(`No markets found for "${params.token}" on this chain.`);
|
|
989
|
+
|
|
990
|
+
const formatted = results.map((r: any) => ({
|
|
991
|
+
collateral: r.collateralToken,
|
|
992
|
+
loan: r.loanToken,
|
|
993
|
+
lltv: r.lltv,
|
|
994
|
+
supplyApy: `${(r.supplyApy * 100).toFixed(2)}%`,
|
|
995
|
+
borrowApy: `${(r.borrowApy * 100).toFixed(2)}%`,
|
|
996
|
+
utilization: `${(r.utilization * 100).toFixed(1)}%`,
|
|
997
|
+
totalSupply: `$${r.totalSupplyUsd.toFixed(0)}`,
|
|
998
|
+
totalBorrow: `$${r.totalBorrowUsd.toFixed(0)}`,
|
|
999
|
+
}));
|
|
1000
|
+
|
|
1001
|
+
return ok(JSON.stringify(formatted, null, 2));
|
|
1002
|
+
} catch (e) { return fail(e); }
|
|
1003
|
+
},
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
// ═══════════════════════════════════════════════════════
|
|
1007
|
+
// TOOL: morpho_borrowing_options (wallet scan → matching markets)
|
|
1008
|
+
// ═══════════════════════════════════════════════════════
|
|
1009
|
+
api.registerTool({
|
|
1010
|
+
name: "morpho_borrowing_options",
|
|
1011
|
+
description:
|
|
1012
|
+
"Find what the agent can borrow. " +
|
|
1013
|
+
"Without arguments: scans wallet for all tokens with balance > 0, then finds Morpho markets " +
|
|
1014
|
+
"where each token can be used as collateral. " +
|
|
1015
|
+
"With 'collateral' argument: finds all markets for that specific collateral token. " +
|
|
1016
|
+
"Use this when user asks 'what can I borrow?', 'where can I put X as collateral?', " +
|
|
1017
|
+
"'what can I borrow with my WETH?'",
|
|
1018
|
+
parameters: {
|
|
1019
|
+
type: "object",
|
|
1020
|
+
properties: {
|
|
1021
|
+
collateral: {
|
|
1022
|
+
type: "string",
|
|
1023
|
+
description: "Specific collateral token to check (e.g. 'WETH', 'ezETH'). If omitted, scans wallet for all tokens.",
|
|
1024
|
+
},
|
|
1025
|
+
},
|
|
1026
|
+
required: [],
|
|
1027
|
+
},
|
|
1028
|
+
async execute(_id: string, params: { collateral?: string }) {
|
|
1029
|
+
try {
|
|
1030
|
+
const cfg = getConfig(api);
|
|
1031
|
+
const client = createMorphoClient(cfg);
|
|
1032
|
+
const options = await client.findBorrowingOptions(params.collateral);
|
|
1033
|
+
|
|
1034
|
+
if (options.length === 0) {
|
|
1035
|
+
if (params.collateral) {
|
|
1036
|
+
return ok(`No borrowing markets found for ${params.collateral} as collateral on this chain.`);
|
|
1037
|
+
}
|
|
1038
|
+
return ok("No tokens with balance > 0 found in the agent wallet, or no matching Morpho markets exist.");
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// Format for LLM readability
|
|
1042
|
+
const formatted = options.map(opt => ({
|
|
1043
|
+
collateralToken: opt.collateralToken,
|
|
1044
|
+
walletBalance: opt.collateralBalance,
|
|
1045
|
+
availableMarkets: opt.markets.map(m => ({
|
|
1046
|
+
borrow: m.loanToken,
|
|
1047
|
+
borrowApy: m.borrowApy,
|
|
1048
|
+
lltv: m.lltv,
|
|
1049
|
+
utilization: m.utilization,
|
|
1050
|
+
availableLiquidity: m.availableLiquidity,
|
|
1051
|
+
})),
|
|
1052
|
+
}));
|
|
1053
|
+
|
|
1054
|
+
return ok(JSON.stringify(formatted, null, 2));
|
|
1055
|
+
} catch (e) { return fail(e); }
|
|
1056
|
+
},
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
// ═══════════════════════════════════════════════════════
|
|
1060
|
+
// TOOL: morpho_supply_options (find lending opportunities)
|
|
1061
|
+
// ═══════════════════════════════════════════════════════
|
|
1062
|
+
api.registerTool({
|
|
1063
|
+
name: "morpho_supply_options",
|
|
1064
|
+
description:
|
|
1065
|
+
"Find supply/lending opportunities for a specific loan token. " +
|
|
1066
|
+
"Use when user asks 'what can I supply to earn WETH?', 'where can I lend USDC?', " +
|
|
1067
|
+
"'what supply APY is available for USDC?'. " +
|
|
1068
|
+
"Shows all markets where the specified token is the loan asset (user supplies it to earn yield).",
|
|
1069
|
+
parameters: {
|
|
1070
|
+
type: "object",
|
|
1071
|
+
properties: {
|
|
1072
|
+
loanToken: { type: "string", description: "The token to supply/lend (e.g. 'USDC', 'WETH')" },
|
|
1073
|
+
},
|
|
1074
|
+
required: ["loanToken"],
|
|
1075
|
+
},
|
|
1076
|
+
async execute(_id: string, params: { loanToken: string }) {
|
|
1077
|
+
try {
|
|
1078
|
+
const cfg = getConfig(api);
|
|
1079
|
+
const client = createMorphoClient(cfg);
|
|
1080
|
+
const options = await client.findSupplyOptions(params.loanToken);
|
|
1081
|
+
|
|
1082
|
+
if (options.length === 0) return ok(`No supply markets found for ${params.loanToken} on this chain.`);
|
|
1083
|
+
|
|
1084
|
+
const formatted = options.map((m: any) => ({
|
|
1085
|
+
collateral: m.collateralToken,
|
|
1086
|
+
loan: m.loanToken,
|
|
1087
|
+
supplyApy: m.supplyApy,
|
|
1088
|
+
lltv: m.lltv,
|
|
1089
|
+
utilization: m.utilization,
|
|
1090
|
+
totalSupply: m.totalSupply,
|
|
1091
|
+
}));
|
|
1092
|
+
|
|
1093
|
+
return ok(JSON.stringify(formatted, null, 2));
|
|
1094
|
+
} catch (e) { return fail(e); }
|
|
1095
|
+
},
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
// ═══════════════════════════════════════════════════════
|
|
1099
|
+
// TOOL: morpho_wallet_tokens (scan wallet for all token balances)
|
|
1100
|
+
// ═══════════════════════════════════════════════════════
|
|
1101
|
+
api.registerTool({
|
|
1102
|
+
name: "morpho_wallet_tokens",
|
|
1103
|
+
description:
|
|
1104
|
+
"Scan the agent's wallet for all ERC-20 tokens that exist in Morpho markets. " +
|
|
1105
|
+
"Shows every token with balance > 0. Use this when user asks 'what tokens do I have?', " +
|
|
1106
|
+
"'what's in my wallet?', 'what can I use?'.",
|
|
1107
|
+
parameters: {
|
|
1108
|
+
type: "object",
|
|
1109
|
+
properties: {},
|
|
1110
|
+
required: [],
|
|
1111
|
+
},
|
|
1112
|
+
async execute(_id: string) {
|
|
1113
|
+
try {
|
|
1114
|
+
const cfg = getConfig(api);
|
|
1115
|
+
const client = createMorphoClient(cfg);
|
|
1116
|
+
const tokens = await client.getWalletTokenBalances();
|
|
1117
|
+
|
|
1118
|
+
if (tokens.length === 0) return ok("No tokens with balance > 0 found in the agent wallet.");
|
|
1119
|
+
|
|
1120
|
+
const formatted = tokens.map(t => ({
|
|
1121
|
+
token: t.symbol,
|
|
1122
|
+
balance: t.balanceFormatted,
|
|
1123
|
+
address: t.address,
|
|
1124
|
+
}));
|
|
1125
|
+
|
|
1126
|
+
return ok(JSON.stringify(formatted, null, 2));
|
|
1127
|
+
} catch (e) { return fail(e); }
|
|
1128
|
+
},
|
|
1129
|
+
});
|
|
1130
|
+
|
|
961
1131
|
// ═══════════════════════════════════════════════════════
|
|
962
1132
|
// TOOL: agether_score (backend API — x402 gated)
|
|
963
1133
|
// ═══════════════════════════════════════════════════════
|