opencode-froggy 0.2.0 → 0.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.
Files changed (42) hide show
  1. package/README.md +250 -25
  2. package/command/commit-push.md +1 -1
  3. package/command/diff-summary.md +19 -0
  4. package/command/doc-changes.md +1 -1
  5. package/command/review-changes.md +15 -1
  6. package/command/review-pr.md +17 -2
  7. package/command/simplify-changes.md +1 -1
  8. package/dist/index.js +12 -3
  9. package/dist/tools/blockchain/eth-address-balance.d.ts +20 -0
  10. package/dist/tools/blockchain/eth-address-balance.js +37 -0
  11. package/dist/tools/blockchain/eth-address-txs.d.ts +23 -0
  12. package/dist/tools/blockchain/eth-address-txs.js +41 -0
  13. package/dist/tools/blockchain/eth-token-transfers.d.ts +23 -0
  14. package/dist/tools/blockchain/eth-token-transfers.js +41 -0
  15. package/dist/tools/blockchain/eth-transaction.d.ts +34 -0
  16. package/dist/tools/blockchain/eth-transaction.js +203 -0
  17. package/dist/tools/blockchain/etherscan-client.d.ts +26 -0
  18. package/dist/tools/blockchain/etherscan-client.js +174 -0
  19. package/dist/tools/blockchain/etherscan-client.test.d.ts +1 -0
  20. package/dist/tools/blockchain/etherscan-client.test.js +211 -0
  21. package/dist/tools/blockchain/event-decoder.d.ts +14 -0
  22. package/dist/tools/blockchain/event-decoder.js +96 -0
  23. package/dist/tools/blockchain/event-decoder.test.d.ts +1 -0
  24. package/dist/tools/blockchain/event-decoder.test.js +197 -0
  25. package/dist/tools/blockchain/formatters.d.ts +10 -0
  26. package/dist/tools/blockchain/formatters.js +147 -0
  27. package/dist/tools/blockchain/index.d.ts +10 -0
  28. package/dist/tools/blockchain/index.js +10 -0
  29. package/dist/tools/blockchain/tools.test.d.ts +1 -0
  30. package/dist/tools/blockchain/tools.test.js +208 -0
  31. package/dist/tools/blockchain/types.d.ts +154 -0
  32. package/dist/tools/blockchain/types.js +8 -0
  33. package/dist/tools/blockchain/viem-client.d.ts +9 -0
  34. package/dist/tools/blockchain/viem-client.js +98 -0
  35. package/dist/tools/index.d.ts +1 -1
  36. package/dist/tools/index.js +1 -1
  37. package/package.json +3 -2
  38. package/skill/code-simplify/SKILL.md +6 -0
  39. package/dist/tools/diff-summary.d.ts +0 -20
  40. package/dist/tools/diff-summary.js +0 -111
  41. package/dist/tools/reply-child.d.ts +0 -19
  42. package/dist/tools/reply-child.js +0 -42
package/README.md CHANGED
@@ -21,6 +21,12 @@ Plugin providing Claude Code–style hooks, specialized agents (doc-writer, code
21
21
  - [diff-summary](#diff-summary)
22
22
  - [prompt-session](#prompt-session)
23
23
  - [list-child-sessions](#list-child-sessions)
24
+ - [Blockchain](#blockchain)
25
+ - [Configuration](#configuration)
26
+ - [eth-transaction](#eth-transaction)
27
+ - [eth-address-balance](#eth-address-balance)
28
+ - [eth-address-txs](#eth-address-txs)
29
+ - [eth-token-transfers](#eth-token-transfers)
24
30
  - [Hooks](#hooks)
25
31
  - [Configuration Locations](#configuration-locations)
26
32
  - [Configuration File Format](#configuration-file-format)
@@ -135,38 +141,26 @@ gitingest({
135
141
 
136
142
  ### diff-summary
137
143
 
138
- Generate a structured summary of git diffs. Use for reviewing branch comparisons or working tree changes. Returns stats, commits, files changed, and full diff in a structured markdown format.
144
+ **Command** that displays a structured summary of git working tree changes (staged, unstaged, and untracked files). Injects git diff output directly into the prompt using bash commands.
139
145
 
140
- #### Parameters
146
+ #### Usage
141
147
 
142
- | Parameter | Type | Required | Default | Description |
143
- |-----------|------|----------|---------|-------------|
144
- | `source` | `string` | No | - | Source branch to compare (e.g., `feature-branch`). If omitted, analyzes working tree changes. |
145
- | `target` | `string` | No | `main` | Target branch to compare against |
146
- | `remote` | `string` | No | `origin` | Git remote name |
148
+ ```bash
149
+ /diff-summary
150
+ ```
147
151
 
148
- #### Usage Examples
152
+ #### What it shows
149
153
 
150
- ```typescript
151
- // Analyze working tree changes (staged, unstaged, and untracked files)
152
- diffSummary({})
154
+ - Git status (porcelain format)
155
+ - Staged changes (stats and full diff)
156
+ - Unstaged changes (stats and full diff)
157
+ - Untracked files content (first 50 lines of each file)
153
158
 
154
- // Compare feature branch against main
155
- diffSummary({ source: "feature-branch" })
159
+ #### Implementation
156
160
 
157
- // Compare feature branch against develop
158
- diffSummary({
159
- source: "feature-branch",
160
- target: "develop"
161
- })
161
+ This command uses OpenCode's `!`\`...\`` syntax to inject bash command output directly into the prompt, avoiding the 2000-line truncation limit that affects tools.
162
162
 
163
- // Compare branches on a different remote
164
- diffSummary({
165
- source: "feature-branch",
166
- target: "main",
167
- remote: "upstream"
168
- })
169
- ```
163
+ See `command/diff-summary.md` for the full implementation.
170
164
 
171
165
  #### Output Structure
172
166
 
@@ -256,6 +250,237 @@ Child sessions (2):
256
250
 
257
251
  ---
258
252
 
253
+ ### Blockchain
254
+
255
+ Tools for querying Ethereum and EVM-compatible blockchains via Etherscan APIs.
256
+
257
+ All blockchain tools support multiple chains via the `chainId` parameter:
258
+
259
+ | Chain ID | Network |
260
+ |----------|---------|
261
+ | `1` | Ethereum (default) |
262
+ | `137` | Polygon |
263
+ | `56` | BSC |
264
+ | `42161` | Arbitrum |
265
+ | `10` | Optimism |
266
+ | `8453` | Base |
267
+ | `43114` | Avalanche |
268
+ | `250` | Fantom |
269
+ | `324` | zkSync |
270
+
271
+ #### Configuration
272
+
273
+ The blockchain tools use Etherscan-compatible APIs. An API key is optional but recommended.
274
+
275
+ **Environment Variable:**
276
+
277
+ | Variable | Required | Description |
278
+ |----------|----------|-------------|
279
+ | `ETHERSCAN_API_KEY` | No | API key for Etherscan and compatible explorers |
280
+
281
+ **Without an API key:** Requests are rate-limited (typically 1 request per 5 seconds).
282
+
283
+ **With an API key:** Higher rate limits and more reliable access.
284
+
285
+ **Getting an API key:**
286
+
287
+ 1. Create a free account at [etherscan.io](https://etherscan.io/register)
288
+ 2. Navigate to API Keys in your account settings
289
+ 3. Generate a new API key
290
+
291
+ **Setting the environment variable:**
292
+
293
+ ```bash
294
+ export ETHERSCAN_API_KEY="your-api-key-here"
295
+ ```
296
+
297
+ #### eth-transaction
298
+
299
+ Get Ethereum transaction details by transaction hash. Returns status, block, addresses, gas costs in JSON format. Use optional parameters to include internal transactions, token transfers, and decoded event logs.
300
+
301
+ ##### Parameters
302
+
303
+ | Parameter | Type | Required | Default | Description |
304
+ |-----------|------|----------|---------|-------------|
305
+ | `hash` | `string` | Yes | - | Transaction hash (0x...) |
306
+ | `chainId` | `string` | No | `"1"` | Chain ID (see table above) |
307
+ | `includeInternalTxs` | `boolean` | No | `false` | Include internal transactions (ETH transfers between contracts) |
308
+ | `includeTokenTransfers` | `boolean` | No | `false` | Include ERC-20 token transfers |
309
+ | `decodeLogs` | `boolean` | No | `false` | Decode event logs (Transfer, Approval, Deposit, Withdrawal) |
310
+
311
+ ##### Usage Examples
312
+
313
+ ```typescript
314
+ // Get basic transaction details on Ethereum mainnet
315
+ ethTransaction({ hash: "0x123abc..." })
316
+
317
+ // Get transaction on Polygon
318
+ ethTransaction({
319
+ hash: "0x123abc...",
320
+ chainId: "137"
321
+ })
322
+
323
+ // Get transaction with internal transactions and token transfers
324
+ ethTransaction({
325
+ hash: "0x123abc...",
326
+ includeInternalTxs: true,
327
+ includeTokenTransfers: true
328
+ })
329
+
330
+ // Get full transaction details with decoded event logs
331
+ ethTransaction({
332
+ hash: "0x123abc...",
333
+ includeInternalTxs: true,
334
+ includeTokenTransfers: true,
335
+ decodeLogs: true
336
+ })
337
+ ```
338
+
339
+ ##### Output Structure
340
+
341
+ The tool returns JSON with labeled addresses (contract names resolved via Etherscan):
342
+
343
+ ```json
344
+ {
345
+ "hash": "0x123...",
346
+ "status": "success",
347
+ "block": 12345678,
348
+ "from": { "address": "0xabc...", "label": "Uniswap V3: Router" },
349
+ "to": { "address": "0xdef...", "label": "WETH" },
350
+ "value": "0",
351
+ "gas": { "used": 150000, "price": "20000000000", "cost": "0.003" }
352
+ }
353
+ ```
354
+
355
+ With `includeInternalTxs: true`:
356
+ ```json
357
+ {
358
+ "internalTransactions": [
359
+ {
360
+ "from": { "address": "0x...", "label": "Uniswap V3: Router" },
361
+ "to": { "address": "0x...", "label": null },
362
+ "value": "1.5",
363
+ "type": "call"
364
+ }
365
+ ]
366
+ }
367
+ ```
368
+
369
+ With `includeTokenTransfers: true`:
370
+ ```json
371
+ {
372
+ "tokenTransfers": [
373
+ {
374
+ "token": { "address": "0x...", "name": "Wrapped Ether", "symbol": "WETH", "decimals": 18 },
375
+ "from": { "address": "0x...", "label": null },
376
+ "to": { "address": "0x...", "label": "Uniswap V3: Router" },
377
+ "value": "1.5"
378
+ }
379
+ ]
380
+ }
381
+ ```
382
+
383
+ With `decodeLogs: true`:
384
+ ```json
385
+ {
386
+ "decodedEvents": [
387
+ {
388
+ "name": "Transfer",
389
+ "address": { "address": "0x...", "label": "WETH" },
390
+ "params": { "from": "0x...", "to": "0x...", "value": "1500000000000000000" }
391
+ }
392
+ ],
393
+ "undecodedEventsCount": 2
394
+ }
395
+ ```
396
+
397
+ ##### Supported Decoded Events
398
+
399
+ | Event | Description |
400
+ |-------|-------------|
401
+ | `Transfer` | ERC-20 token transfer |
402
+ | `Approval` | ERC-20 approval for spending |
403
+ | `Deposit` | WETH deposit (ETH → WETH) |
404
+ | `Withdrawal` | WETH withdrawal (WETH → ETH) |
405
+
406
+ #### eth-address-balance
407
+
408
+ Get the ETH balance of an Ethereum address. Returns balance in both ETH and Wei.
409
+
410
+ ##### Parameters
411
+
412
+ | Parameter | Type | Required | Default | Description |
413
+ |-----------|------|----------|---------|-------------|
414
+ | `address` | `string` | Yes | - | Ethereum address (0x...) |
415
+ | `chainId` | `string` | No | `"1"` | Chain ID (see table above) |
416
+
417
+ ##### Usage Examples
418
+
419
+ ```typescript
420
+ // Get balance on Ethereum mainnet
421
+ ethAddressBalance({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" })
422
+
423
+ // Get balance on Arbitrum
424
+ ethAddressBalance({
425
+ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
426
+ chainId: "42161"
427
+ })
428
+ ```
429
+
430
+ #### eth-address-txs
431
+
432
+ List Ethereum transactions for an address. Shows incoming and outgoing transactions with values, timestamps, and status.
433
+
434
+ ##### Parameters
435
+
436
+ | Parameter | Type | Required | Default | Description |
437
+ |-----------|------|----------|---------|-------------|
438
+ | `address` | `string` | Yes | - | Ethereum address (0x...) |
439
+ | `limit` | `number` | No | `20` | Maximum number of transactions to return |
440
+ | `chainId` | `string` | No | `"1"` | Chain ID (see table above) |
441
+
442
+ ##### Usage Examples
443
+
444
+ ```typescript
445
+ // List recent transactions on Ethereum mainnet
446
+ ethAddressTxs({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" })
447
+
448
+ // List last 50 transactions on Base
449
+ ethAddressTxs({
450
+ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
451
+ limit: 50,
452
+ chainId: "8453"
453
+ })
454
+ ```
455
+
456
+ #### eth-token-transfers
457
+
458
+ List ERC-20 token transfers for an Ethereum address. Shows token names, symbols, values, and transaction details.
459
+
460
+ ##### Parameters
461
+
462
+ | Parameter | Type | Required | Default | Description |
463
+ |-----------|------|----------|---------|-------------|
464
+ | `address` | `string` | Yes | - | Ethereum address (0x...) |
465
+ | `limit` | `number` | No | `20` | Maximum number of transfers to return |
466
+ | `chainId` | `string` | No | `"1"` | Chain ID (see table above) |
467
+
468
+ ##### Usage Examples
469
+
470
+ ```typescript
471
+ // List recent token transfers on Ethereum mainnet
472
+ ethTokenTransfers({ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" })
473
+
474
+ // List last 100 token transfers on Optimism
475
+ ethTokenTransfers({
476
+ address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
477
+ limit: 100,
478
+ chainId: "10"
479
+ })
480
+ ```
481
+
482
+ ---
483
+
259
484
  ## Hooks
260
485
 
261
486
  Hooks run actions on session events. Configuration is loaded from standard OpenCode configuration directories.
@@ -9,7 +9,7 @@ agent: build
9
9
 
10
10
  ## Your task
11
11
 
12
- 1. Use the `diff-summary` tool (without parameters) to analyze all working tree changes
12
+ 1. Run `/diff-summary` to analyze all working tree changes
13
13
  2. Present a summary to the user:
14
14
  - Files modified/added/deleted with stats
15
15
  - Proposed commit message based on the changes
@@ -0,0 +1,19 @@
1
+ ---
2
+ description: Show working tree changes (staged, unstaged, untracked)
3
+ ---
4
+
5
+ # Diff Summary: Working Tree → HEAD
6
+
7
+ ## Status
8
+ !`git status --porcelain`
9
+
10
+ ## Staged Changes
11
+ !`git diff --cached --stat`
12
+ !`git diff --cached`
13
+
14
+ ## Unstaged Changes
15
+ !`git diff --stat`
16
+ !`git diff`
17
+
18
+ ## Untracked Files Content
19
+ !`bash -c 'git ls-files --others --exclude-standard | while read f; do [ -f "$f" ] && echo "=== $f ===" && sed -n "1,50p" "$f" && sed -n "51p" "$f" | grep -q . && echo "... (truncated)"; done'`
@@ -5,7 +5,7 @@ agent: doc-writer
5
5
 
6
6
  ## Analysis Phase
7
7
 
8
- Use the `diff-summary` tool (without parameters) to get the working tree changes, then:
8
+ Run `/diff-summary` to get the working tree changes, then:
9
9
 
10
10
  1. **Identify new features** in the changes:
11
11
  - New public APIs, functions, or methods
@@ -5,4 +5,18 @@ agent: code-reviewer
5
5
 
6
6
  # Review: Working Tree → HEAD
7
7
 
8
- Use the `diff-summary` tool (without parameters) to get the working tree changes, then review them.
8
+ ## Status
9
+ !`git status --porcelain`
10
+
11
+ ## Staged Changes
12
+ !`git diff --cached --stat`
13
+ !`git diff --cached`
14
+
15
+ ## Unstaged Changes
16
+ !`git diff --stat`
17
+ !`git diff`
18
+
19
+ ## Untracked Files Content
20
+ !`bash -c 'git ls-files --others --exclude-standard | while read f; do [ -f "$f" ] && echo "=== $f ===" && sed -n "1,50p" "$f" && sed -n "51p" "$f" | grep -q . && echo "... (truncated)"; done'`
21
+
22
+ Review the above changes for quality, correctness, and adherence to project guidelines.
@@ -3,6 +3,21 @@ description: Review changes from source branch into target branch
3
3
  agent: code-reviewer
4
4
  ---
5
5
 
6
- # Review: origin/$1 → origin/$2
6
+ # Review: $1 → $2
7
7
 
8
- Use the `diff-summary` tool with `source: "$1"` and `target: "$2"` to get the diff, then review the changes.
8
+ ## Fetch latest
9
+ !`git fetch --all --prune 2>/dev/null || true`
10
+
11
+ ## Stats Overview
12
+ !`git diff --stat $2...$1`
13
+
14
+ ## Commits to Review
15
+ !`git log --oneline --no-merges $2..$1`
16
+
17
+ ## Files Changed
18
+ !`git diff --name-only $2...$1`
19
+
20
+ ## Full Diff
21
+ !`git diff -U5 --function-context $2...$1`
22
+
23
+ Review the above changes for quality, correctness, and adherence to project guidelines.
@@ -5,4 +5,4 @@ agent: code-simplifier
5
5
 
6
6
  # Simplify: Working Tree → HEAD
7
7
 
8
- Use the `diff-summary` tool (without parameters) to get the working tree changes, then simplify them.
8
+ Run `/diff-summary` to get the working tree changes, then simplify them.
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { getGlobalHookDir, getProjectHookDir } from "./config-paths";
5
5
  import { hasCodeExtension } from "./code-files";
6
6
  import { log } from "./logger";
7
7
  import { executeBashAction, DEFAULT_BASH_TIMEOUT, } from "./bash-executor";
8
- import { gitingestTool, createDiffSummaryTool, createPromptSessionTool, createListChildSessionsTool, } from "./tools";
8
+ import { gitingestTool, createPromptSessionTool, createListChildSessionsTool, ethTransactionTool, ethAddressTxsTool, ethAddressBalanceTool, ethTokenTransfersTool, } from "./tools";
9
9
  export { parseFrontmatter, loadAgents, loadCommands } from "./loaders";
10
10
  // ============================================================================
11
11
  // CONSTANTS
@@ -30,7 +30,13 @@ const SmartfrogPlugin = async (ctx) => {
30
30
  agents: Object.keys(agents),
31
31
  commands: Object.keys(commands),
32
32
  hooks: Array.from(hooks.keys()),
33
- tools: ["gitingest", "diff-summary"],
33
+ tools: [
34
+ "gitingest",
35
+ "eth-transaction",
36
+ "eth-address-txs",
37
+ "eth-address-balance",
38
+ "eth-token-transfers",
39
+ ],
34
40
  });
35
41
  async function executeHookActions(hook, sessionID, extraLog, options) {
36
42
  const prefix = `[hook:${hook.event}]`;
@@ -176,9 +182,12 @@ const SmartfrogPlugin = async (ctx) => {
176
182
  },
177
183
  tool: {
178
184
  gitingest: gitingestTool,
179
- "diff-summary": createDiffSummaryTool(ctx.directory),
180
185
  "prompt-session": createPromptSessionTool(ctx.client),
181
186
  "list-child-sessions": createListChildSessionsTool(ctx.client),
187
+ "eth-transaction": ethTransactionTool,
188
+ "eth-address-txs": ethAddressTxsTool,
189
+ "eth-address-balance": ethAddressBalanceTool,
190
+ "eth-token-transfers": ethTokenTransfersTool,
182
191
  },
183
192
  "tool.execute.before": async (input, output) => {
184
193
  const sessionID = input.sessionID;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Tool to get Ethereum address balance
3
+ */
4
+ import { type ToolContext } from "@opencode-ai/plugin";
5
+ export interface EthAddressBalanceArgs {
6
+ address: string;
7
+ chainId?: string;
8
+ }
9
+ export declare function getAddressBalance(address: string, chainId?: string): Promise<string>;
10
+ export declare const ethAddressBalanceTool: {
11
+ description: string;
12
+ args: {
13
+ address: import("zod").ZodString;
14
+ chainId: import("zod").ZodOptional<import("zod").ZodString>;
15
+ };
16
+ execute(args: {
17
+ address: string;
18
+ chainId?: string | undefined;
19
+ }, context: ToolContext): Promise<string>;
20
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Tool to get Ethereum address balance
3
+ */
4
+ import { tool } from "@opencode-ai/plugin";
5
+ import { EtherscanClient, EtherscanClientError, validateAddress } from "./etherscan-client";
6
+ import { formatBalance } from "./formatters";
7
+ import { CHAIN_ID_DESCRIPTION } from "./types";
8
+ export async function getAddressBalance(address, chainId) {
9
+ validateAddress(address);
10
+ const client = new EtherscanClient(undefined, chainId);
11
+ const balanceWei = await client.getBalance(address);
12
+ return formatBalance(address, balanceWei);
13
+ }
14
+ export const ethAddressBalanceTool = tool({
15
+ description: "Get the ETH balance of an Ethereum address. " +
16
+ "Returns balance in both ETH and Wei.",
17
+ args: {
18
+ address: tool.schema
19
+ .string()
20
+ .describe("Ethereum address (0x...)"),
21
+ chainId: tool.schema
22
+ .string()
23
+ .optional()
24
+ .describe(CHAIN_ID_DESCRIPTION),
25
+ },
26
+ async execute(args, _context) {
27
+ try {
28
+ return await getAddressBalance(args.address, args.chainId);
29
+ }
30
+ catch (error) {
31
+ if (error instanceof EtherscanClientError) {
32
+ return `Error: ${error.message}`;
33
+ }
34
+ throw error;
35
+ }
36
+ },
37
+ });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Tool to list Ethereum transactions for an address
3
+ */
4
+ import { type ToolContext } from "@opencode-ai/plugin";
5
+ export interface EthAddressTxsArgs {
6
+ address: string;
7
+ limit?: number;
8
+ chainId?: string;
9
+ }
10
+ export declare function getAddressTransactions(address: string, limit?: number, chainId?: string): Promise<string>;
11
+ export declare const ethAddressTxsTool: {
12
+ description: string;
13
+ args: {
14
+ address: import("zod").ZodString;
15
+ limit: import("zod").ZodOptional<import("zod").ZodNumber>;
16
+ chainId: import("zod").ZodOptional<import("zod").ZodString>;
17
+ };
18
+ execute(args: {
19
+ address: string;
20
+ limit?: number | undefined;
21
+ chainId?: string | undefined;
22
+ }, context: ToolContext): Promise<string>;
23
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Tool to list Ethereum transactions for an address
3
+ */
4
+ import { tool } from "@opencode-ai/plugin";
5
+ import { EtherscanClient, EtherscanClientError, validateAddress } from "./etherscan-client";
6
+ import { formatTransactionList } from "./formatters";
7
+ import { DEFAULT_TRANSACTION_LIMIT, CHAIN_ID_DESCRIPTION } from "./types";
8
+ export async function getAddressTransactions(address, limit = DEFAULT_TRANSACTION_LIMIT, chainId) {
9
+ validateAddress(address);
10
+ const client = new EtherscanClient(undefined, chainId);
11
+ const transactions = await client.getTransactions(address, limit);
12
+ return formatTransactionList(address, transactions);
13
+ }
14
+ export const ethAddressTxsTool = tool({
15
+ description: "List Ethereum transactions for an address. " +
16
+ "Shows incoming and outgoing transactions with values, timestamps, and status.",
17
+ args: {
18
+ address: tool.schema
19
+ .string()
20
+ .describe("Ethereum address (0x...)"),
21
+ limit: tool.schema
22
+ .number()
23
+ .optional()
24
+ .describe(`Maximum number of transactions to return (default: ${DEFAULT_TRANSACTION_LIMIT})`),
25
+ chainId: tool.schema
26
+ .string()
27
+ .optional()
28
+ .describe(CHAIN_ID_DESCRIPTION),
29
+ },
30
+ async execute(args, _context) {
31
+ try {
32
+ return await getAddressTransactions(args.address, args.limit, args.chainId);
33
+ }
34
+ catch (error) {
35
+ if (error instanceof EtherscanClientError) {
36
+ return `Error: ${error.message}`;
37
+ }
38
+ throw error;
39
+ }
40
+ },
41
+ });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Tool to list ERC-20 token transfers for an address
3
+ */
4
+ import { type ToolContext } from "@opencode-ai/plugin";
5
+ export interface EthTokenTransfersArgs {
6
+ address: string;
7
+ limit?: number;
8
+ chainId?: string;
9
+ }
10
+ export declare function getTokenTransfers(address: string, limit?: number, chainId?: string): Promise<string>;
11
+ export declare const ethTokenTransfersTool: {
12
+ description: string;
13
+ args: {
14
+ address: import("zod").ZodString;
15
+ limit: import("zod").ZodOptional<import("zod").ZodNumber>;
16
+ chainId: import("zod").ZodOptional<import("zod").ZodString>;
17
+ };
18
+ execute(args: {
19
+ address: string;
20
+ limit?: number | undefined;
21
+ chainId?: string | undefined;
22
+ }, context: ToolContext): Promise<string>;
23
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Tool to list ERC-20 token transfers for an address
3
+ */
4
+ import { tool } from "@opencode-ai/plugin";
5
+ import { EtherscanClient, EtherscanClientError, validateAddress } from "./etherscan-client";
6
+ import { formatTokenTransferList } from "./formatters";
7
+ import { DEFAULT_TRANSACTION_LIMIT, CHAIN_ID_DESCRIPTION } from "./types";
8
+ export async function getTokenTransfers(address, limit = DEFAULT_TRANSACTION_LIMIT, chainId) {
9
+ validateAddress(address);
10
+ const client = new EtherscanClient(undefined, chainId);
11
+ const transfers = await client.getTokenTransfers(address, limit);
12
+ return formatTokenTransferList(address, transfers);
13
+ }
14
+ export const ethTokenTransfersTool = tool({
15
+ description: "List ERC-20 token transfers for an Ethereum address. " +
16
+ "Shows token names, symbols, values, and transaction details.",
17
+ args: {
18
+ address: tool.schema
19
+ .string()
20
+ .describe("Ethereum address (0x...)"),
21
+ limit: tool.schema
22
+ .number()
23
+ .optional()
24
+ .describe(`Maximum number of transfers to return (default: ${DEFAULT_TRANSACTION_LIMIT})`),
25
+ chainId: tool.schema
26
+ .string()
27
+ .optional()
28
+ .describe(CHAIN_ID_DESCRIPTION),
29
+ },
30
+ async execute(args, _context) {
31
+ try {
32
+ return await getTokenTransfers(args.address, args.limit, args.chainId);
33
+ }
34
+ catch (error) {
35
+ if (error instanceof EtherscanClientError) {
36
+ return `Error: ${error.message}`;
37
+ }
38
+ throw error;
39
+ }
40
+ },
41
+ });
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Tool to get Ethereum transaction details by hash
3
+ */
4
+ import { type ToolContext } from "@opencode-ai/plugin";
5
+ import { type TransactionDetails } from "./types";
6
+ export interface EthTransactionArgs {
7
+ hash: string;
8
+ chainId?: string;
9
+ includeInternalTxs?: boolean;
10
+ includeTokenTransfers?: boolean;
11
+ decodeLogs?: boolean;
12
+ }
13
+ export declare function getTransactionDetails(hash: string, chainId?: string, options?: {
14
+ includeInternalTxs?: boolean;
15
+ includeTokenTransfers?: boolean;
16
+ decodeLogs?: boolean;
17
+ }): Promise<TransactionDetails>;
18
+ export declare const ethTransactionTool: {
19
+ description: string;
20
+ args: {
21
+ hash: import("zod").ZodString;
22
+ chainId: import("zod").ZodOptional<import("zod").ZodString>;
23
+ includeInternalTxs: import("zod").ZodOptional<import("zod").ZodBoolean>;
24
+ includeTokenTransfers: import("zod").ZodOptional<import("zod").ZodBoolean>;
25
+ decodeLogs: import("zod").ZodOptional<import("zod").ZodBoolean>;
26
+ };
27
+ execute(args: {
28
+ hash: string;
29
+ chainId?: string | undefined;
30
+ includeInternalTxs?: boolean | undefined;
31
+ includeTokenTransfers?: boolean | undefined;
32
+ decodeLogs?: boolean | undefined;
33
+ }, context: ToolContext): Promise<string>;
34
+ };