@agether/agether 2.3.0 → 2.4.0
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/openclaw.plugin.json +8 -7
- package/package.json +3 -3
- package/skills/agether/SKILL.md +158 -52
- package/src/index.ts +112 -33
package/openclaw.plugin.json
CHANGED
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
"id": "agether",
|
|
3
3
|
"name": "Agether Credit",
|
|
4
4
|
"description": "Onchain credit protocol for AI agents — Morpho-backed overcollateralized credit, ERC-8004 identity, x402 payments. Private key and RPC keys are read from OpenClaw secrets (env vars); no plaintext config needed.",
|
|
5
|
-
"version": "2.3.
|
|
5
|
+
"version": "2.3.1",
|
|
6
6
|
"skills": ["skills/agether"],
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|
|
9
9
|
"additionalProperties": false,
|
|
10
10
|
"properties": {
|
|
11
|
+
"chain": {
|
|
12
|
+
"type": "number",
|
|
13
|
+
"description": "Chain ID: 1 = Ethereum (default), 8453 = Base",
|
|
14
|
+
"default": 1,
|
|
15
|
+
"enum": [1, 8453]
|
|
16
|
+
},
|
|
11
17
|
"agentId": {
|
|
12
18
|
"type": "string",
|
|
13
19
|
"description": "ERC-8004 agent ID (set after registration, auto-saved by tools)"
|
|
@@ -27,11 +33,6 @@
|
|
|
27
33
|
"description": "Daily USDC spending cap for x402 auto-draw payments (0 = unlimited). Persisted to cache file so it survives restarts.",
|
|
28
34
|
"default": 0
|
|
29
35
|
},
|
|
30
|
-
"autoDrawBuffer": {
|
|
31
|
-
"type": "number",
|
|
32
|
-
"description": "Extra USDC buffer when auto-drawing from Morpho (e.g. 0.5 = borrow $0.50 extra)",
|
|
33
|
-
"default": 0
|
|
34
|
-
},
|
|
35
36
|
"healthAlertThreshold": {
|
|
36
37
|
"type": "number",
|
|
37
38
|
"description": "LTV percentage threshold for health warnings (e.g. 70 = warn at 70% LTV, liquidation at 80%)",
|
|
@@ -41,11 +42,11 @@
|
|
|
41
42
|
"required": []
|
|
42
43
|
},
|
|
43
44
|
"uiHints": {
|
|
45
|
+
"chain": { "label": "Chain", "placeholder": "1 (Ethereum)" },
|
|
44
46
|
"agentId": { "label": "Agent ID", "placeholder": "17676" },
|
|
45
47
|
"autoDraw": { "label": "Auto-Draw Credit", "placeholder": "false" },
|
|
46
48
|
"autoYield": { "label": "Auto-Yield (use yield before borrowing)", "placeholder": "false" },
|
|
47
49
|
"dailySpendLimitUsdc": { "label": "Daily Spend Limit (USDC)", "placeholder": "0" },
|
|
48
|
-
"autoDrawBuffer": { "label": "Auto-Draw Buffer (USDC)", "placeholder": "0" },
|
|
49
50
|
"healthAlertThreshold": { "label": "Health Alert Threshold (%)", "placeholder": "70" }
|
|
50
51
|
}
|
|
51
52
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agether/agether",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "OpenClaw plugin for Agether — onchain credit for AI agents",
|
|
3
|
+
"version": "2.4.0",
|
|
4
|
+
"description": "OpenClaw plugin for Agether — onchain credit for AI agents on Ethereum & Base",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"openclaw": {
|
|
7
7
|
"extensions": [
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
]
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@agether/sdk": "^2.
|
|
12
|
+
"@agether/sdk": "^2.7.0",
|
|
13
13
|
"axios": "^1.6.0",
|
|
14
14
|
"ethers": "^6.9.0"
|
|
15
15
|
},
|
package/skills/agether/SKILL.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agether
|
|
3
|
-
description: On-chain credit protocol for AI agents on Base. Morpho credit, x402 payments, ERC-8004 identity.
|
|
3
|
+
description: On-chain credit protocol for AI agents on Base. Morpho credit & lending, x402 payments, ERC-8004 identity.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Agether — On-Chain Credit for AI Agents
|
|
7
7
|
|
|
8
|
-
You are an AI agent with on-chain financial capabilities on **Base mainnet**. You can
|
|
8
|
+
You are an AI agent with on-chain financial capabilities on **Base mainnet**. You can borrow USDC, earn yield by lending, and pay for APIs autonomously.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -37,6 +37,9 @@ If you don't paste it, the user sees NOTHING. An empty colon ":" with no data af
|
|
|
37
37
|
12. **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.
|
|
38
38
|
13. **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.
|
|
39
39
|
14. **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.
|
|
40
|
+
15. **Collateral tokens are dynamic.** Don't hardcode "WETH/wstETH/cbETH". Call `morpho_markets` to discover which tokens are available. The SDK auto-discovers tokens from Morpho GraphQL API.
|
|
41
|
+
16. **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.
|
|
42
|
+
17. **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.
|
|
40
43
|
|
|
41
44
|
---
|
|
42
45
|
|
|
@@ -67,42 +70,84 @@ Both `agether_set_agent` and `agether_register` save the agentId to config perma
|
|
|
67
70
|
| `agether_health` | **START HERE.** Comprehensive check: balances, all positions with LTV & liquidation risk, borrowing headroom, alerts — all in one call. |
|
|
68
71
|
| `agether_preflight` | Setup readiness check: private key present? RPC working? Agent registered? Balances OK? Returns pass/fail checklist. |
|
|
69
72
|
|
|
70
|
-
### Identity
|
|
73
|
+
### Identity
|
|
71
74
|
| Tool | What it does |
|
|
72
75
|
|------|-------------|
|
|
73
|
-
| `agether_balance` | Show ETH + USDC + collateral
|
|
76
|
+
| `agether_balance` | Show ETH + USDC + all collateral token balances for both EOA wallet and AgentAccount (Safe). Tokens auto-discovered from markets. |
|
|
74
77
|
| `agether_register` | Register on-chain: mints ERC-8004 identity NFT + creates Safe account (via Safe7579). Auto-saves agentId to config. |
|
|
75
78
|
| `agether_set_agent` | Set a known agentId (e.g. from memory) and save to config. Use when agentId is "?" but you remember it. |
|
|
76
79
|
| `agether_score` | Get credit score. `refresh: false` = free read. `refresh: true` = pays x402, computes fresh score on-chain. **Always call this when user asks about score.** |
|
|
77
|
-
| `
|
|
80
|
+
| `agether_kya_status` | Check if KYA code verification is required for this deployment. |
|
|
81
|
+
| `agether_set_kya` | Enable or disable KYA verification gate (owner only). |
|
|
78
82
|
|
|
79
|
-
###
|
|
83
|
+
### Wallet (move funds between EOA ↔ AgentAccount)
|
|
80
84
|
| Tool | Params | What it does |
|
|
81
85
|
|------|--------|-------------|
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
86
|
+
| `wallet_fund` | `amount` | Transfer USDC from EOA → AgentAccount |
|
|
87
|
+
| `wallet_withdraw_token` | `token`, `amount` | Withdraw any ERC-20 token from AgentAccount → EOA. Use `amount: "all"` for full balance. |
|
|
88
|
+
| `wallet_withdraw_eth` | `amount` | Withdraw ETH from AgentAccount → EOA. Use `amount: "all"` for full balance. |
|
|
89
|
+
|
|
90
|
+
### Morpho Borrowing (Overcollateralized — instant, no approval needed)
|
|
91
|
+
| Tool | Params | What it does |
|
|
92
|
+
|------|--------|-------------|
|
|
93
|
+
| `morpho_status` | none | Show all Morpho positions — collateral, debt, LTV, **Health Factor** (HF), headroom, risk level per market |
|
|
94
|
+
| `morpho_markets` | `token?` | List Morpho Blue USDC markets — supply/borrow APY, utilization, LLTV, liquidity. Optional token filter. |
|
|
85
95
|
| `morpho_max_borrowable` | none | Calculate max additional USDC borrowable given current collateral/debt |
|
|
86
|
-
| `
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
|
|
96
|
+
| `morpho_deposit` | `amount`, `token` | Deposit collateral from EOA → Morpho (no borrow). Token auto-discovered. |
|
|
97
|
+
| `morpho_deposit_and_borrow` | `collateralAmount`, `token`, `borrowAmount` | **PREFERRED** — Deposit + borrow in one batched tx (ERC-7579 batch mode). Best for first-time setup. |
|
|
98
|
+
| `morpho_borrow` | `amount`, `token?` | Borrow USDC against existing collateral → lands in AgentAccount. Token auto-detected. |
|
|
99
|
+
| `morpho_repay` | `amount`, `token?` | Repay USDC debt. Use `amount: "all"` to clear dust shares. |
|
|
100
|
+
| `morpho_withdraw` | `amount`, `token`, `toEoa?` | Withdraw collateral from Morpho. Default: stays in AgentAccount. `toEoa: true` → send to EOA wallet. |
|
|
101
|
+
| `morpho_sponsor` | `agentId`/`agentAddress`, `amount`, `token` | Transfer collateral to another agent's AgentAccount. |
|
|
102
|
+
|
|
103
|
+
### Morpho Lending (Supply-side — earn yield)
|
|
104
|
+
| Tool | Params | What it does |
|
|
105
|
+
|------|--------|-------------|
|
|
106
|
+
| `morpho_supply` | `amount`, `market?` | Supply USDC as a LENDER to earn yield from borrowers. Auto-picks highest APY market if no market specified. |
|
|
107
|
+
| `morpho_supply_status` | `market?` | Show supply (lending) positions with earned yield. Tracks yield on-chain — no database needed. |
|
|
108
|
+
| `morpho_withdraw_supply` | `amount`, `market?`, `toEoa?` | Withdraw supplied USDC (principal + earned interest). Default: stays in AgentAccount. `toEoa: true` → send to EOA. |
|
|
93
109
|
|
|
94
110
|
### x402 Payments
|
|
95
111
|
| Tool | Params | What it does |
|
|
96
112
|
|------|--------|-------------|
|
|
97
|
-
| `x402_pay` | `url`, `method?`, `body
|
|
113
|
+
| `x402_pay` | `url`, `method?`, `body?` | Make a paid API call via x402 protocol. Pays with USDC via EIP-3009 from AgentAccount. If USDC is low, auto-sources: yield first (autoYield), then borrow (autoDraw). |
|
|
98
114
|
|
|
99
115
|
### Slash Commands (user types these — no AI invocation)
|
|
100
116
|
| Command | What it does |
|
|
101
117
|
|---------|-------------|
|
|
102
|
-
| `/balance` | Quick balance check |
|
|
103
|
-
| `/morpho` | Quick Morpho position summary |
|
|
118
|
+
| `/balance` | Quick balance check (shows all non-zero balances) |
|
|
119
|
+
| `/morpho` | Quick Morpho position summary with Health Factor |
|
|
104
120
|
| `/health` | Quick position health: LTV, liquidation risk, balances |
|
|
105
|
-
| `/rates` | Current Morpho market rates |
|
|
121
|
+
| `/rates` | Current Morpho market rates (supply APY, borrow APY, utilization) |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## ⚙️ PLUGIN CONFIGURATION
|
|
126
|
+
|
|
127
|
+
These settings are in `openclaw.json` under `plugins.entries.agether.config`:
|
|
128
|
+
|
|
129
|
+
| Setting | Type | Default | Description |
|
|
130
|
+
|---------|------|---------|-------------|
|
|
131
|
+
| `agentId` | string | — | ERC-8004 agent ID (auto-saved by register/set_agent tools) |
|
|
132
|
+
| `autoDraw` | boolean | `false` | Auto-borrow from Morpho when USDC is low for x402 payments |
|
|
133
|
+
| `autoYield` | boolean | `false` | Auto-withdraw earned yield before borrowing. Waterfall: balance → yield → borrow |
|
|
134
|
+
| `dailySpendLimitUsdc` | number | `0` | Daily spending cap for x402 auto-draw (0 = unlimited). Persisted to cache file. |
|
|
135
|
+
| `healthAlertThreshold` | number | `70` | LTV % threshold for health warnings in `agether_health` and `/health` (liquidation at 80%). Also controls 🟡 vs 🟢 icons. |
|
|
136
|
+
|
|
137
|
+
### x402 Auto-Funding Waterfall
|
|
138
|
+
When `autoYield` and/or `autoDraw` are enabled, `x402_pay` automatically sources USDC:
|
|
139
|
+
```
|
|
140
|
+
1. Check AgentAccount USDC balance
|
|
141
|
+
→ If enough → pay directly (no extra tx)
|
|
142
|
+
2. If autoYield enabled AND supply positions have earned yield:
|
|
143
|
+
→ Withdraw yield from supply position (1 tx)
|
|
144
|
+
→ Pay with that
|
|
145
|
+
3. If still not enough AND autoDraw enabled AND collateral deposited in Morpho:
|
|
146
|
+
→ Borrow from Morpho credit line (1 tx)
|
|
147
|
+
→ Pay with that
|
|
148
|
+
4. If dailySpendLimitUsdc > 0:
|
|
149
|
+
→ Enforce daily cap (resets at midnight UTC, persisted to disk)
|
|
150
|
+
```
|
|
106
151
|
|
|
107
152
|
---
|
|
108
153
|
|
|
@@ -120,18 +165,24 @@ Both `agether_set_agent` and `agether_register` save the agentId to config perma
|
|
|
120
165
|
|
|
121
166
|
### User asks to call a paid API (x402)
|
|
122
167
|
```
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
168
|
+
IF autoYield or autoDraw are configured:
|
|
169
|
+
→ x402_pay(url) ← the waterfall handles everything automatically
|
|
170
|
+
→ Paste: response data, payment info, any auto-fund actions taken
|
|
171
|
+
|
|
172
|
+
IF no auto-funding configured:
|
|
173
|
+
1. agether_health ← get full picture
|
|
174
|
+
2. Look at balances.agentAccount.usdc:
|
|
175
|
+
IF USDC ≥ $0.01:
|
|
176
|
+
→ x402_pay(url)
|
|
177
|
+
3. IF no USDC but positions exist with headroom:
|
|
178
|
+
→ morpho_borrow(amount: "1") ← borrow $1
|
|
179
|
+
→ x402_pay(url)
|
|
180
|
+
4. IF no USDC AND no positions BUT EOA has collateral:
|
|
181
|
+
→ morpho_deposit_and_borrow(collateralAmount, token, borrowAmount: "1")
|
|
182
|
+
→ x402_pay(url)
|
|
183
|
+
5. IF nothing at all:
|
|
184
|
+
→ Tell user: "Need collateral on Base. Send to <EOA address>"
|
|
185
|
+
→ Call morpho_markets to show which tokens are accepted
|
|
135
186
|
```
|
|
136
187
|
|
|
137
188
|
### User wants to borrow USDC via Morpho
|
|
@@ -145,14 +196,40 @@ Both `agether_set_agent` and `agether_register` save the agentId to config perma
|
|
|
145
196
|
5. Show: tx hash, collateral deposited, USDC borrowed, new balances, new LTV
|
|
146
197
|
```
|
|
147
198
|
|
|
199
|
+
### User wants to earn yield (supply-side lending)
|
|
200
|
+
```
|
|
201
|
+
1. Check USDC availability:
|
|
202
|
+
- agether_health for AgentAccount USDC
|
|
203
|
+
- If no USDC in AgentAccount but exists in EOA → wallet_fund first
|
|
204
|
+
2. morpho_markets ← show supply APYs to pick best market
|
|
205
|
+
3. morpho_supply(amount, market?) ← supply USDC to earn yield
|
|
206
|
+
4. Later: morpho_supply_status ← check earned yield
|
|
207
|
+
5. To exit: morpho_withdraw_supply("all") ← principal + earned interest
|
|
208
|
+
```
|
|
209
|
+
|
|
148
210
|
### User wants to repay + withdraw
|
|
149
211
|
```
|
|
150
212
|
1. agether_health ← check current debt, collateral, LTV
|
|
151
213
|
2. morpho_repay(amount or "all") ← repay USDC
|
|
152
|
-
3. morpho_withdraw("all", token) ← get collateral back
|
|
214
|
+
3. morpho_withdraw("all", token, toEoa: true) ← get collateral back to EOA
|
|
153
215
|
4. agether_balance ← show final balances
|
|
154
216
|
```
|
|
155
217
|
|
|
218
|
+
### User wants to move funds to EOA
|
|
219
|
+
```
|
|
220
|
+
For tokens (USDC, WETH, etc.):
|
|
221
|
+
→ wallet_withdraw_token(token, amount) ← any ERC-20
|
|
222
|
+
|
|
223
|
+
For ETH:
|
|
224
|
+
→ wallet_withdraw_eth(amount)
|
|
225
|
+
|
|
226
|
+
For Morpho collateral:
|
|
227
|
+
→ morpho_withdraw(amount, token, toEoa: true) ← must use toEoa flag
|
|
228
|
+
|
|
229
|
+
For supply positions (lent USDC):
|
|
230
|
+
→ morpho_withdraw_supply(amount, market?, toEoa: true) ← must use toEoa flag
|
|
231
|
+
```
|
|
232
|
+
|
|
156
233
|
### User asks about position health or liquidation risk
|
|
157
234
|
```
|
|
158
235
|
1. agether_health ← returns LTV, risk level, alerts per position
|
|
@@ -162,12 +239,11 @@ Both `agether_set_agent` and `agether_register` save the agentId to config perma
|
|
|
162
239
|
→ Show: morpho_max_borrowable for headroom context
|
|
163
240
|
```
|
|
164
241
|
|
|
165
|
-
### User wants to
|
|
242
|
+
### User wants to compare markets or check rates
|
|
166
243
|
```
|
|
167
|
-
1.
|
|
168
|
-
2.
|
|
169
|
-
3.
|
|
170
|
-
4. Suggest optimal strategy based on their holdings
|
|
244
|
+
1. morpho_markets ← supply APY, borrow APY, utilization, LLTV, liquidity per market
|
|
245
|
+
2. Present: which market has lowest borrow APY, highest supply APY
|
|
246
|
+
3. Suggest optimal strategy based on their holdings
|
|
171
247
|
```
|
|
172
248
|
|
|
173
249
|
### User asks to check or refresh credit score
|
|
@@ -182,6 +258,13 @@ Both `agether_set_agent` and `agether_register` save the agentId to config perma
|
|
|
182
258
|
3. NEVER say "not registered" or "no score yet" without calling the tool first!
|
|
183
259
|
```
|
|
184
260
|
|
|
261
|
+
### User wants to sponsor another agent
|
|
262
|
+
```
|
|
263
|
+
1. morpho_sponsor(agentId or agentAddress, amount, token)
|
|
264
|
+
→ Transfers collateral from your EOA to another agent's AgentAccount
|
|
265
|
+
2. The target agent can then deposit that collateral into Morpho themselves
|
|
266
|
+
```
|
|
267
|
+
|
|
185
268
|
### Something seems wrong / setup issues
|
|
186
269
|
```
|
|
187
270
|
1. agether_preflight ← run the diagnostic checklist
|
|
@@ -197,10 +280,13 @@ Both `agether_set_agent` and `agether_register` save the agentId to config perma
|
|
|
197
280
|
```
|
|
198
281
|
Explain: You're an AI agent with on-chain credit on Base.
|
|
199
282
|
You can:
|
|
200
|
-
- Deposit
|
|
201
|
-
-
|
|
202
|
-
- Pay for APIs using x402 protocol
|
|
283
|
+
- Deposit collateral and borrow USDC instantly (125% collateral ratio)
|
|
284
|
+
- Earn yield by lending USDC to Morpho markets
|
|
285
|
+
- Pay for APIs autonomously using x402 protocol
|
|
286
|
+
- Auto-fund payments from yield or credit (autoYield + autoDraw)
|
|
287
|
+
- Sponsor other agents with collateral
|
|
203
288
|
- Monitor position health and avoid liquidation
|
|
289
|
+
- Move funds freely between AgentAccount and EOA wallet
|
|
204
290
|
- All on Base mainnet, all autonomous
|
|
205
291
|
```
|
|
206
292
|
|
|
@@ -231,6 +317,15 @@ Example after register:
|
|
|
231
317
|
🔗 Tx: https://basescan.org/tx/0x177fdf...
|
|
232
318
|
```
|
|
233
319
|
|
|
320
|
+
Example after supply (lending):
|
|
321
|
+
```
|
|
322
|
+
✅ Supplied $500 USDC to WETH/USDC market
|
|
323
|
+
|
|
324
|
+
🔗 Tx: https://basescan.org/tx/0x789abc...
|
|
325
|
+
📈 Earning ~3.2% APY from borrowers
|
|
326
|
+
💰 AgentAccount: $50 USDC remaining
|
|
327
|
+
```
|
|
328
|
+
|
|
234
329
|
If something **fails**:
|
|
235
330
|
```
|
|
236
331
|
❌ Borrow failed: ExceedsMaxLtv
|
|
@@ -246,7 +341,7 @@ If something **fails**:
|
|
|
246
341
|
| Chain | Base mainnet (8453) |
|
|
247
342
|
| Currency | USDC (6 decimals) |
|
|
248
343
|
| Max LTV | 80% (= 125% collateral ratio) |
|
|
249
|
-
| Collateral tokens |
|
|
344
|
+
| Collateral tokens | Dynamically discovered from Morpho markets (call `morpho_markets`) |
|
|
250
345
|
| x402 cost | ~$0.001 per API call (WeatherXM) |
|
|
251
346
|
| Gas cost | ~$0.001–$0.01 per tx |
|
|
252
347
|
|
|
@@ -258,11 +353,12 @@ If something **fails**:
|
|
|
258
353
|
|-------|---------|-----------|
|
|
259
354
|
| `Missing AGETHER_PRIVATE_KEY` | Private key not set in secrets | Run `openclaw secrets configure` → source: env → id: AGETHER_PRIVATE_KEY |
|
|
260
355
|
| `ExceedsMaxLtv` | Collateral too low for borrow amount | Deposit more collateral or borrow less. LTV must be ≤ 80% |
|
|
261
|
-
| `Payment rejected (402)` | No USDC for x402 payment | Borrow USDC first
|
|
356
|
+
| `Payment rejected (402)` | No USDC for x402 payment | Borrow USDC first, or enable autoDraw/autoYield in config |
|
|
262
357
|
| `No collateral deposited` | Trying to borrow without collateral | `morpho_deposit` first |
|
|
263
|
-
| `Insufficient
|
|
264
|
-
| `Insufficient USDC in AgentAccount` | Not enough USDC for repay |
|
|
358
|
+
| `Insufficient collateral` | EOA doesn't have enough of that token | Tell user to send collateral to EOA address |
|
|
359
|
+
| `Insufficient USDC in AgentAccount` | Not enough USDC for repay/pay | Fund via borrow, yield withdrawal, or `wallet_fund` |
|
|
265
360
|
| `ExecutionFailed` | Smart contract call reverted | Check inner error, usually LTV or approval issue |
|
|
361
|
+
| `PositionNotActive` | No collateral deposited for this token | Deposit collateral with `morpho_deposit` first |
|
|
266
362
|
|
|
267
363
|
---
|
|
268
364
|
|
|
@@ -287,15 +383,26 @@ If no RPC key is set, the plugin falls back to `https://base-rpc.publicnode.com`
|
|
|
287
383
|
EOA Wallet (private key from AGETHER_PRIVATE_KEY)
|
|
288
384
|
├── Owns ERC-8004 Identity NFT (agentId) ← can own MULTIPLE
|
|
289
385
|
└── Owns Safe Account (via Safe7579 + ERC-4337, 1 per agentId)
|
|
290
|
-
├── Holds USDC (from borrows)
|
|
386
|
+
├── Holds USDC (from borrows or fund transfers)
|
|
387
|
+
├── Holds any ERC-20 tokens (collateral, etc.)
|
|
291
388
|
├── ERC8004ValidationModule validates ownership + KYA gate
|
|
292
|
-
└── Executes
|
|
389
|
+
└── Executes operations via ERC-4337 UserOps through EntryPoint
|
|
293
390
|
|
|
294
391
|
Morpho Blue (direct lending, overcollateralized 125%)
|
|
295
|
-
├──
|
|
296
|
-
├──
|
|
297
|
-
├──
|
|
298
|
-
|
|
392
|
+
├── BORROWER side:
|
|
393
|
+
│ ├── supplyCollateral() → collateral into Morpho Blue market
|
|
394
|
+
│ ├── borrow() → USDC from Morpho Blue → AgentAccount
|
|
395
|
+
│ ├── repay() → USDC from AgentAccount → Morpho Blue
|
|
396
|
+
│ └── withdrawCollateral() → collateral back (to AgentAccount or EOA)
|
|
397
|
+
└── LENDER side:
|
|
398
|
+
├── supply() → USDC into Morpho Blue market (earn yield)
|
|
399
|
+
├── withdraw() → USDC + earned interest back (to AgentAccount or EOA)
|
|
400
|
+
└── Yield tracked via Morpho GraphQL API (no database needed)
|
|
401
|
+
|
|
402
|
+
Wallet transfers:
|
|
403
|
+
├── wallet_fund → USDC from EOA → AgentAccount
|
|
404
|
+
├── wallet_withdraw_token → any ERC-20 from AgentAccount → EOA
|
|
405
|
+
└── wallet_withdraw_eth → ETH from AgentAccount → EOA
|
|
299
406
|
```
|
|
300
407
|
|
|
301
408
|
---
|
|
@@ -308,7 +415,6 @@ Morpho Blue (direct lending, overcollateralized 125%)
|
|
|
308
415
|
| Agether8004ValidationModule | `0xde896C58163b5f6cAC5B16C1b0109843f26106F6` |
|
|
309
416
|
| AgetherHookMultiplexer | `0x4AB6DaD0f7360fa8d8c75889A5c206B65d7CbeDb` |
|
|
310
417
|
| Agether7579Bootstrap | `0xCc83AA714c05B7141B21a17e80EB21bD09652b27` |
|
|
311
|
-
| ValidationRegistry | Not deployed yet |
|
|
312
418
|
| Agether8004Scorer | `0x56c7D35A976fac67b1993b66b861fCA32f59104F` |
|
|
313
419
|
| TimelockController | `0xc600e7AAB8a230326C714CE66f356fdf6aC021d8` |
|
|
314
420
|
| Safe Singleton | `0x41675C099F32341bf84BFc5382aF534df5C7461a` |
|
package/src/index.ts
CHANGED
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
* Each tool = MorphoClient / X402Client call → format result with txLink.
|
|
5
5
|
* Market discovery via Morpho GraphQL API (no backend dependency for markets).
|
|
6
6
|
*
|
|
7
|
+
* Supported chains: Ethereum (1, default), Base (8453).
|
|
8
|
+
*
|
|
7
9
|
* v2: Secrets-first config
|
|
8
10
|
* ─────────────────────────
|
|
9
11
|
* - privateKey → AGETHER_PRIVATE_KEY env var (set via `openclaw secrets configure` → crypto)
|
|
10
12
|
* - rpcUrl → auto-resolved from ALCHEMY_API_KEY / ANKR_API_KEY / QUICKNODE_URL env vars,
|
|
11
|
-
* falls back to
|
|
12
|
-
* - backendUrl → hardcoded (no config needed)
|
|
13
|
+
* falls back to publicnode.com (chain-aware)
|
|
13
14
|
* - agentId → optional plugin config field (auto-saved by tools)
|
|
14
|
-
*
|
|
15
|
-
* The plugin works with an empty `plugins.entries.agether.config: {}`.
|
|
15
|
+
* - chain → plugin config field (default: 1 = Ethereum)
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import axios from "axios";
|
|
@@ -21,13 +21,27 @@ import * as path from "path";
|
|
|
21
21
|
import {
|
|
22
22
|
MorphoClient,
|
|
23
23
|
X402Client,
|
|
24
|
+
getContractAddresses,
|
|
25
|
+
ChainId,
|
|
24
26
|
} from "@agether/sdk";
|
|
25
27
|
|
|
26
28
|
// ─── Constants ────────────────────────────────────────────
|
|
27
29
|
|
|
28
|
-
const BACKEND_URL = "
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
const BACKEND_URL = "https://api.agether.ai";
|
|
31
|
+
|
|
32
|
+
// Per-chain defaults
|
|
33
|
+
const CHAIN_DEFAULTS: Record<number, { rpc: string; explorer: string; chainName: string }> = {
|
|
34
|
+
[ChainId.Ethereum]: {
|
|
35
|
+
rpc: "https://ethereum-rpc.publicnode.com",
|
|
36
|
+
explorer: "https://etherscan.io/tx",
|
|
37
|
+
chainName: "Ethereum",
|
|
38
|
+
},
|
|
39
|
+
[ChainId.Base]: {
|
|
40
|
+
rpc: "https://base-rpc.publicnode.com",
|
|
41
|
+
explorer: "https://basescan.org/tx",
|
|
42
|
+
chainName: "Base",
|
|
43
|
+
},
|
|
44
|
+
};
|
|
31
45
|
|
|
32
46
|
// ─── Spending Cache (persists dailySpendLimit tracker across restarts) ────
|
|
33
47
|
|
|
@@ -73,11 +87,13 @@ interface PluginConfig {
|
|
|
73
87
|
privateKey: string;
|
|
74
88
|
agentId?: string;
|
|
75
89
|
rpcUrl: string;
|
|
76
|
-
|
|
90
|
+
chainId: ChainId;
|
|
77
91
|
}
|
|
78
92
|
|
|
79
93
|
function txLink(hash: string): string {
|
|
80
|
-
|
|
94
|
+
if (!hash) return "";
|
|
95
|
+
const explorer = CHAIN_DEFAULTS[activeChainId]?.explorer ?? CHAIN_DEFAULTS[ChainId.Ethereum].explorer;
|
|
96
|
+
return `${explorer}/${hash}`;
|
|
81
97
|
}
|
|
82
98
|
|
|
83
99
|
function ok(text: string) {
|
|
@@ -102,18 +118,25 @@ function fail(err: unknown) {
|
|
|
102
118
|
/**
|
|
103
119
|
* Resolve RPC URL from environment secrets.
|
|
104
120
|
* Priority: ALCHEMY_API_KEY → ANKR_API_KEY → QUICKNODE_URL → publicnode fallback.
|
|
121
|
+
* Chain-aware: uses the correct endpoint subdomain for the configured chain.
|
|
105
122
|
*/
|
|
106
|
-
function resolveRpcUrl(): string {
|
|
123
|
+
function resolveRpcUrl(chainId: ChainId): string {
|
|
107
124
|
const alchemy = process.env.ALCHEMY_API_KEY;
|
|
108
|
-
if (alchemy)
|
|
125
|
+
if (alchemy) {
|
|
126
|
+
const alchemyChain = chainId === ChainId.Base ? "base-mainnet" : "eth-mainnet";
|
|
127
|
+
return `https://${alchemyChain}.g.alchemy.com/v2/${alchemy}`;
|
|
128
|
+
}
|
|
109
129
|
|
|
110
130
|
const ankr = process.env.ANKR_API_KEY;
|
|
111
|
-
if (ankr)
|
|
131
|
+
if (ankr) {
|
|
132
|
+
const ankrChain = chainId === ChainId.Base ? "base" : "eth";
|
|
133
|
+
return `https://rpc.ankr.com/${ankrChain}/${ankr}`;
|
|
134
|
+
}
|
|
112
135
|
|
|
113
136
|
const quicknode = process.env.QUICKNODE_URL;
|
|
114
137
|
if (quicknode) return quicknode;
|
|
115
138
|
|
|
116
|
-
return
|
|
139
|
+
return CHAIN_DEFAULTS[chainId]?.rpc ?? CHAIN_DEFAULTS[ChainId.Ethereum].rpc;
|
|
117
140
|
}
|
|
118
141
|
|
|
119
142
|
/**
|
|
@@ -134,16 +157,19 @@ function resolvePrivateKey(): string {
|
|
|
134
157
|
|
|
135
158
|
function getConfig(api: any): PluginConfig {
|
|
136
159
|
const cfg = api.config?.plugins?.entries?.["agether"]?.config ?? {};
|
|
160
|
+
const chainId = (cfg.chain as ChainId) || ChainId.Ethereum;
|
|
161
|
+
activeChainId = chainId; // Update module-level for txLink
|
|
137
162
|
return {
|
|
138
163
|
privateKey: resolvePrivateKey(),
|
|
139
164
|
agentId: cfg.agentId,
|
|
140
|
-
rpcUrl: resolveRpcUrl(),
|
|
141
|
-
|
|
165
|
+
rpcUrl: resolveRpcUrl(chainId),
|
|
166
|
+
chainId,
|
|
142
167
|
};
|
|
143
168
|
}
|
|
144
169
|
|
|
145
170
|
// Module-level cache
|
|
146
171
|
let cachedAgentId: string | undefined;
|
|
172
|
+
let activeChainId: ChainId = ChainId.Ethereum;
|
|
147
173
|
|
|
148
174
|
function createClient(cfg: PluginConfig): MorphoClient {
|
|
149
175
|
const agentId = cachedAgentId || cfg.agentId;
|
|
@@ -151,6 +177,7 @@ function createClient(cfg: PluginConfig): MorphoClient {
|
|
|
151
177
|
privateKey: cfg.privateKey,
|
|
152
178
|
rpcUrl: cfg.rpcUrl,
|
|
153
179
|
agentId,
|
|
180
|
+
chainId: cfg.chainId,
|
|
154
181
|
});
|
|
155
182
|
}
|
|
156
183
|
|
|
@@ -186,7 +213,7 @@ export default function register(api: any) {
|
|
|
186
213
|
api.registerTool({
|
|
187
214
|
name: "agether_balance",
|
|
188
215
|
description:
|
|
189
|
-
"Check ETH and USDC balances for the agent's EOA wallet and AgentAccount
|
|
216
|
+
"Check ETH and USDC balances for the agent's EOA wallet and AgentAccount.",
|
|
190
217
|
parameters: { type: "object", properties: {}, required: [] },
|
|
191
218
|
async execute() {
|
|
192
219
|
try {
|
|
@@ -204,7 +231,7 @@ export default function register(api: any) {
|
|
|
204
231
|
api.registerTool({
|
|
205
232
|
name: "agether_register",
|
|
206
233
|
description:
|
|
207
|
-
"Register a new ERC-8004 agent identity
|
|
234
|
+
"Register a new ERC-8004 agent identity and create a Safe smart account (via Safe7579). Returns the new agentId.",
|
|
208
235
|
parameters: {
|
|
209
236
|
type: "object",
|
|
210
237
|
properties: {
|
|
@@ -359,14 +386,50 @@ export default function register(api: any) {
|
|
|
359
386
|
api.registerTool({
|
|
360
387
|
name: "morpho_status",
|
|
361
388
|
description:
|
|
362
|
-
"Show all Morpho Blue positions — collateral
|
|
389
|
+
"Show all Morpho Blue positions — collateral, debt, LTV, and Health Factor for each market.",
|
|
363
390
|
parameters: { type: "object", properties: {}, required: [] },
|
|
364
391
|
async execute() {
|
|
365
392
|
try {
|
|
366
393
|
const cfg = getConfig(api);
|
|
367
394
|
const client = createClient(cfg);
|
|
368
|
-
const
|
|
369
|
-
|
|
395
|
+
const [status, maxBorrow] = await Promise.all([
|
|
396
|
+
client.getStatus(),
|
|
397
|
+
client.getMaxBorrowable(),
|
|
398
|
+
]);
|
|
399
|
+
|
|
400
|
+
const positions = status.positions.map((p: any) => {
|
|
401
|
+
const mm = maxBorrow.byMarket.find((m: any) => m.collateralToken === p.collateralToken);
|
|
402
|
+
const collateralValueUsd = mm ? Number(mm.collateralValue) / 1e6 : 0;
|
|
403
|
+
const debt = parseFloat(p.debt);
|
|
404
|
+
const lltv = 0.80; // Morpho LLTV
|
|
405
|
+
const ltv = collateralValueUsd > 0 ? debt / collateralValueUsd : 0;
|
|
406
|
+
// HF = LLTV / LTV — >1 is safe, <1 is liquidatable
|
|
407
|
+
const hf = ltv > 0 ? lltv / ltv : Infinity;
|
|
408
|
+
const headroom = mm ? Number(mm.maxAdditional) / 1e6 : 0;
|
|
409
|
+
|
|
410
|
+
let risk: string;
|
|
411
|
+
if (debt === 0) risk = "🟢 no debt";
|
|
412
|
+
else if (hf <= 1.0) risk = "🔴 LIQUIDATION ZONE";
|
|
413
|
+
else if (hf <= 1.15) risk = "🟡 WARNING";
|
|
414
|
+
else risk = "🟢 healthy";
|
|
415
|
+
|
|
416
|
+
return {
|
|
417
|
+
collateralToken: p.collateralToken,
|
|
418
|
+
collateral: p.collateral,
|
|
419
|
+
collateralValueUsd: `$${collateralValueUsd.toFixed(2)}`,
|
|
420
|
+
debt: `$${debt.toFixed(2)}`,
|
|
421
|
+
ltv: `${(ltv * 100).toFixed(1)}%`,
|
|
422
|
+
healthFactor: debt === 0 ? "∞" : hf.toFixed(2),
|
|
423
|
+
headroom: `$${headroom.toFixed(2)}`,
|
|
424
|
+
risk,
|
|
425
|
+
};
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
return ok(JSON.stringify({
|
|
429
|
+
agentAccount: status.agentAccount,
|
|
430
|
+
totalDebt: `$${status.totalDebt}`,
|
|
431
|
+
positions,
|
|
432
|
+
}, null, 2));
|
|
370
433
|
} catch (e) { return fail(e); }
|
|
371
434
|
},
|
|
372
435
|
});
|
|
@@ -715,7 +778,7 @@ export default function register(api: any) {
|
|
|
715
778
|
api.registerTool({
|
|
716
779
|
name: "morpho_markets",
|
|
717
780
|
description:
|
|
718
|
-
"List available Morpho Blue USDC markets
|
|
781
|
+
"List available Morpho Blue USDC markets — liquidity, supply/borrow APY, utilization, LLTV. " +
|
|
719
782
|
"Optionally filter by collateral token.",
|
|
720
783
|
parameters: {
|
|
721
784
|
type: "object",
|
|
@@ -772,22 +835,22 @@ export default function register(api: any) {
|
|
|
772
835
|
if (params.refresh) {
|
|
773
836
|
// x402-gated fresh score — account address required for payment
|
|
774
837
|
const accountAddress = await client.getAccountAddress();
|
|
838
|
+
const contracts = getContractAddresses(cfg.chainId);
|
|
775
839
|
const x402 = new X402Client({
|
|
776
840
|
privateKey: cfg.privateKey,
|
|
777
841
|
rpcUrl: cfg.rpcUrl,
|
|
778
|
-
backendUrl: cfg.backendUrl,
|
|
779
842
|
agentId,
|
|
780
843
|
accountAddress,
|
|
781
844
|
// Safe7579 needs validator prefix for ERC-1271 isValidSignature routing
|
|
782
|
-
validatorModule:
|
|
845
|
+
validatorModule: contracts.erc8004ValidationModule,
|
|
783
846
|
});
|
|
784
|
-
const result = await x402.get(`${
|
|
847
|
+
const result = await x402.get(`${BACKEND_URL}/score/${agentId}?chain=${cfg.chainId}`);
|
|
785
848
|
if (!result.success) return fail(result.error || "Score request failed");
|
|
786
849
|
return ok(JSON.stringify(result.data, null, 2));
|
|
787
850
|
}
|
|
788
851
|
|
|
789
852
|
// Free: read current onchain score
|
|
790
|
-
const { data } = await axios.get(`${
|
|
853
|
+
const { data } = await axios.get(`${BACKEND_URL}/score/${agentId}/current?chain=${cfg.chainId}`);
|
|
791
854
|
return ok(JSON.stringify(data, null, 2));
|
|
792
855
|
} catch (e) { return fail(e); }
|
|
793
856
|
},
|
|
@@ -920,22 +983,21 @@ export default function register(api: any) {
|
|
|
920
983
|
|
|
921
984
|
const autoDrawEnabled = agetherCfg.autoDraw === true;
|
|
922
985
|
const autoYieldEnabled = agetherCfg.autoYield === true;
|
|
986
|
+
const contracts = getContractAddresses(cfg.chainId);
|
|
923
987
|
const x402 = new X402Client({
|
|
924
988
|
privateKey: cfg.privateKey,
|
|
925
989
|
rpcUrl: cfg.rpcUrl,
|
|
926
|
-
backendUrl: cfg.backendUrl,
|
|
927
990
|
agentId,
|
|
928
991
|
accountAddress,
|
|
929
992
|
autoDraw: autoDrawEnabled,
|
|
930
993
|
autoYield: autoYieldEnabled,
|
|
931
994
|
dailySpendLimitUsdc: agetherCfg.dailySpendLimitUsdc,
|
|
932
|
-
autoDrawBuffer: agetherCfg.autoDrawBuffer,
|
|
933
995
|
// Restore spending state from cache so limit survives restarts
|
|
934
996
|
initialSpendingState: loadSpendCache(),
|
|
935
997
|
// Persist every spending update to cache file
|
|
936
998
|
onSpendingUpdate: (state: any) => saveSpendCache(state),
|
|
937
999
|
// Safe7579 needs validator prefix for ERC-1271 isValidSignature routing
|
|
938
|
-
validatorModule:
|
|
1000
|
+
validatorModule: contracts.erc8004ValidationModule,
|
|
939
1001
|
});
|
|
940
1002
|
|
|
941
1003
|
let result;
|
|
@@ -1095,6 +1157,7 @@ export default function register(api: any) {
|
|
|
1095
1157
|
totalBorrowingHeadroom: `$${(Number(maxBorrow.total) / 1e6).toFixed(2)}`,
|
|
1096
1158
|
positions: positionHealth,
|
|
1097
1159
|
alerts: alerts.length > 0 ? alerts : ["✅ All positions healthy"],
|
|
1160
|
+
chain: CHAIN_DEFAULTS[cfg.chainId]?.chainName ?? `Chain ${cfg.chainId}`,
|
|
1098
1161
|
rpcSource: process.env.ALCHEMY_API_KEY ? "Alchemy" :
|
|
1099
1162
|
process.env.ANKR_API_KEY ? "Ankr" :
|
|
1100
1163
|
process.env.QUICKNODE_URL ? "QuickNode" : "PublicNode (free)",
|
|
@@ -1127,10 +1190,14 @@ export default function register(api: any) {
|
|
|
1127
1190
|
}
|
|
1128
1191
|
|
|
1129
1192
|
// 2. RPC URL
|
|
1130
|
-
const
|
|
1193
|
+
const pluginCfg = api.config?.plugins?.entries?.["agether"]?.config ?? {};
|
|
1194
|
+
const prefChainId = (pluginCfg.chain as ChainId) || ChainId.Ethereum;
|
|
1195
|
+
const chainName = CHAIN_DEFAULTS[prefChainId]?.chainName ?? "Unknown";
|
|
1196
|
+
const rpcUrl = resolveRpcUrl(prefChainId);
|
|
1131
1197
|
const rpcSource = process.env.ALCHEMY_API_KEY ? "Alchemy" :
|
|
1132
1198
|
process.env.ANKR_API_KEY ? "Ankr" :
|
|
1133
1199
|
process.env.QUICKNODE_URL ? "QuickNode" : "PublicNode (free fallback)";
|
|
1200
|
+
checks.push({ check: "Chain", status: `✅ ${chainName} (${prefChainId})` });
|
|
1134
1201
|
checks.push({ check: "RPC endpoint", status: `✅ ${rpcSource}`, detail: rpcUrl.replace(/\/[a-zA-Z0-9_-]{20,}$/, '/***') });
|
|
1135
1202
|
|
|
1136
1203
|
// 3. Agent registration
|
|
@@ -1219,17 +1286,28 @@ export default function register(api: any) {
|
|
|
1219
1286
|
|
|
1220
1287
|
api.registerCommand({
|
|
1221
1288
|
name: "morpho",
|
|
1222
|
-
description: "Show Morpho positions (no AI)",
|
|
1289
|
+
description: "Show Morpho positions with Health Factor (no AI)",
|
|
1223
1290
|
handler: async () => {
|
|
1224
1291
|
try {
|
|
1225
1292
|
const cfg = getConfig(api);
|
|
1226
1293
|
const client = createClient(cfg);
|
|
1227
|
-
const s = await
|
|
1294
|
+
const [s, maxBorrow] = await Promise.all([
|
|
1295
|
+
client.getStatus(),
|
|
1296
|
+
client.getMaxBorrowable(),
|
|
1297
|
+
]);
|
|
1228
1298
|
|
|
1229
1299
|
let text = `📊 Morpho\nAccount: ${s.agentAccount}\nTotal debt: $${s.totalDebt}\n`;
|
|
1230
1300
|
for (const p of s.positions) {
|
|
1231
|
-
|
|
1301
|
+
const mm = maxBorrow.byMarket.find((m: any) => m.collateralToken === p.collateralToken);
|
|
1302
|
+
const cv = mm ? Number(mm.collateralValue) / 1e6 : 0;
|
|
1303
|
+
const debt = parseFloat(p.debt);
|
|
1304
|
+
const ltv = cv > 0 ? debt / cv : 0;
|
|
1305
|
+
const hf = ltv > 0 ? 0.80 / ltv : Infinity;
|
|
1306
|
+
const hfStr = debt === 0 ? "∞" : hf.toFixed(2);
|
|
1307
|
+
const icon = debt === 0 ? "🟢" : hf <= 1.0 ? "🔴" : hf <= 1.15 ? "🟡" : "🟢";
|
|
1308
|
+
text += `\n${icon} ${p.collateralToken}: ${p.collateral} col, $${p.debt} debt, HF ${hfStr}`;
|
|
1232
1309
|
}
|
|
1310
|
+
if (s.positions.length === 0) text += "\nNo active positions.";
|
|
1233
1311
|
return { text };
|
|
1234
1312
|
} catch (e: any) {
|
|
1235
1313
|
return { text: `❌ ${e.message}` };
|
|
@@ -1315,8 +1393,9 @@ export default function register(api: any) {
|
|
|
1315
1393
|
const balances = await client.getBalances();
|
|
1316
1394
|
const agentId = balances.agentId ?? "?";
|
|
1317
1395
|
const safeUsdc = balances.agentAccount?.usdc ?? "0";
|
|
1396
|
+
const chainName = CHAIN_DEFAULTS[cfg.chainId]?.chainName ?? `Chain ${cfg.chainId}`;
|
|
1318
1397
|
api.logger?.info?.(
|
|
1319
|
-
`[agether] Session start — Agent #${agentId}, EOA: ${balances.eth} ETH / $${balances.usdc} USDC, Safe: $${safeUsdc} USDC`,
|
|
1398
|
+
`[agether] Session start — ${chainName}, Agent #${agentId}, EOA: ${balances.eth} ETH / $${balances.usdc} USDC, Safe: $${safeUsdc} USDC`,
|
|
1320
1399
|
);
|
|
1321
1400
|
} catch {
|
|
1322
1401
|
// Silently fail — hook should not block conversations
|