@agether/openclaw-plugin 1.1.1 → 1.2.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.
@@ -2,7 +2,7 @@
2
2
  "id": "agether",
3
3
  "name": "Agether Credit",
4
4
  "description": "On-chain credit protocol for AI agents — Morpho-backed overcollateralized credit, ERC-8004 identity, x402 payments",
5
- "version": "1.1.0",
5
+ "version": "1.2.0",
6
6
  "skills": ["skills/agether"],
7
7
  "configSchema": {
8
8
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agether/openclaw-plugin",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "OpenClaw plugin for Agether — on-chain credit for AI agents",
5
5
  "main": "src/index.ts",
6
6
  "openclaw": {
package/src/index.ts CHANGED
@@ -30,6 +30,7 @@ const ERC8004_ABI = [
30
30
  "function register(string agentURI) returns (uint256)",
31
31
  "function ownerOf(uint256 tokenId) view returns (address)",
32
32
  "function balanceOf(address owner) view returns (uint256)",
33
+ "function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)",
33
34
  ];
34
35
 
35
36
  const COLLATERAL_TOKENS: Record<string, { address: string; decimals: number }> = {
@@ -69,6 +70,23 @@ async function getAccountAddr(signer: ethers.Wallet, factoryAddr: string, agentI
69
70
  return addr;
70
71
  }
71
72
 
73
+ // ─── Auto-resolve agentId from chain ──────────────────────
74
+ let _cachedAgentId: string | null = null;
75
+
76
+ async function resolveAgentId(cfg: PluginConfig, signer: ethers.Wallet, status: any): Promise<string> {
77
+ // 1. Config takes priority
78
+ if (cfg.agentId && cfg.agentId !== "0") return cfg.agentId;
79
+ // 2. Session cache
80
+ if (_cachedAgentId) return _cachedAgentId;
81
+ // 3. Look up on-chain: does this wallet own any ERC-8004 token?
82
+ const agentRegistry = new ethers.Contract(status.contracts.agentRegistry, ERC8004_ABI, signer.provider!);
83
+ const balance: bigint = await agentRegistry.balanceOf(signer.address);
84
+ if (balance === 0n) throw new Error("No agent registered. Use agether_register first.");
85
+ const tokenId: bigint = await agentRegistry.tokenOfOwnerByIndex(signer.address, 0);
86
+ _cachedAgentId = tokenId.toString();
87
+ return _cachedAgentId;
88
+ }
89
+
72
90
  function ok(text: string) {
73
91
  return { content: [{ type: "text" as const, text }] };
74
92
  }
@@ -103,15 +121,17 @@ export default function register(api: any) {
103
121
 
104
122
  const result: any = {
105
123
  address,
106
- agentId: cfg.agentId || "not set",
124
+ agentId: cfg.agentId || _cachedAgentId || "not registered",
107
125
  eth: ethers.formatEther(ethBal),
108
126
  usdc: ethers.formatUnits(usdcBal, 6),
109
127
  };
110
128
 
111
- // AgentAccount balances
112
- if (cfg.agentId && status.contracts.accountFactory) {
113
- try {
114
- const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
129
+ // AgentAccount balances — try to auto-resolve agentId
130
+ try {
131
+ const agentId = await resolveAgentId(cfg, signer, status);
132
+ result.agentId = agentId;
133
+ if (status.contracts.accountFactory) {
134
+ const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
115
135
  const accEth = await provider.getBalance(accountAddr);
116
136
  const accUsdc = await usdc.balanceOf(accountAddr);
117
137
  result.agentAccount = {
@@ -119,8 +139,8 @@ export default function register(api: any) {
119
139
  eth: ethers.formatEther(accEth),
120
140
  usdc: ethers.formatUnits(accUsdc, 6),
121
141
  };
122
- } catch { /* no account yet */ }
123
- }
142
+ }
143
+ } catch { /* no agent registered yet */ }
124
144
 
125
145
  return ok(JSON.stringify(result, null, 2));
126
146
  } catch (e) { return fail(e); }
@@ -211,13 +231,15 @@ export default function register(api: any) {
211
231
  accountAddr = await factory.getAccount(agentId);
212
232
  }
213
233
 
234
+ // Cache agentId for the session so all subsequent tools work
235
+ _cachedAgentId = agentId.toString();
236
+
214
237
  return ok(JSON.stringify({
215
238
  status: "registered",
216
239
  agentId: agentId.toString(),
217
240
  address: signer.address,
218
241
  agentAccount: accountAddr,
219
242
  tx: tx.hash,
220
- important: "Save this agentId in your plugin config: plugins.entries.agether.config.agentId",
221
243
  }));
222
244
  } catch (e) { return fail(e); }
223
245
  },
@@ -236,9 +258,9 @@ export default function register(api: any) {
236
258
  const cfg = getConfig(api);
237
259
  const signer = getSigner(cfg);
238
260
  const status = await getBackendStatus(cfg);
239
- if (!cfg.agentId) return fail("No agentId configured");
261
+ const agentId = await resolveAgentId(cfg, signer, status);
240
262
 
241
- const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
263
+ const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
242
264
  const morpho = new ethers.Contract(status.contracts.morphoCredit, MORPHO_CREDIT_ABI, signer.provider!);
243
265
 
244
266
  const positions: any[] = [];
@@ -285,13 +307,13 @@ export default function register(api: any) {
285
307
  const cfg = getConfig(api);
286
308
  const signer = getSigner(cfg);
287
309
  const status = await getBackendStatus(cfg);
288
- if (!cfg.agentId) return fail("No agentId configured");
310
+ const agentId = await resolveAgentId(cfg, signer, status);
289
311
 
290
312
  const tokenInfo = COLLATERAL_TOKENS[params.token];
291
313
  if (!tokenInfo) return fail(`Unsupported token: ${params.token}. Use WETH, wstETH, or cbETH`);
292
314
 
293
315
  const morphoCreditAddr = status.contracts.morphoCredit;
294
- const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
316
+ const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
295
317
  const amount = ethers.parseUnits(params.amount, tokenInfo.decimals);
296
318
 
297
319
  // Check balance
@@ -351,13 +373,13 @@ export default function register(api: any) {
351
373
  const cfg = getConfig(api);
352
374
  const signer = getSigner(cfg);
353
375
  const status = await getBackendStatus(cfg);
354
- if (!cfg.agentId) return fail("No agentId configured");
376
+ const agentId = await resolveAgentId(cfg, signer, status);
355
377
 
356
378
  const tokenInfo = COLLATERAL_TOKENS[params.token];
357
379
  if (!tokenInfo) return fail(`Unsupported token: ${params.token}`);
358
380
 
359
381
  const morphoCreditAddr = status.contracts.morphoCredit;
360
- const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
382
+ const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
361
383
  const collateralWei = ethers.parseUnits(params.collateralAmount, tokenInfo.decimals);
362
384
  const borrowWei = ethers.parseUnits(params.borrowAmount, 6);
363
385
 
@@ -526,9 +548,9 @@ export default function register(api: any) {
526
548
  const cfg = getConfig(api);
527
549
  const signer = getSigner(cfg);
528
550
  const status = await getBackendStatus(cfg);
529
- if (!cfg.agentId) return fail("No agentId configured");
551
+ const agentId = await resolveAgentId(cfg, signer, status);
530
552
 
531
- const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
553
+ const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
532
554
  const morpho = new ethers.Contract(status.contracts.morphoCredit, MORPHO_CREDIT_ABI, signer.provider!);
533
555
 
534
556
  // Find active collateral
@@ -583,9 +605,9 @@ export default function register(api: any) {
583
605
  const cfg = getConfig(api);
584
606
  const signer = getSigner(cfg);
585
607
  const status = await getBackendStatus(cfg);
586
- if (!cfg.agentId) return fail("No agentId configured");
608
+ const agentId = await resolveAgentId(cfg, signer, status);
587
609
 
588
- const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
610
+ const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
589
611
  const morpho = new ethers.Contract(status.contracts.morphoCredit, MORPHO_CREDIT_ABI, signer.provider!);
590
612
 
591
613
  // Find active collateral with debt
@@ -652,12 +674,12 @@ export default function register(api: any) {
652
674
  const cfg = getConfig(api);
653
675
  const signer = getSigner(cfg);
654
676
  const status = await getBackendStatus(cfg);
655
- if (!cfg.agentId) return fail("No agentId configured");
677
+ const agentId = await resolveAgentId(cfg, signer, status);
656
678
 
657
679
  const tokenInfo = COLLATERAL_TOKENS[params.token];
658
680
  if (!tokenInfo) return fail(`Unsupported token: ${params.token}`);
659
681
 
660
- const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
682
+ const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
661
683
  const morpho = new ethers.Contract(status.contracts.morphoCredit, MORPHO_CREDIT_ABI, signer.provider!);
662
684
  const pos = await morpho.getPosition(accountAddr, tokenInfo.address);
663
685
 
@@ -758,8 +780,10 @@ export default function register(api: any) {
758
780
  async execute() {
759
781
  try {
760
782
  const cfg = getConfig(api);
761
- if (!cfg.agentId) return fail("No agentId configured");
762
- const { data } = await axios.get(`${cfg.backendUrl}/credit/score/${cfg.agentId}`);
783
+ const signer = getSigner(cfg);
784
+ const status = await getBackendStatus(cfg);
785
+ const agentId = await resolveAgentId(cfg, signer, status);
786
+ const { data } = await axios.get(`${cfg.backendUrl}/credit/score/${agentId}`);
763
787
  return ok(JSON.stringify(data, null, 2));
764
788
  } catch (e) { return fail(e); }
765
789
  },
@@ -783,9 +807,9 @@ export default function register(api: any) {
783
807
  const cfg = getConfig(api);
784
808
  const signer = getSigner(cfg);
785
809
  const status = await getBackendStatus(cfg);
786
- if (!cfg.agentId) return fail("No agentId configured");
810
+ const agentId = await resolveAgentId(cfg, signer, status);
787
811
 
788
- const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
812
+ const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
789
813
  const amountWei = ethers.parseUnits(params.amount, 6);
790
814
 
791
815
  const usdc = new ethers.Contract(status.contracts.usdc, ERC20_ABI, signer);
@@ -834,15 +858,15 @@ export default function register(api: any) {
834
858
 
835
859
  // Resolve AgentAccount address for x402 payments
836
860
  let accountAddress: string | undefined;
837
- if (cfg.agentId && status.contracts.accountFactory) {
838
- try {
839
- accountAddress = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
840
- } catch { /* no account, pay from EOA */ }
841
- }
861
+ let agentId: string | undefined;
862
+ try {
863
+ agentId = await resolveAgentId(cfg, signer, status);
864
+ accountAddress = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
865
+ } catch { /* no account, pay from EOA */ }
842
866
 
843
867
  // Auto-draw: if enabled, check USDC balance and borrow if needed
844
868
  const shouldAutoDraw = params.autoDraw ?? cfg.autoDraw;
845
- if (shouldAutoDraw && accountAddress && cfg.agentId) {
869
+ if (shouldAutoDraw && accountAddress && agentId) {
846
870
  const usdc = new ethers.Contract(status.contracts.usdc, ERC20_ABI, signer.provider!);
847
871
  const accBalance = await usdc.balanceOf(accountAddress);
848
872
  // If balance < $1, try to auto-borrow $10 (enough for several x402 calls)
@@ -871,7 +895,7 @@ export default function register(api: any) {
871
895
  privateKey: cfg.privateKey,
872
896
  rpcUrl: cfg.rpcUrl!,
873
897
  backendUrl: cfg.backendUrl!,
874
- agentId: cfg.agentId,
898
+ agentId: agentId,
875
899
  accountAddress,
876
900
  });
877
901
 
@@ -912,14 +936,17 @@ export default function register(api: any) {
912
936
  const usdc = new ethers.Contract(status.contracts.usdc, ERC20_ABI, provider);
913
937
  const usdcBal = await usdc.balanceOf(signer.address);
914
938
 
915
- let text = `💰 Agent #${cfg.agentId || "?"}\n`;
939
+ let agentId: string | undefined;
940
+ try { agentId = await resolveAgentId(cfg, signer, status); } catch {}
941
+
942
+ let text = `💰 Agent #${agentId || "?"}\n`;
916
943
  text += `Address: ${signer.address}\n`;
917
944
  text += `ETH: ${parseFloat(ethers.formatEther(ethBal)).toFixed(6)}\n`;
918
945
  text += `USDC: $${ethers.formatUnits(usdcBal, 6)}`;
919
946
 
920
- if (cfg.agentId && status.contracts.accountFactory) {
947
+ if (agentId && status.contracts.accountFactory) {
921
948
  try {
922
- const accAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
949
+ const accAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
923
950
  const accUsdc = await usdc.balanceOf(accAddr);
924
951
  text += `\n\n🏦 AgentAccount: ${accAddr}\nUSDC: $${ethers.formatUnits(accUsdc, 6)}`;
925
952
  } catch { /* no account */ }
@@ -940,13 +967,13 @@ export default function register(api: any) {
940
967
  const cfg = getConfig(api);
941
968
  const signer = getSigner(cfg);
942
969
  const status = await getBackendStatus(cfg);
943
- if (!cfg.agentId) return { text: "❌ No agentId configured" };
970
+ const agentId = await resolveAgentId(cfg, signer, status);
944
971
 
945
- const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, cfg.agentId);
972
+ const accountAddr = await getAccountAddr(signer, status.contracts.accountFactory, agentId);
946
973
  const morpho = new ethers.Contract(status.contracts.morphoCredit, MORPHO_CREDIT_ABI, signer.provider!);
947
974
  const totalDebt = await morpho.getTotalDebt(accountAddr);
948
975
 
949
- let text = `📊 Morpho — Agent #${cfg.agentId}\nAccount: ${accountAddr}\nTotal debt: $${ethers.formatUnits(totalDebt, 6)}\n`;
976
+ let text = `📊 Morpho — Agent #${agentId}\nAccount: ${accountAddr}\nTotal debt: $${ethers.formatUnits(totalDebt, 6)}\n`;
950
977
 
951
978
  for (const [symbol, info] of Object.entries(COLLATERAL_TOKENS)) {
952
979
  const pos = await morpho.getPosition(accountAddr, info.address);