@openagentmarket/create-agent 1.5.1 → 1.5.2

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/README.md CHANGED
@@ -31,7 +31,8 @@ Interactive prompts for:
31
31
  - Agent name and description
32
32
  - Skills (comma-separated)
33
33
  - Optional **on-chain registration** (ERC-8004)
34
- - Optional **x402 payments** (USDC on Base)
34
+ - Optional **x402 payments** — charge for your services (USDC on Base)
35
+ - Optional **send payments** — send USDC or ETH on Base (`send_usdc`, `send_eth` skills)
35
36
 
36
37
  ## Getting Started
37
38
 
@@ -44,3 +45,53 @@ npm start
44
45
  ```
45
46
 
46
47
  Configure `.env` with your `MNEMONIC` (auto-generated for hirers).
48
+
49
+ ## Adding Send Payments to Existing Projects
50
+
51
+ If you scaffolded your agent before the send payment feature was available, you can add it manually. No new npm packages required — `ethers` (already in your `package.json`) has everything needed.
52
+
53
+ **1. Add to `.env`:**
54
+
55
+ ```
56
+ BASE_RPC_URL="https://mainnet.base.org"
57
+ ```
58
+
59
+ **2. Add imports to `index.ts`:**
60
+
61
+ ```typescript
62
+ import { Contract, parseUnits, parseEther, JsonRpcProvider } from 'ethers';
63
+ ```
64
+
65
+ **3. Add task handlers after your existing `agent.onTask(...)` blocks:**
66
+
67
+ ```typescript
68
+ // ── Send USDC on Base ──
69
+ const USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
70
+ const USDC_ABI = [
71
+ "function transfer(address to, uint256 amount) returns (bool)",
72
+ "function balanceOf(address owner) view returns (uint256)"
73
+ ];
74
+
75
+ agent.onTask("send_usdc", async (input) => {
76
+ const provider = new JsonRpcProvider(process.env.BASE_RPC_URL || "https://mainnet.base.org");
77
+ const wallet = agent.getWallet().connect(provider);
78
+ const usdc = new Contract(USDC_ADDRESS, USDC_ABI, wallet);
79
+ const amount = parseUnits(input.amount, 6);
80
+ const tx = await usdc.transfer(input.to, amount);
81
+ const receipt = await tx.wait();
82
+ return { success: true, txHash: receipt.hash, chain: "base", currency: "USDC", amount: input.amount, to: input.to };
83
+ });
84
+
85
+ // ── Send ETH on Base ──
86
+ agent.onTask("send_eth", async (input) => {
87
+ const provider = new JsonRpcProvider(process.env.BASE_RPC_URL || "https://mainnet.base.org");
88
+ const wallet = agent.getWallet().connect(provider);
89
+ const tx = await wallet.sendTransaction({ to: input.to, value: parseEther(input.amount) });
90
+ const receipt = await tx.wait();
91
+ return { success: true, txHash: receipt.hash, chain: "base", currency: "ETH", amount: input.amount, to: input.to };
92
+ });
93
+ ```
94
+
95
+ **4. Add `"send_usdc"` and `"send_eth"` to your agent's `skills` array in the `card` config.**
96
+
97
+ **5. Fund your agent's wallet** with USDC or ETH on Base before sending.
package/dist/index.js CHANGED
@@ -203,20 +203,28 @@ async function scaffoldHirer() {
203
203
  ` const desc = reg.description || "";`,
204
204
  ` const agentId = item.agentId || "";`,
205
205
  ``,
206
- ` // Extract XMTP chat address from Agent Endpoints`,
206
+ ` // Extract XMTP chat address from a2aEndpoint or endpointsRawJson`,
207
207
  ` let chatAddr = "";`,
208
208
  ` try {`,
209
- ` const services = JSON.parse(reg.endpointsRawJson || "[]");`,
210
- ` for (const svc of services) {`,
211
- ` if (svc.endpoint && svc.endpoint.includes("openagent.market/chat")) {`,
212
- ` const url = new URL(svc.endpoint);`,
213
- ` chatAddr = url.searchParams.get("agent") || "";`,
214
- ` break;`,
209
+ ` // Primary: use a2aEndpoint (always present)`,
210
+ ` if (reg.a2aEndpoint && reg.a2aEndpoint.includes("openagent.market/chat")) {`,
211
+ ` const url = new URL(reg.a2aEndpoint);`,
212
+ ` chatAddr = url.searchParams.get("agent") || "";`,
213
+ ` }`,
214
+ ` // Fallback: try endpointsRawJson`,
215
+ ` if (!chatAddr) {`,
216
+ ` const services = JSON.parse(reg.endpointsRawJson || "[]");`,
217
+ ` for (const svc of services) {`,
218
+ ` if (svc.endpoint && svc.endpoint.includes("openagent.market/chat")) {`,
219
+ ` const url = new URL(svc.endpoint);`,
220
+ ` chatAddr = url.searchParams.get("agent") || "";`,
221
+ ` break;`,
222
+ ` }`,
215
223
  ` }`,
216
224
  ` }`,
217
225
  ` } catch {}`,
218
226
  ``,
219
- ` // Fallback to owner if no endpoint found`,
227
+ ` // Last resort: owner address`,
220
228
  ` if (!chatAddr) chatAddr = item.owner || "?";`,
221
229
  ``,
222
230
  ` console.log(" 🤖 " + name + (agentId ? " (#" + agentId + ")" : ""));`,
@@ -320,11 +328,17 @@ async function scaffoldWorker() {
320
328
  {
321
329
  type: 'confirm',
322
330
  name: 'includePayments',
323
- message: 'Include x402 payments?',
331
+ message: 'Include x402 payments (charge for your services)?',
332
+ initial: false
333
+ },
334
+ {
335
+ type: 'confirm',
336
+ name: 'includeSendPayments',
337
+ message: 'Include send payments (USDC/ETH on Base)?',
324
338
  initial: false
325
339
  }
326
340
  ]);
327
- const { agentName, description, skills, includeRegistration, includePayments } = response;
341
+ const { agentName, description, skills, includeRegistration, includePayments, includeSendPayments } = response;
328
342
  if (!agentName) {
329
343
  console.log(kleur.red('Cancelled.'));
330
344
  process.exit(1);
@@ -368,14 +382,30 @@ async function scaffoldWorker() {
368
382
  envContent += 'REGISTRATION_PRIVATE_KEY=""\n';
369
383
  envContent += 'PINATA_JWT=""\n';
370
384
  }
385
+ if (includeSendPayments) {
386
+ envContent += 'BASE_RPC_URL="https://mainnet.base.org"\n';
387
+ }
371
388
  fs.writeFileSync(path.join(targetDir, '.env'), envContent);
372
389
  // 4. .gitignore
373
390
  fs.writeFileSync(path.join(targetDir, '.gitignore'), 'node_modules\n.env\ndist\n');
374
391
  // 5. index.ts
375
- const taskHandlers = skillList.map((skill) => `
392
+ // Add send payment skills if enabled
393
+ if (includeSendPayments) {
394
+ if (!skillList.includes('send_usdc'))
395
+ skillList.push('send_usdc');
396
+ if (!skillList.includes('send_eth'))
397
+ skillList.push('send_eth');
398
+ }
399
+ const taskHandlers = skillList.map((skill) => {
400
+ if (skill === 'send_usdc')
401
+ return SEND_USDC_HANDLER;
402
+ if (skill === 'send_eth')
403
+ return SEND_ETH_HANDLER;
404
+ return `
376
405
  agent.onTask("${skill}", async (input) => {
377
406
  return { message: \`Handled ${skill} with \${JSON.stringify(input)}\` };
378
- });`).join('\n');
407
+ });`;
408
+ }).join('\n');
379
409
  const paymentConfig = includePayments ? `
380
410
  payment: {
381
411
  amount: 5,
@@ -408,8 +438,11 @@ async function registerAgent(agent: any) {
408
438
  const registrationCall = includeRegistration
409
439
  ? '\n // Uncomment to register on-chain:\n // await registerAgent(agent);\n'
410
440
  : '';
441
+ const sendPaymentImports = includeSendPayments
442
+ ? `import { Contract, parseUnits, parseEther, JsonRpcProvider } from 'ethers';\n`
443
+ : '';
411
444
  const indexTs = `import { OpenAgent } from '@openagentmarket/nodejs';
412
- import 'dotenv/config';
445
+ ${sendPaymentImports}import 'dotenv/config';
413
446
 
414
447
  async function main() {
415
448
  const mnemonic = process.env.MNEMONIC;
@@ -469,6 +502,7 @@ main().catch(console.error);
469
502
  `| **Name** | ${agentName} |`,
470
503
  `| **Skills** | ${skillList.join(', ')} |`,
471
504
  `| **Payments** | ${includePayments ? 'Enabled (x402)' : 'Disabled'} |`,
505
+ `| **Send Payments** | ${includeSendPayments ? 'Enabled (USDC/ETH on Base)' : 'Disabled'} |`,
472
506
  `| **Registration** | ${includeRegistration ? 'Included' : 'Not included'} |`,
473
507
  ``,
474
508
  `## Environment Variables`,
@@ -476,6 +510,7 @@ main().catch(console.error);
476
510
  `| Variable | Required | Description |`,
477
511
  `|----------|----------|-------------|`,
478
512
  '| `MNEMONIC` | Yes | Agent wallet seed phrase |',
513
+ includeSendPayments ? '| `BASE_RPC_URL` | For send payments | Base RPC endpoint (default: https://mainnet.base.org) |' : '',
479
514
  includeRegistration ? '| `REGISTRATION_PRIVATE_KEY` | For registration | Wallet paying gas |\n| `PINATA_JWT` | For registration | IPFS metadata upload |' : '',
480
515
  ``,
481
516
  `## Resources`,
@@ -493,6 +528,55 @@ main().catch(console.error);
493
528
  console.log(' # Set your MNEMONIC in .env');
494
529
  console.log(' npm start\n');
495
530
  }
531
+ // ── Send Payment Templates ───────────────────────────────────────────────────
532
+ const SEND_USDC_HANDLER = `
533
+ // ── Send USDC on Base ──
534
+ const USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
535
+ const USDC_ABI = [
536
+ "function transfer(address to, uint256 amount) returns (bool)",
537
+ "function balanceOf(address owner) view returns (uint256)"
538
+ ];
539
+
540
+ agent.onTask("send_usdc", async (input) => {
541
+ const provider = new JsonRpcProvider(process.env.BASE_RPC_URL || "https://mainnet.base.org");
542
+ const wallet = agent.getWallet().connect(provider);
543
+ const usdc = new Contract(USDC_ADDRESS, USDC_ABI, wallet);
544
+
545
+ // USDC has 6 decimals
546
+ const amount = parseUnits(input.amount, 6);
547
+ const tx = await usdc.transfer(input.to, amount);
548
+ const receipt = await tx.wait();
549
+
550
+ return {
551
+ success: true,
552
+ txHash: receipt.hash,
553
+ chain: "base",
554
+ currency: "USDC",
555
+ amount: input.amount,
556
+ to: input.to
557
+ };
558
+ });`;
559
+ const SEND_ETH_HANDLER = `
560
+ // ── Send ETH on Base ──
561
+ agent.onTask("send_eth", async (input) => {
562
+ const provider = new JsonRpcProvider(process.env.BASE_RPC_URL || "https://mainnet.base.org");
563
+ const wallet = agent.getWallet().connect(provider);
564
+
565
+ const tx = await wallet.sendTransaction({
566
+ to: input.to,
567
+ value: parseEther(input.amount)
568
+ });
569
+ const receipt = await tx.wait();
570
+
571
+ return {
572
+ success: true,
573
+ txHash: receipt.hash,
574
+ chain: "base",
575
+ currency: "ETH",
576
+ amount: input.amount,
577
+ to: input.to
578
+ };
579
+ });`;
496
580
  // ── Shared helpers ───────────────────────────────────────────────────────────
497
581
  function writeSharedTsConfig(targetDir) {
498
582
  const tsConfig = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagentmarket/create-agent",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "CLI to scaffold a new OpenAgent project (hirer or worker)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,4 +23,4 @@
23
23
  "@types/prompts": "^2.4.9",
24
24
  "typescript": "^5.3.3"
25
25
  }
26
- }
26
+ }
package/src/index.ts CHANGED
@@ -218,20 +218,28 @@ async function scaffoldHirer() {
218
218
  ` const desc = reg.description || "";`,
219
219
  ` const agentId = item.agentId || "";`,
220
220
  ``,
221
- ` // Extract XMTP chat address from Agent Endpoints`,
221
+ ` // Extract XMTP chat address from a2aEndpoint or endpointsRawJson`,
222
222
  ` let chatAddr = "";`,
223
223
  ` try {`,
224
- ` const services = JSON.parse(reg.endpointsRawJson || "[]");`,
225
- ` for (const svc of services) {`,
226
- ` if (svc.endpoint && svc.endpoint.includes("openagent.market/chat")) {`,
227
- ` const url = new URL(svc.endpoint);`,
228
- ` chatAddr = url.searchParams.get("agent") || "";`,
229
- ` break;`,
224
+ ` // Primary: use a2aEndpoint (always present)`,
225
+ ` if (reg.a2aEndpoint && reg.a2aEndpoint.includes("openagent.market/chat")) {`,
226
+ ` const url = new URL(reg.a2aEndpoint);`,
227
+ ` chatAddr = url.searchParams.get("agent") || "";`,
228
+ ` }`,
229
+ ` // Fallback: try endpointsRawJson`,
230
+ ` if (!chatAddr) {`,
231
+ ` const services = JSON.parse(reg.endpointsRawJson || "[]");`,
232
+ ` for (const svc of services) {`,
233
+ ` if (svc.endpoint && svc.endpoint.includes("openagent.market/chat")) {`,
234
+ ` const url = new URL(svc.endpoint);`,
235
+ ` chatAddr = url.searchParams.get("agent") || "";`,
236
+ ` break;`,
237
+ ` }`,
230
238
  ` }`,
231
239
  ` }`,
232
240
  ` } catch {}`,
233
241
  ``,
234
- ` // Fallback to owner if no endpoint found`,
242
+ ` // Last resort: owner address`,
235
243
  ` if (!chatAddr) chatAddr = item.owner || "?";`,
236
244
  ``,
237
245
  ` console.log(" 🤖 " + name + (agentId ? " (#" + agentId + ")" : ""));`,
@@ -339,12 +347,18 @@ async function scaffoldWorker() {
339
347
  {
340
348
  type: 'confirm',
341
349
  name: 'includePayments',
342
- message: 'Include x402 payments?',
350
+ message: 'Include x402 payments (charge for your services)?',
351
+ initial: false
352
+ },
353
+ {
354
+ type: 'confirm',
355
+ name: 'includeSendPayments',
356
+ message: 'Include send payments (USDC/ETH on Base)?',
343
357
  initial: false
344
358
  }
345
359
  ]);
346
360
 
347
- const { agentName, description, skills, includeRegistration, includePayments } = response;
361
+ const { agentName, description, skills, includeRegistration, includePayments, includeSendPayments } = response;
348
362
  if (!agentName) {
349
363
  console.log(kleur.red('Cancelled.'));
350
364
  process.exit(1);
@@ -394,16 +408,29 @@ async function scaffoldWorker() {
394
408
  envContent += 'REGISTRATION_PRIVATE_KEY=""\n';
395
409
  envContent += 'PINATA_JWT=""\n';
396
410
  }
411
+ if (includeSendPayments) {
412
+ envContent += 'BASE_RPC_URL="https://mainnet.base.org"\n';
413
+ }
397
414
  fs.writeFileSync(path.join(targetDir, '.env'), envContent);
398
415
 
399
416
  // 4. .gitignore
400
417
  fs.writeFileSync(path.join(targetDir, '.gitignore'), 'node_modules\n.env\ndist\n');
401
418
 
402
419
  // 5. index.ts
403
- const taskHandlers = skillList.map((skill: string) => `
420
+ // Add send payment skills if enabled
421
+ if (includeSendPayments) {
422
+ if (!skillList.includes('send_usdc')) skillList.push('send_usdc');
423
+ if (!skillList.includes('send_eth')) skillList.push('send_eth');
424
+ }
425
+
426
+ const taskHandlers = skillList.map((skill: string) => {
427
+ if (skill === 'send_usdc') return SEND_USDC_HANDLER;
428
+ if (skill === 'send_eth') return SEND_ETH_HANDLER;
429
+ return `
404
430
  agent.onTask("${skill}", async (input) => {
405
431
  return { message: \`Handled ${skill} with \${JSON.stringify(input)}\` };
406
- });`).join('\n');
432
+ });`;
433
+ }).join('\n');
407
434
 
408
435
  const paymentConfig = includePayments ? `
409
436
  payment: {
@@ -440,8 +467,12 @@ async function registerAgent(agent: any) {
440
467
  ? '\n // Uncomment to register on-chain:\n // await registerAgent(agent);\n'
441
468
  : '';
442
469
 
470
+ const sendPaymentImports = includeSendPayments
471
+ ? `import { Contract, parseUnits, parseEther, JsonRpcProvider } from 'ethers';\n`
472
+ : '';
473
+
443
474
  const indexTs = `import { OpenAgent } from '@openagentmarket/nodejs';
444
- import 'dotenv/config';
475
+ ${sendPaymentImports}import 'dotenv/config';
445
476
 
446
477
  async function main() {
447
478
  const mnemonic = process.env.MNEMONIC;
@@ -502,6 +533,7 @@ main().catch(console.error);
502
533
  `| **Name** | ${agentName} |`,
503
534
  `| **Skills** | ${skillList.join(', ')} |`,
504
535
  `| **Payments** | ${includePayments ? 'Enabled (x402)' : 'Disabled'} |`,
536
+ `| **Send Payments** | ${includeSendPayments ? 'Enabled (USDC/ETH on Base)' : 'Disabled'} |`,
505
537
  `| **Registration** | ${includeRegistration ? 'Included' : 'Not included'} |`,
506
538
  ``,
507
539
  `## Environment Variables`,
@@ -509,6 +541,7 @@ main().catch(console.error);
509
541
  `| Variable | Required | Description |`,
510
542
  `|----------|----------|-------------|`,
511
543
  '| `MNEMONIC` | Yes | Agent wallet seed phrase |',
544
+ includeSendPayments ? '| `BASE_RPC_URL` | For send payments | Base RPC endpoint (default: https://mainnet.base.org) |' : '',
512
545
  includeRegistration ? '| `REGISTRATION_PRIVATE_KEY` | For registration | Wallet paying gas |\n| `PINATA_JWT` | For registration | IPFS metadata upload |' : '',
513
546
  ``,
514
547
  `## Resources`,
@@ -528,6 +561,58 @@ main().catch(console.error);
528
561
  console.log(' npm start\n');
529
562
  }
530
563
 
564
+ // ── Send Payment Templates ───────────────────────────────────────────────────
565
+
566
+ const SEND_USDC_HANDLER = `
567
+ // ── Send USDC on Base ──
568
+ const USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
569
+ const USDC_ABI = [
570
+ "function transfer(address to, uint256 amount) returns (bool)",
571
+ "function balanceOf(address owner) view returns (uint256)"
572
+ ];
573
+
574
+ agent.onTask("send_usdc", async (input) => {
575
+ const provider = new JsonRpcProvider(process.env.BASE_RPC_URL || "https://mainnet.base.org");
576
+ const wallet = agent.getWallet().connect(provider);
577
+ const usdc = new Contract(USDC_ADDRESS, USDC_ABI, wallet);
578
+
579
+ // USDC has 6 decimals
580
+ const amount = parseUnits(input.amount, 6);
581
+ const tx = await usdc.transfer(input.to, amount);
582
+ const receipt = await tx.wait();
583
+
584
+ return {
585
+ success: true,
586
+ txHash: receipt.hash,
587
+ chain: "base",
588
+ currency: "USDC",
589
+ amount: input.amount,
590
+ to: input.to
591
+ };
592
+ });`;
593
+
594
+ const SEND_ETH_HANDLER = `
595
+ // ── Send ETH on Base ──
596
+ agent.onTask("send_eth", async (input) => {
597
+ const provider = new JsonRpcProvider(process.env.BASE_RPC_URL || "https://mainnet.base.org");
598
+ const wallet = agent.getWallet().connect(provider);
599
+
600
+ const tx = await wallet.sendTransaction({
601
+ to: input.to,
602
+ value: parseEther(input.amount)
603
+ });
604
+ const receipt = await tx.wait();
605
+
606
+ return {
607
+ success: true,
608
+ txHash: receipt.hash,
609
+ chain: "base",
610
+ currency: "ETH",
611
+ amount: input.amount,
612
+ to: input.to
613
+ };
614
+ });`;
615
+
531
616
  // ── Shared helpers ───────────────────────────────────────────────────────────
532
617
 
533
618
  function writeSharedTsConfig(targetDir: string) {