@clawnch/clawtomaton 0.8.1 → 0.9.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.
Files changed (40) hide show
  1. package/README.md +5 -4
  2. package/dist/agent/index.d.ts.map +1 -1
  3. package/dist/agent/index.js +2 -0
  4. package/dist/agent/index.js.map +1 -1
  5. package/dist/agent/prompt.d.ts.map +1 -1
  6. package/dist/agent/prompt.js +35 -0
  7. package/dist/agent/prompt.js.map +1 -1
  8. package/dist/heartbeat/index.d.ts +28 -0
  9. package/dist/heartbeat/index.d.ts.map +1 -1
  10. package/dist/heartbeat/index.js +188 -2
  11. package/dist/heartbeat/index.js.map +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/market/index.d.ts +39 -0
  17. package/dist/market/index.d.ts.map +1 -1
  18. package/dist/market/index.js +95 -1
  19. package/dist/market/index.js.map +1 -1
  20. package/dist/skills/herd.d.ts +23 -0
  21. package/dist/skills/herd.d.ts.map +1 -0
  22. package/dist/skills/herd.js +687 -0
  23. package/dist/skills/herd.js.map +1 -0
  24. package/dist/skills/hummingbot.d.ts +7 -17
  25. package/dist/skills/hummingbot.d.ts.map +1 -1
  26. package/dist/skills/hummingbot.js +984 -362
  27. package/dist/skills/hummingbot.js.map +1 -1
  28. package/dist/skills/index.d.ts +3 -1
  29. package/dist/skills/index.d.ts.map +1 -1
  30. package/dist/skills/index.js +9 -1
  31. package/dist/skills/index.js.map +1 -1
  32. package/dist/skills/walletconnect.d.ts +17 -0
  33. package/dist/skills/walletconnect.d.ts.map +1 -0
  34. package/dist/skills/walletconnect.js +336 -0
  35. package/dist/skills/walletconnect.js.map +1 -0
  36. package/dist/state/index.d.ts +16 -0
  37. package/dist/state/index.d.ts.map +1 -1
  38. package/dist/state/index.js +67 -0
  39. package/dist/state/index.js.map +1 -1
  40. package/package.json +3 -3
@@ -0,0 +1,687 @@
1
+ /**
2
+ * Skill: herd_intelligence — On-chain intelligence via Herd MCP.
3
+ *
4
+ * Multi-action skill that exposes HerdIntelligence composed methods
5
+ * to the Clawtomaton agent. Combines Herd's block explorer data with
6
+ * Clawncher's domain-specific on-chain reading.
7
+ *
8
+ * Actions (all read-only, available at normal + low_compute tiers):
9
+ * investigate — Investigate contract, tx, or wallet (auto-detects)
10
+ * audit_token — Security audit with risk score (0-100)
11
+ * validate_swap — Pre-swap route validation vs historical data
12
+ * validate_claim — Fee-claim validation vs historical claims
13
+ * profile_counterparty — Trust assessment for a wallet/contract
14
+ * search_code — Regex search across on-chain contract code
15
+ * track_token — Track token transfers for a given holder+token
16
+ * bookmark — List/add/remove Herd bookmarks
17
+ * simulate — Generate HAL expressions for simulation
18
+ *
19
+ * Requires HERD_ACCESS_TOKEN env var or stored auth at ~/.clawncher/herd-auth.json.
20
+ */
21
+ import { HerdIntelligence, HalBuilder } from '@clawnch/clawncher-sdk';
22
+ import { isAddress, isHash } from 'viem';
23
+ // ============================================================================
24
+ // Tier permissions — all actions are read-only, no gas cost
25
+ // ============================================================================
26
+ const ALL_ACTIONS = new Set([
27
+ 'investigate',
28
+ 'audit_token',
29
+ 'validate_swap',
30
+ 'validate_claim',
31
+ 'profile_counterparty',
32
+ 'search_code',
33
+ 'track_token',
34
+ 'bookmark',
35
+ 'simulate',
36
+ ]);
37
+ const TIER_ALLOWED = {
38
+ normal: new Set(ALL_ACTIONS),
39
+ low_compute: new Set(ALL_ACTIONS),
40
+ critical: new Set(['investigate', 'audit_token', 'bookmark']),
41
+ dead: new Set(),
42
+ };
43
+ // ============================================================================
44
+ // Cached HerdIntelligence singleton
45
+ // ============================================================================
46
+ let cachedHerd = null;
47
+ async function getHerd(ctx) {
48
+ if (cachedHerd)
49
+ return cachedHerd;
50
+ const rpcUrl = process.env.BASE_RPC_URL ?? 'https://mainnet.base.org';
51
+ // Dynamic import to match check-price pattern
52
+ const { buildClients } = await import('../identity/index.js');
53
+ const { publicClient } = buildClients(ctx.identity, rpcUrl);
54
+ const config = {
55
+ publicClient: publicClient,
56
+ network: 'mainnet',
57
+ accessToken: process.env.HERD_ACCESS_TOKEN,
58
+ };
59
+ cachedHerd = new HerdIntelligence(config);
60
+ return cachedHerd;
61
+ }
62
+ // ============================================================================
63
+ // Skill Definition
64
+ // ============================================================================
65
+ export const herdIntelligenceSkill = {
66
+ name: 'herd_intelligence',
67
+ description: 'On-chain intelligence powered by Herd MCP. ' +
68
+ 'Actions: investigate (contract/tx/wallet auto-detect), audit_token (security risk score 0-100), ' +
69
+ 'validate_swap (pre-swap safety check), validate_claim (fee claim validation), ' +
70
+ 'profile_counterparty (trust assessment), search_code (regex code search), ' +
71
+ 'track_token (token flow tracking), bookmark (list/add/remove), ' +
72
+ 'simulate (HAL expression builder for transfer/swap/balance/allowance/approve). ' +
73
+ 'All actions are read-only (no gas cost). Requires HERD_ACCESS_TOKEN.',
74
+ parameters: [
75
+ {
76
+ name: 'action',
77
+ type: 'string',
78
+ description: 'Action: investigate, audit_token, validate_swap, validate_claim, ' +
79
+ 'profile_counterparty, search_code, track_token, bookmark, simulate',
80
+ required: true,
81
+ },
82
+ {
83
+ name: 'target',
84
+ type: 'string',
85
+ description: 'Target address or tx hash. For investigate: auto-detects contract/tx/wallet. ' +
86
+ 'For audit_token/validate_claim/profile_counterparty: address. ' +
87
+ 'For search_code: contract address(es), comma-separated. ' +
88
+ 'For track_token: holder address.',
89
+ required: false,
90
+ },
91
+ {
92
+ name: 'token_in',
93
+ type: 'address',
94
+ description: 'Token-in address for validate_swap. For track_token: the token address.',
95
+ required: false,
96
+ },
97
+ {
98
+ name: 'token_out',
99
+ type: 'address',
100
+ description: 'Token-out address for validate_swap.',
101
+ required: false,
102
+ },
103
+ {
104
+ name: 'amount',
105
+ type: 'string',
106
+ description: 'Amount (human-readable) for validate_swap or simulate.',
107
+ required: false,
108
+ },
109
+ {
110
+ name: 'pattern',
111
+ type: 'string',
112
+ description: 'Regex or natural language query for search_code.',
113
+ required: false,
114
+ },
115
+ {
116
+ name: 'bookmark_action',
117
+ type: 'string',
118
+ description: 'For bookmark action: list, add, or remove.',
119
+ required: false,
120
+ },
121
+ {
122
+ name: 'label',
123
+ type: 'string',
124
+ description: 'Label/note for bookmark add.',
125
+ required: false,
126
+ },
127
+ {
128
+ name: 'bookmark_type',
129
+ type: 'string',
130
+ description: 'Bookmark type: contract, wallet, transaction.',
131
+ required: false,
132
+ },
133
+ {
134
+ name: 'simulate_type',
135
+ type: 'string',
136
+ description: 'For simulate: transfer, swap, balance, allowance, approve.',
137
+ required: false,
138
+ },
139
+ {
140
+ name: 'recipient',
141
+ type: 'address',
142
+ description: 'Recipient address for simulate transfer.',
143
+ required: false,
144
+ },
145
+ {
146
+ name: 'chain',
147
+ type: 'string',
148
+ description: 'Blockchain: base or ethereum. Defaults to base.',
149
+ required: false,
150
+ },
151
+ ],
152
+ execute: executeHerdIntelligence,
153
+ };
154
+ // ============================================================================
155
+ // Executor
156
+ // ============================================================================
157
+ async function executeHerdIntelligence(params, ctx) {
158
+ const action = params.action;
159
+ if (!action) {
160
+ return fail('Missing required parameter: action');
161
+ }
162
+ // Check tier permissions
163
+ const allowed = TIER_ALLOWED[ctx.survival.tier];
164
+ if (!allowed || !allowed.has(action)) {
165
+ return fail(`Action "${action}" not allowed at ${ctx.survival.tier} tier. ` +
166
+ `Available: ${[...allowed].join(', ')}`);
167
+ }
168
+ try {
169
+ const herd = await getHerd(ctx);
170
+ switch (action) {
171
+ case 'investigate':
172
+ return await actionInvestigate(herd, params);
173
+ case 'audit_token':
174
+ return await actionAuditToken(herd, params);
175
+ case 'validate_swap':
176
+ return await actionValidateSwap(herd, params);
177
+ case 'validate_claim':
178
+ return await actionValidateClaim(herd, params);
179
+ case 'profile_counterparty':
180
+ return await actionProfileCounterparty(herd, params);
181
+ case 'search_code':
182
+ return await actionSearchCode(herd, params);
183
+ case 'track_token':
184
+ return await actionTrackToken(herd, params);
185
+ case 'bookmark':
186
+ return await actionBookmark(herd, params);
187
+ case 'simulate':
188
+ return await actionSimulate(params);
189
+ default:
190
+ return fail(`Unknown action: "${action}". Valid: investigate, audit_token, validate_swap, ` +
191
+ `validate_claim, profile_counterparty, search_code, track_token, bookmark, simulate`);
192
+ }
193
+ }
194
+ catch (err) {
195
+ const msg = err instanceof Error ? err.message : String(err);
196
+ if (msg.includes('authentication required') || msg.includes('HERD_ACCESS_TOKEN')) {
197
+ return fail('Herd authentication required. Set HERD_ACCESS_TOKEN env var or run `clawncher herd auth`.');
198
+ }
199
+ return fail(msg);
200
+ }
201
+ }
202
+ // ============================================================================
203
+ // Actions
204
+ // ============================================================================
205
+ async function actionInvestigate(herd, params) {
206
+ const target = params.target;
207
+ if (!target) {
208
+ return fail('Missing required parameter: target (address or tx hash)');
209
+ }
210
+ const blockchain = params.chain || undefined;
211
+ // Auto-detect target type
212
+ if (isHash(target)) {
213
+ const profile = await herd.investigateTransaction(target, { blockchain });
214
+ return ok(formatTransactionProfile(profile));
215
+ }
216
+ if (isAddress(target)) {
217
+ // Try contract first
218
+ const profile = await herd.investigateContract(target, { blockchain });
219
+ if (profile.name || profile.functions.length > 0 || profile.proxy) {
220
+ return ok(formatContractProfile(profile));
221
+ }
222
+ // Fall back to wallet
223
+ const wallet = await herd.investigateWallet(target, { blockchain });
224
+ return ok(formatWalletProfile(wallet));
225
+ }
226
+ return fail('Invalid target. Provide a valid address (0x..., 42 chars) or tx hash (0x..., 66 chars).');
227
+ }
228
+ async function actionAuditToken(herd, params) {
229
+ const target = params.target;
230
+ if (!target || !isAddress(target)) {
231
+ return fail('Missing or invalid target address for audit_token.');
232
+ }
233
+ const blockchain = params.chain || undefined;
234
+ const audit = await herd.auditTokenSafety(target, { blockchain });
235
+ return ok(formatAuditReport(audit), {
236
+ riskScore: audit.riskScore,
237
+ riskLevel: audit.riskLevel,
238
+ findingCount: audit.findings.length,
239
+ });
240
+ }
241
+ async function actionValidateSwap(herd, params) {
242
+ const tokenIn = (params.token_in || params.target);
243
+ const tokenOut = params.token_out;
244
+ const amount = params.amount || '1.0';
245
+ if (!tokenIn || !isAddress(tokenIn)) {
246
+ return fail('Missing or invalid token_in address for validate_swap.');
247
+ }
248
+ if (!tokenOut || !isAddress(tokenOut)) {
249
+ return fail('Missing or invalid token_out address for validate_swap.');
250
+ }
251
+ const blockchain = params.chain || undefined;
252
+ const validation = await herd.validateSwapRoute(tokenIn, tokenOut, amount, { blockchain });
253
+ return ok(formatSwapValidation(validation), {
254
+ recommendation: validation.analysis.recommendation,
255
+ quoteReasonable: validation.analysis.quoteReasonable,
256
+ warningCount: validation.analysis.warnings.length,
257
+ });
258
+ }
259
+ async function actionValidateClaim(herd, params) {
260
+ const target = params.target;
261
+ if (!target || !isAddress(target)) {
262
+ return fail('Missing or invalid target token address for validate_claim.');
263
+ }
264
+ const blockchain = params.chain || undefined;
265
+ const validation = await herd.validateFeeClaim(target, { blockchain });
266
+ return ok(formatFeeClaimValidation(validation), {
267
+ estimateReliable: validation.analysis.estimateReliable,
268
+ estimatedNetProfitEth: validation.analysis.estimatedNetProfitEth,
269
+ warningCount: validation.analysis.warnings.length,
270
+ });
271
+ }
272
+ async function actionProfileCounterparty(herd, params) {
273
+ const target = params.target;
274
+ if (!target || !isAddress(target)) {
275
+ return fail('Missing or invalid target address for profile_counterparty.');
276
+ }
277
+ const blockchain = params.chain || undefined;
278
+ const profile = await herd.profileCounterparty(target, { blockchain });
279
+ return ok(formatCounterpartyProfile(profile), {
280
+ trustLevel: profile.riskAssessment.trustLevel,
281
+ factorCount: profile.riskAssessment.factors.length,
282
+ });
283
+ }
284
+ async function actionSearchCode(herd, params) {
285
+ const target = params.target;
286
+ const pattern = params.pattern;
287
+ if (!target) {
288
+ return fail('Missing target address(es) for search_code.');
289
+ }
290
+ if (!pattern) {
291
+ return fail('Missing required parameter: pattern (regex or query)');
292
+ }
293
+ // Support comma-separated addresses
294
+ const addresses = target.split(',').map((a) => a.trim());
295
+ for (const addr of addresses) {
296
+ if (!isAddress(addr)) {
297
+ return fail(`Invalid address in target list: ${addr}`);
298
+ }
299
+ }
300
+ const results = await herd.searchCode(addresses, pattern);
301
+ if (!results || results.trim().length === 0) {
302
+ return ok(`No matches found for "${pattern}" in ${addresses.join(', ')}`);
303
+ }
304
+ return ok(`Code search results for "${pattern}":\n${results}`);
305
+ }
306
+ async function actionTrackToken(herd, params) {
307
+ const holder = params.target;
308
+ const token = params.token_in;
309
+ if (!holder || !isAddress(holder)) {
310
+ return fail('Missing or invalid target (holder address) for track_token.');
311
+ }
312
+ if (!token || !isAddress(token)) {
313
+ return fail('Missing or invalid token_in (token address) for track_token.');
314
+ }
315
+ const blockchain = params.chain || undefined;
316
+ const flow = await herd.trackTokenFlow(holder, token, { blockchain });
317
+ return ok(formatTokenFlow(flow));
318
+ }
319
+ async function actionBookmark(herd, params) {
320
+ const subAction = params.bookmark_action || 'list';
321
+ switch (subAction) {
322
+ case 'list': {
323
+ const bookmarks = await herd.getBookmarks();
324
+ if (bookmarks.length === 0) {
325
+ return ok('No bookmarks saved.');
326
+ }
327
+ const lines = bookmarks.map((b, i) => `${i + 1}. [${b.objectType}] ${b.objectId}${b.label ? ` — ${b.label}` : ''}${b.blockchain ? ` (${b.blockchain})` : ''}`);
328
+ return ok(`=== Herd Bookmarks (${bookmarks.length}) ===\n${lines.join('\n')}`);
329
+ }
330
+ case 'add': {
331
+ const target = params.target;
332
+ if (!target) {
333
+ return fail('Missing target address/hash for bookmark add.');
334
+ }
335
+ const objType = params.bookmark_type || 'contract';
336
+ const label = params.label || undefined;
337
+ const chain = params.chain || undefined;
338
+ await herd.bookmark(objType, target, label, chain);
339
+ return ok(`Bookmarked ${target} as ${objType}${label ? ` (${label})` : ''}.`);
340
+ }
341
+ case 'remove': {
342
+ const target = params.target;
343
+ if (!target) {
344
+ return fail('Missing target address/hash for bookmark remove.');
345
+ }
346
+ const objType = params.bookmark_type || 'contract';
347
+ const chain = params.chain || undefined;
348
+ await herd.removeBookmark(objType, target, chain);
349
+ return ok(`Removed bookmark for ${target}.`);
350
+ }
351
+ default:
352
+ return fail(`Unknown bookmark_action: "${subAction}". Valid: list, add, remove.`);
353
+ }
354
+ }
355
+ async function actionSimulate(params) {
356
+ const simType = params.simulate_type;
357
+ if (!simType) {
358
+ return fail('Missing required parameter: simulate_type (transfer, swap, balance, allowance, approve)');
359
+ }
360
+ const target = params.target;
361
+ const chain = params.chain || 'base';
362
+ const hal = new HalBuilder();
363
+ try {
364
+ let expression;
365
+ switch (simType) {
366
+ case 'transfer': {
367
+ if (!target)
368
+ return fail('Missing target (token address) for transfer simulation.');
369
+ expression = hal.buildTransferAdapter({ token: target, blockchain: chain });
370
+ break;
371
+ }
372
+ case 'swap': {
373
+ const sellToken = (params.token_in || target);
374
+ const buyToken = params.token_out;
375
+ if (!sellToken)
376
+ return fail('Missing token_in (sell token) for swap simulation.');
377
+ if (!buyToken)
378
+ return fail('Missing token_out (buy token) for swap simulation.');
379
+ expression = hal.buildSwapAction({ sellToken, buyToken, blockchain: chain });
380
+ break;
381
+ }
382
+ case 'balance': {
383
+ if (!target)
384
+ return fail('Missing target (token address) for balance read.');
385
+ expression = hal.buildBalanceReader({ token: target, blockchain: chain });
386
+ break;
387
+ }
388
+ case 'allowance': {
389
+ if (!target)
390
+ return fail('Missing target (token address) for allowance read.');
391
+ const spender = params.recipient;
392
+ expression = hal.buildAllowanceReader({ token: target, blockchain: chain, spender });
393
+ break;
394
+ }
395
+ case 'approve': {
396
+ if (!target)
397
+ return fail('Missing target (token address) for approve.');
398
+ expression = hal.buildApproveAdapter({ token: target, blockchain: chain });
399
+ break;
400
+ }
401
+ default:
402
+ return fail(`Unknown simulate_type: "${simType}". Valid: transfer, swap, balance, allowance, approve.`);
403
+ }
404
+ const exprJson = JSON.stringify(expression, null, 2);
405
+ return ok(`HAL Expression (${simType}):\n${exprJson}\n\nUse this expression with a HAL-compatible simulator to preview the result.`);
406
+ }
407
+ catch (err) {
408
+ return fail(`Failed to build HAL expression: ${err instanceof Error ? err.message : String(err)}`);
409
+ }
410
+ }
411
+ // ============================================================================
412
+ // Formatters
413
+ // ============================================================================
414
+ function formatContractProfile(p) {
415
+ const lines = [
416
+ `=== Contract: ${p.address} ===`,
417
+ p.name ? `Name: ${p.name}` : '',
418
+ p.compiler ? `Compiler: ${p.compiler}` : '',
419
+ p.protocol ? `Protocol: ${p.protocol}` : '',
420
+ p.verified ? 'Verified: Yes' : 'Verified: No',
421
+ p.proxy ? `Proxy: ${p.proxy.proxyType} → ${p.proxy.currentImplementation}` : '',
422
+ ];
423
+ if (p.token) {
424
+ lines.push(`\nToken: ${p.token.symbol}`);
425
+ lines.push(` Decimals: ${p.token.decimals}`);
426
+ if (p.token.priceUsd !== null)
427
+ lines.push(` Price: $${p.token.priceUsd}`);
428
+ if (p.token.marketCap !== null)
429
+ lines.push(` Market Cap: $${formatLargeNumber(p.token.marketCap)}`);
430
+ if (p.token.holders !== null)
431
+ lines.push(` Holders: ${p.token.holders}`);
432
+ }
433
+ if (p.clawncher) {
434
+ lines.push(`\nClawncher Token: Yes`);
435
+ lines.push(` Fees (WETH): ${p.clawncher.feesWeth}`);
436
+ lines.push(` Fees (Token): ${p.clawncher.feesToken}`);
437
+ lines.push(` Vault: ${p.clawncher.vaultStatus}`);
438
+ lines.push(` MEV Protection: ${p.clawncher.mevProtection ? 'Yes' : 'No'}`);
439
+ if (p.clawncher.agent)
440
+ lines.push(` Agent: ${p.clawncher.agent}`);
441
+ }
442
+ if (p.securityFlags.length > 0) {
443
+ lines.push(`\nSecurity Flags (${p.securityFlags.length}):`);
444
+ for (const f of p.securityFlags) {
445
+ lines.push(` [${f.severity}] ${f.category}: ${f.description}`);
446
+ }
447
+ }
448
+ if (p.functions.length > 0) {
449
+ const reads = p.functions.filter((f) => f.type === 'read');
450
+ const writes = p.functions.filter((f) => f.type === 'write');
451
+ lines.push(`\nFunctions: ${p.functions.length} (${reads.length} read, ${writes.length} write)`);
452
+ for (const fn of p.functions.slice(0, 10)) {
453
+ lines.push(` [${fn.type}] ${fn.name}(${fn.inputs.map((i) => `${i.type} ${i.name}`).join(', ')})`);
454
+ }
455
+ if (p.functions.length > 10)
456
+ lines.push(` ... and ${p.functions.length - 10} more`);
457
+ }
458
+ return lines.filter(Boolean).join('\n');
459
+ }
460
+ function formatTransactionProfile(p) {
461
+ const lines = [
462
+ `=== Transaction: ${p.hash} ===`,
463
+ `Status: ${p.success ? 'Success' : 'Failed'}`,
464
+ `Block: ${p.blockNumber}`,
465
+ `Timestamp: ${p.timestamp}`,
466
+ p.functionCalled ? `Function: ${p.functionCalled}` : '',
467
+ p.revertReason ? `Revert: ${p.revertReason}` : '',
468
+ ];
469
+ lines.push(`\nGas: ${p.gas.gasUsed} used, ${p.gas.costEth} ETH${p.gas.costUsd ? ` ($${p.gas.costUsd})` : ''}`);
470
+ if (p.balanceChanges.length > 0) {
471
+ lines.push(`\nBalance Changes (${p.balanceChanges.length}):`);
472
+ for (const bc of p.balanceChanges.slice(0, 10)) {
473
+ lines.push(` ${bc.token}: ${bc.from} → ${bc.to} (${bc.amount}${bc.usdValue ? `, $${bc.usdValue}` : ''})`);
474
+ }
475
+ if (p.balanceChanges.length > 10)
476
+ lines.push(` ... and ${p.balanceChanges.length - 10} more`);
477
+ }
478
+ if (p.events.length > 0) {
479
+ lines.push(`\nEvents (${p.events.length}):`);
480
+ for (const e of p.events.slice(0, 8)) {
481
+ lines.push(` ${e.eventName}${e.contractName ? ` @ ${e.contractName}` : ''} (${e.contract})`);
482
+ }
483
+ if (p.events.length > 8)
484
+ lines.push(` ... and ${p.events.length - 8} more`);
485
+ }
486
+ if (p.clawncher) {
487
+ lines.push(`\nClawncher: ${p.clawncher.operationType}`);
488
+ lines.push(` ${p.clawncher.description}`);
489
+ if (p.clawncher.tokenAddress)
490
+ lines.push(` Token: ${p.clawncher.tokenAddress}`);
491
+ }
492
+ return lines.filter(Boolean).join('\n');
493
+ }
494
+ function formatWalletProfile(p) {
495
+ const lines = [
496
+ `=== Wallet: ${p.address} ===`,
497
+ `Type: ${p.walletType}`,
498
+ p.totalValueUsd !== null ? `Total Value: $${formatLargeNumber(p.totalValueUsd)}` : '',
499
+ ];
500
+ if (p.activity) {
501
+ lines.push(`Transactions: ${p.activity.transactionCount}`);
502
+ lines.push(`Contracts Deployed: ${p.activity.contractsDeployed}`);
503
+ if (p.activity.firstTransaction)
504
+ lines.push(`First Active: ${p.activity.firstTransaction}`);
505
+ }
506
+ if (p.holdings.length > 0) {
507
+ lines.push(`\nTop Holdings (${p.holdings.length}):`);
508
+ for (const h of p.holdings.slice(0, 10)) {
509
+ lines.push(` ${h.token}: ${h.balance}${h.usdValue !== null ? ` ($${formatLargeNumber(h.usdValue)})` : ''}`);
510
+ }
511
+ if (p.holdings.length > 10)
512
+ lines.push(` ... and ${p.holdings.length - 10} more`);
513
+ }
514
+ if (p.multisig) {
515
+ lines.push(`\nMultisig: ${p.multisig.threshold}/${p.multisig.signers.length} signers`);
516
+ lines.push(` Pending: ${p.multisig.pendingTransactions} txs`);
517
+ }
518
+ if (p.clawncher) {
519
+ lines.push(`\nClawncher:`);
520
+ lines.push(` Registered Agent: ${p.clawncher.isRegisteredAgent ? 'Yes' : 'No'}`);
521
+ if (p.clawncher.tokenPositions.length > 0) {
522
+ lines.push(` Token Positions (${p.clawncher.tokenPositions.length}):`);
523
+ for (const pos of p.clawncher.tokenPositions) {
524
+ lines.push(` ${pos.symbol}: ${pos.balance}`);
525
+ if (pos.claimableFees) {
526
+ lines.push(` Fees: ${pos.claimableFees.weth} WETH, ${pos.claimableFees.token} token`);
527
+ }
528
+ }
529
+ }
530
+ }
531
+ return lines.filter(Boolean).join('\n');
532
+ }
533
+ function formatAuditReport(a) {
534
+ const lines = [
535
+ `=== Token Audit: ${a.contract.address} ===`,
536
+ `Risk Score: ${a.riskScore}/100 (${a.riskLevel})`,
537
+ '',
538
+ `Upgradeable: ${a.isUpgradeable ? 'Yes' : 'No'}`,
539
+ `Owner Controls: ${a.hasOwnerControls ? 'Yes' : 'No'}`,
540
+ `Mint Function: ${a.hasMintFunction ? 'Yes' : 'No'}`,
541
+ `Pause/Blacklist: ${a.hasPauseOrBlacklist ? 'Yes' : 'No'}`,
542
+ ];
543
+ if (a.findings.length > 0) {
544
+ lines.push(`\nFindings (${a.findings.length}):`);
545
+ for (const f of a.findings) {
546
+ lines.push(` [${f.severity}] ${f.category}: ${f.description}`);
547
+ }
548
+ }
549
+ if (a.checksPerformed.length > 0) {
550
+ lines.push(`\nChecks Performed: ${a.checksPerformed.join(', ')}`);
551
+ }
552
+ lines.push(`\nAudited: ${a.auditedAt}`);
553
+ return lines.filter(Boolean).join('\n');
554
+ }
555
+ function formatSwapValidation(v) {
556
+ const lines = [
557
+ `=== Swap Validation ===`,
558
+ `${v.tokenIn} → ${v.tokenOut}`,
559
+ `Amount In: ${v.amountIn}`,
560
+ `Recommendation: ${v.analysis.recommendation.toUpperCase()}`,
561
+ `Quote Reasonable: ${v.analysis.quoteReasonable ? 'Yes' : 'No'}`,
562
+ '',
563
+ ];
564
+ if (v.ourQuote) {
565
+ lines.push(`Our Quote:`);
566
+ lines.push(` Amount Out: ${v.ourQuote.amountOut}`);
567
+ lines.push(` Price Impact: ${v.ourQuote.priceImpact}%`);
568
+ }
569
+ if (v.analysis.deviationPercent !== null) {
570
+ lines.push(`Deviation from Historical: ${v.analysis.deviationPercent.toFixed(2)}%`);
571
+ }
572
+ if (v.historicalSwaps.length > 0) {
573
+ lines.push(`\nRecent Swaps (${v.historicalSwaps.length}):`);
574
+ for (const s of v.historicalSwaps.slice(0, 5)) {
575
+ lines.push(` ${s.timestamp}: ${s.amountIn} → ${s.amountOut} (rate: ${s.effectiveRate})`);
576
+ }
577
+ }
578
+ if (v.analysis.warnings.length > 0) {
579
+ lines.push(`\nWarnings:`);
580
+ for (const w of v.analysis.warnings) {
581
+ lines.push(` - ${w}`);
582
+ }
583
+ }
584
+ return lines.filter(Boolean).join('\n');
585
+ }
586
+ function formatFeeClaimValidation(v) {
587
+ const lines = [
588
+ `=== Fee Claim Validation ===`,
589
+ `Token: ${v.tokenAddress}`,
590
+ `Estimate Reliable: ${v.analysis.estimateReliable ? 'Yes' : 'No'}`,
591
+ '',
592
+ ];
593
+ if (v.ourEstimate) {
594
+ lines.push(`Our Estimate:`);
595
+ lines.push(` WETH Available: ${v.ourEstimate.wethAvailable}`);
596
+ lines.push(` Token Available: ${v.ourEstimate.tokenAvailable}`);
597
+ }
598
+ if (v.analysis.avgGasCostEth) {
599
+ lines.push(`Avg Gas Cost: ${v.analysis.avgGasCostEth} ETH`);
600
+ }
601
+ if (v.analysis.estimatedNetProfitEth) {
602
+ lines.push(`Estimated Net Profit: ${v.analysis.estimatedNetProfitEth} ETH`);
603
+ }
604
+ if (v.historicalClaims.length > 0) {
605
+ lines.push(`\nRecent Claims (${v.historicalClaims.length}):`);
606
+ for (const c of v.historicalClaims.slice(0, 5)) {
607
+ lines.push(` ${c.timestamp}: ${c.wethReceived} WETH, ${c.tokenReceived} token (gas: ${c.gasCostEth} ETH)`);
608
+ }
609
+ }
610
+ if (v.analysis.warnings.length > 0) {
611
+ lines.push(`\nWarnings:`);
612
+ for (const w of v.analysis.warnings) {
613
+ lines.push(` - ${w}`);
614
+ }
615
+ }
616
+ return lines.filter(Boolean).join('\n');
617
+ }
618
+ function formatCounterpartyProfile(p) {
619
+ const lines = [
620
+ `=== Counterparty: ${p.wallet.address} ===`,
621
+ `Trust Level: ${p.riskAssessment.trustLevel}`,
622
+ `Wallet Type: ${p.wallet.walletType}`,
623
+ p.walletAge ? `Account Age: ${p.walletAge}` : '',
624
+ '',
625
+ ];
626
+ if (p.wallet.activity) {
627
+ lines.push(`Transactions: ${p.wallet.activity.transactionCount}`);
628
+ }
629
+ if (p.deployedContracts.length > 0) {
630
+ lines.push(`\nDeployed Contracts (${p.deployedContracts.length}):`);
631
+ for (const c of p.deployedContracts.slice(0, 5)) {
632
+ lines.push(` ${c.address}${c.name ? ` (${c.name})` : ''} — ${c.verified ? 'verified' : 'unverified'}`);
633
+ }
634
+ }
635
+ if (p.riskAssessment.factors.length > 0) {
636
+ lines.push(`\nRisk Factors:`);
637
+ for (const f of p.riskAssessment.factors) {
638
+ lines.push(` - ${f}`);
639
+ }
640
+ }
641
+ return lines.filter(Boolean).join('\n');
642
+ }
643
+ function formatTokenFlow(flow) {
644
+ const lines = [
645
+ `=== Token Flow: ${flow.tokenSymbol} ===`,
646
+ `Holder: ${flow.holder}`,
647
+ `Token: ${flow.token}`,
648
+ `Current Balance: ${flow.currentBalance}`,
649
+ '',
650
+ ];
651
+ if (flow.transfers.length > 0) {
652
+ lines.push(`Transfers (${flow.transfers.length}):`);
653
+ for (const t of flow.transfers.slice(0, 20)) {
654
+ const counterpartyLabel = t.counterpartyName || `${t.counterparty.slice(0, 10)}...`;
655
+ lines.push(` ${t.timestamp} ${t.direction === 'in' ? '←' : '→'} ${counterpartyLabel}: ${t.amount}${t.usdValue ? ` ($${t.usdValue})` : ''}`);
656
+ }
657
+ if (flow.transfers.length > 20) {
658
+ lines.push(` ... and ${flow.transfers.length - 20} more`);
659
+ }
660
+ }
661
+ if (flow.annotations.length > 0) {
662
+ lines.push(`\nAnnotations:`);
663
+ for (const a of flow.annotations) {
664
+ lines.push(` ${a.label} (transfers: ${a.transferIndices.join(', ')})`);
665
+ }
666
+ }
667
+ return lines.filter(Boolean).join('\n');
668
+ }
669
+ // ============================================================================
670
+ // Helpers
671
+ // ============================================================================
672
+ function ok(result, metadata) {
673
+ return { callId: '', success: true, result, metadata };
674
+ }
675
+ function fail(error) {
676
+ return { callId: '', success: false, result: null, error };
677
+ }
678
+ function formatLargeNumber(n) {
679
+ if (n >= 1_000_000_000)
680
+ return `${(n / 1_000_000_000).toFixed(2)}B`;
681
+ if (n >= 1_000_000)
682
+ return `${(n / 1_000_000).toFixed(2)}M`;
683
+ if (n >= 1_000)
684
+ return `${(n / 1_000).toFixed(2)}K`;
685
+ return n.toFixed(2);
686
+ }
687
+ //# sourceMappingURL=herd.js.map