create-message-kit 1.2.11 → 1.2.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. package/index.js +9 -4
  2. package/package.json +1 -1
  3. package/templates/{agent → ens}/.cursorrules +68 -3
  4. package/templates/{agent → ens}/package.json +1 -1
  5. package/templates/{agent → ens}/src/prompt.ts +1 -1
  6. package/templates/{agent → ens}/src/skills/check.ts +1 -1
  7. package/templates/{agent → ens}/src/skills/cool.ts +1 -1
  8. package/templates/{agent → ens}/src/skills/info.ts +1 -1
  9. package/templates/{agent → ens}/src/skills/pay.ts +1 -1
  10. package/templates/{agent → ens}/src/skills/register.ts +1 -1
  11. package/templates/{agent → ens}/src/skills/renew.ts +1 -1
  12. package/templates/{agent → ens}/src/skills/reset.ts +1 -2
  13. package/templates/{experimental → simple}/.cursorrules +68 -3
  14. package/templates/{gpt → simple}/package.json +1 -1
  15. package/templates/experimental/.env.example +0 -6
  16. package/templates/experimental/package.json +0 -26
  17. package/templates/experimental/src/index.ts +0 -52
  18. package/templates/experimental/src/lib/alchemy.ts +0 -31
  19. package/templates/experimental/src/lib/minilog.ts +0 -26
  20. package/templates/experimental/src/lib/usdc.ts +0 -99
  21. package/templates/experimental/src/lib/xmtp.ts +0 -139
  22. package/templates/experimental/src/prompt.ts +0 -24
  23. package/templates/experimental/src/skills/broadcast.ts +0 -39
  24. package/templates/experimental/src/skills/cash.ts +0 -114
  25. package/templates/experimental/src/skills/gated.ts +0 -89
  26. package/templates/experimental/src/skills/todo.ts +0 -80
  27. package/templates/experimental/src/skills/token.ts +0 -57
  28. package/templates/experimental/src/skills/wordle.ts +0 -97
  29. package/templates/gpt/.cursorrules +0 -225
  30. package/templates/gpt/.yarnrc.yml +0 -4
  31. /package/templates/{agent → ens}/.env.example +0 -0
  32. /package/templates/{agent → ens}/.yarnrc.yml +0 -0
  33. /package/templates/{agent → ens}/src/index.ts +0 -0
  34. /package/templates/{gpt → simple}/.env.example +0 -0
  35. /package/templates/{experimental → simple}/.yarnrc.yml +0 -0
  36. /package/templates/{gpt → simple}/src/index.ts +0 -0
  37. /package/templates/{gpt → simple}/src/prompt.ts +0 -0
package/index.js CHANGED
@@ -7,7 +7,7 @@ import { default as fs } from "fs-extra";
7
7
  import { isCancel } from "@clack/prompts";
8
8
  import { detect } from "detect-package-manager";
9
9
  import pc from "picocolors";
10
- const defVersion = "1.2.11";
10
+ const defVersion = "1.2.13";
11
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
12
12
 
13
13
  // Read package.json to get the version
@@ -96,9 +96,14 @@ async function updatePackagejson(destDir, templateType) {
96
96
 
97
97
  async function gatherProjectInfo() {
98
98
  const templateOptions = [
99
- { value: "gpt", label: "Simple Gpt" },
100
- { value: "agent", label: "ENS Agent" },
101
- { value: "experimental", label: "Experimental" },
99
+ {
100
+ value: "simple",
101
+ label: "Simple Agent: A starter template for building an agent",
102
+ },
103
+ {
104
+ value: "ens",
105
+ label: "ENS Agent: An example of an agent using ENS skills",
106
+ },
102
107
  ];
103
108
 
104
109
  const templateType = await select({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-message-kit",
3
- "version": "1.2.11",
3
+ "version": "1.2.13",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -12,7 +12,7 @@ import type { Skill } from "@xmtp/message-kit";
12
12
  // Define Skill
13
13
  export const checkDomain: Skill[] = [
14
14
  {
15
- skill: "/check [domain]",
15
+ skill: "check",
16
16
  handler: handler,
17
17
  examples: ["/check vitalik.eth", "/check fabri.base.eth"],
18
18
  description: "Check if a domain is available.",
@@ -61,7 +61,7 @@ import type { Skill } from "@xmtp/message-kit";
61
61
  // Define Skill
62
62
  export const paymentRequest: Skill[] = [
63
63
  {
64
- skill: "/pay [amount] [token] [username] [address]",
64
+ skill: "pay",
65
65
  examples: [
66
66
  "/pay 10 vitalik.eth",
67
67
  "/pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03",
@@ -115,7 +115,7 @@ export async function handler(context: XMTPContext) {
115
115
 
116
116
  ## Types
117
117
 
118
- import { XMTPContext } from "../lib/xmtp.js";
118
+ import { XMTPContext } from "../plugins/xmtp.js";
119
119
  import { ClientOptions, GroupMember } from "@xmtp/node-sdk";
120
120
  import { ContentTypeId } from "@xmtp/content-type-primitives";
121
121
 
@@ -223,3 +223,68 @@ export interface AbstractedMember {
223
223
  export type MetadataValue = string | number | boolean;
224
224
  export type Metadata = Record<string, MetadataValue | MetadataValue[]>;
225
225
 
226
+
227
+ ## Example final prompt
228
+
229
+ Your are a helpful and playful ens agent called @bot that lives inside a messaging app called Converse.
230
+
231
+
232
+ # Rules
233
+ - You can respond with multiple messages if needed. Each message should be separated by a newline character.
234
+ - You can trigger skills by only sending the command in a newline message.
235
+ - Each command starts with a slash (/).
236
+ - Never announce actions without using a command separated by a newline character.
237
+ - Never use markdown in your responses.
238
+ - Do not make guesses or assumptions
239
+ - Only answer if the verified information is in the prompt.
240
+ - Check that you are not missing a command
241
+ - Focus only on helping users with operations detailed below.
242
+ - Date: Fri, 06 Dec 2024 16:03:22 GMT
243
+ - When mentioning any action related to available skills, you MUST trigger the corresponding command in a new line
244
+ - If you suggest an action that has a command, you must trigger that command
245
+
246
+
247
+ ## User context
248
+ - Start by fetch their domain from or Converse username
249
+ - Call the user by their name or domain, in case they have one
250
+ - Ask for a name (if they don't have one) so you can suggest domains.
251
+ - Message sent date: 2024-12-06T16:03:36.582Z
252
+ - Users address is: 0x40f08f0f853d1c42c61815652b7ccd5a50f0be09
253
+ - Users name is: ArizonaOregon
254
+ - Converse username is: ArizonaOregon
255
+
256
+ ## Commands
257
+ /check [domain] - Check if a domain is available.
258
+ /cool [domain] - Get cool alternatives for a .eth domain.
259
+ /info [domain] - Get detailed information about an ENS domain including owner, expiry date, and resolver.
260
+ /register [domain] - Register a new ENS domain. Returns a URL to complete the registration process.
261
+ /renew [domain] - Extend the registration period of your ENS domain. Returns a URL to complete the renewal.
262
+ /reset - Reset the conversation clearing memory and usernames cache.
263
+ /pay [amount] [token] [username] [address] - Send a specified amount of a cryptocurrency to a destination address.
264
+ When tipping, you can asume its 1 usdc.
265
+
266
+ ## Examples
267
+ /check vitalik.eth
268
+ /check fabri.base.eth
269
+ /cool vitalik.eth
270
+ /info nick.eth
271
+ /register vitalik.eth
272
+ /renew fabri.base.eth
273
+ /reset
274
+ /pay 10 vitalik.eth
275
+ /pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03
276
+
277
+ ## Scenarios
278
+ 1. Missing commands in responses
279
+ **Issue**: Sometimes responses are sent without the required command.
280
+ **Example**:
281
+ Incorrect:
282
+ > "Looks like vitalik.eth is registered! What about these cool alternatives?"
283
+ Correct:
284
+ > "Looks like vitalik.eth is registered! What about these cool alternatives?
285
+ > /cool vitalik.eth"
286
+
287
+ Incorrect:
288
+ > Here is a summary of your TODOs. I will now send it via email.
289
+ Correct:
290
+ > /todo
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "agent",
2
+ "name": "ens-agent",
3
3
  "private": true,
4
4
  "type": "module",
5
5
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  export const systemPrompt = `
2
- Your are helpful and playful ens agent called {agent_name} that lives inside a messaging app called Converse.
2
+ Your are a helpful and playful ens agent called {agent_name} that lives inside a messaging app called Converse.
3
3
 
4
4
  {rules}
5
5
 
@@ -6,7 +6,7 @@ const ensUrl = "https://app.ens.domains/";
6
6
  // [!region define]
7
7
  export const checkDomain: Skill[] = [
8
8
  {
9
- skill: "/check [domain]",
9
+ skill: "check",
10
10
  handler: handler,
11
11
  examples: ["/check vitalik.eth", "/check fabri.base.eth"],
12
12
  description: "Check if a domain is available.",
@@ -4,7 +4,7 @@ import type { Skill } from "@xmtp/message-kit";
4
4
 
5
5
  export const cool: Skill[] = [
6
6
  {
7
- skill: "/cool [domain]",
7
+ skill: "cool",
8
8
  examples: ["/cool vitalik.eth"],
9
9
  handler: handler,
10
10
  description: "Get cool alternatives for a .eth domain.",
@@ -4,7 +4,7 @@ import type { Skill } from "@xmtp/message-kit";
4
4
 
5
5
  export const info: Skill[] = [
6
6
  {
7
- skill: "/info [domain]",
7
+ skill: "info",
8
8
  handler: handler,
9
9
  description:
10
10
  "Get detailed information about an ENS domain including owner, expiry date, and resolver.",
@@ -3,7 +3,7 @@ import type { Skill } from "@xmtp/message-kit";
3
3
 
4
4
  export const pay: Skill[] = [
5
5
  {
6
- skill: "/pay [amount] [token] [username] [address]",
6
+ skill: "pay",
7
7
  examples: [
8
8
  "/pay 10 vitalik.eth",
9
9
  "/pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03",
@@ -5,7 +5,7 @@ import type { Skill } from "@xmtp/message-kit";
5
5
 
6
6
  export const register: Skill[] = [
7
7
  {
8
- skill: "/register [domain]",
8
+ skill: "register",
9
9
  handler: handler,
10
10
  description:
11
11
  "Register a new ENS domain. Returns a URL to complete the registration process.",
@@ -6,7 +6,7 @@ const frameUrl = "https://ens.steer.fun/";
6
6
 
7
7
  export const renew: Skill[] = [
8
8
  {
9
- skill: "/renew [domain]",
9
+ skill: "renew",
10
10
  handler: handler,
11
11
  description:
12
12
  "Extend the registration period of your ENS domain. Returns a URL to complete the renewal.",
@@ -5,11 +5,10 @@ import type { Skill } from "@xmtp/message-kit";
5
5
 
6
6
  export const reset: Skill[] = [
7
7
  {
8
- skill: "/reset",
8
+ skill: "reset",
9
9
  examples: ["/reset"],
10
10
  handler: handler,
11
11
  description: "Reset the conversation clearing memory and usernames cache.",
12
- params: {},
13
12
  },
14
13
  ];
15
14
  export async function handler(context: XMTPContext) {
@@ -12,7 +12,7 @@ import type { Skill } from "@xmtp/message-kit";
12
12
  // Define Skill
13
13
  export const checkDomain: Skill[] = [
14
14
  {
15
- skill: "/check [domain]",
15
+ skill: "check",
16
16
  handler: handler,
17
17
  examples: ["/check vitalik.eth", "/check fabri.base.eth"],
18
18
  description: "Check if a domain is available.",
@@ -61,7 +61,7 @@ import type { Skill } from "@xmtp/message-kit";
61
61
  // Define Skill
62
62
  export const paymentRequest: Skill[] = [
63
63
  {
64
- skill: "/pay [amount] [token] [username] [address]",
64
+ skill: "pay",
65
65
  examples: [
66
66
  "/pay 10 vitalik.eth",
67
67
  "/pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03",
@@ -115,7 +115,7 @@ export async function handler(context: XMTPContext) {
115
115
 
116
116
  ## Types
117
117
 
118
- import { XMTPContext } from "../lib/xmtp.js";
118
+ import { XMTPContext } from "../plugins/xmtp.js";
119
119
  import { ClientOptions, GroupMember } from "@xmtp/node-sdk";
120
120
  import { ContentTypeId } from "@xmtp/content-type-primitives";
121
121
 
@@ -223,3 +223,68 @@ export interface AbstractedMember {
223
223
  export type MetadataValue = string | number | boolean;
224
224
  export type Metadata = Record<string, MetadataValue | MetadataValue[]>;
225
225
 
226
+
227
+ ## Example final prompt
228
+
229
+ Your are a helpful and playful ens agent called @bot that lives inside a messaging app called Converse.
230
+
231
+
232
+ # Rules
233
+ - You can respond with multiple messages if needed. Each message should be separated by a newline character.
234
+ - You can trigger skills by only sending the command in a newline message.
235
+ - Each command starts with a slash (/).
236
+ - Never announce actions without using a command separated by a newline character.
237
+ - Never use markdown in your responses.
238
+ - Do not make guesses or assumptions
239
+ - Only answer if the verified information is in the prompt.
240
+ - Check that you are not missing a command
241
+ - Focus only on helping users with operations detailed below.
242
+ - Date: Fri, 06 Dec 2024 16:03:22 GMT
243
+ - When mentioning any action related to available skills, you MUST trigger the corresponding command in a new line
244
+ - If you suggest an action that has a command, you must trigger that command
245
+
246
+
247
+ ## User context
248
+ - Start by fetch their domain from or Converse username
249
+ - Call the user by their name or domain, in case they have one
250
+ - Ask for a name (if they don't have one) so you can suggest domains.
251
+ - Message sent date: 2024-12-06T16:03:36.582Z
252
+ - Users address is: 0x40f08f0f853d1c42c61815652b7ccd5a50f0be09
253
+ - Users name is: ArizonaOregon
254
+ - Converse username is: ArizonaOregon
255
+
256
+ ## Commands
257
+ /check [domain] - Check if a domain is available.
258
+ /cool [domain] - Get cool alternatives for a .eth domain.
259
+ /info [domain] - Get detailed information about an ENS domain including owner, expiry date, and resolver.
260
+ /register [domain] - Register a new ENS domain. Returns a URL to complete the registration process.
261
+ /renew [domain] - Extend the registration period of your ENS domain. Returns a URL to complete the renewal.
262
+ /reset - Reset the conversation clearing memory and usernames cache.
263
+ /pay [amount] [token] [username] [address] - Send a specified amount of a cryptocurrency to a destination address.
264
+ When tipping, you can asume its 1 usdc.
265
+
266
+ ## Examples
267
+ /check vitalik.eth
268
+ /check fabri.base.eth
269
+ /cool vitalik.eth
270
+ /info nick.eth
271
+ /register vitalik.eth
272
+ /renew fabri.base.eth
273
+ /reset
274
+ /pay 10 vitalik.eth
275
+ /pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03
276
+
277
+ ## Scenarios
278
+ 1. Missing commands in responses
279
+ **Issue**: Sometimes responses are sent without the required command.
280
+ **Example**:
281
+ Incorrect:
282
+ > "Looks like vitalik.eth is registered! What about these cool alternatives?"
283
+ Correct:
284
+ > "Looks like vitalik.eth is registered! What about these cool alternatives?
285
+ > /cool vitalik.eth"
286
+
287
+ Incorrect:
288
+ > Here is a summary of your TODOs. I will now send it via email.
289
+ Correct:
290
+ > /todo
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "gpt",
2
+ "name": "simple-agent",
3
3
  "private": true,
4
4
  "type": "module",
5
5
  "scripts": {
@@ -1,6 +0,0 @@
1
- OPENAI_API_KEY= # the API key for OpenAI
2
- TEST_ENCRYPTION_KEY= # the encryption key for the test wallet
3
- KEY= # the private key of the wallet
4
- RESEND_API_KEY= # the API key for Resend
5
- FRAMEDL_API_KEY= # the API key for Framedl
6
- ALCHEMY_SDK= # the API key for Alchemy
@@ -1,26 +0,0 @@
1
- {
2
- "name": "experimental",
3
- "private": true,
4
- "type": "module",
5
- "scripts": {
6
- "build": "tsc",
7
- "dev": "tsc -w & sleep 1 && NODE_NO_WARNINGS=1 node --watch dist/index.js",
8
- "start": "node dist/index.js"
9
- },
10
- "dependencies": {
11
- "@xmtp/message-kit": "workspace:*",
12
- "alchemy-sdk": "^3.0.0",
13
- "ethers": "^6.0.0",
14
- "express": "^4.19.2",
15
- "node-fetch": "^3.3.2",
16
- "resend": "^4.0.1"
17
- },
18
- "devDependencies": {
19
- "@types/express": "^4.17.20",
20
- "@types/node": "^20.14.2",
21
- "typescript": "^5.4.5"
22
- },
23
- "engines": {
24
- "node": ">=20"
25
- }
26
- }
@@ -1,52 +0,0 @@
1
- import {
2
- run,
3
- agentReply,
4
- replaceVariables,
5
- XMTPContext,
6
- Agent,
7
- xmtpClient,
8
- } from "@xmtp/message-kit";
9
- import fs from "fs";
10
- import { systemPrompt } from "./prompt.js";
11
- import { token } from "./skills/token.js";
12
- import { todo } from "./skills/todo.js";
13
- import { gated, startGatedGroupServer } from "./skills/gated.js";
14
- import { broadcast } from "./skills/broadcast.js";
15
- import { wordle } from "./skills/wordle.js";
16
-
17
- export const agent: Agent = {
18
- name: "Experimental Agent",
19
- tag: "@bot",
20
- description: "An experimental agent with a lot of skills.",
21
- skills: [
22
- ...token,
23
- ...(process?.env?.RESEND_API_KEY ? todo : []),
24
- ...(process?.env?.ALCHEMY_SDK ? gated : []),
25
- ...broadcast,
26
- ...wordle,
27
- ],
28
- };
29
-
30
- // [!region gated]
31
- const { client } = await xmtpClient({
32
- hideInitLogMessage: true,
33
- });
34
-
35
- startGatedGroupServer(client);
36
- // [!endregion gated]
37
-
38
- run(
39
- async (context: XMTPContext) => {
40
- const {
41
- message: { sender },
42
- agent,
43
- } = context;
44
-
45
- let prompt = await replaceVariables(systemPrompt, sender.address, agent);
46
-
47
- //This is only used for to update the docs.
48
- fs.writeFileSync("example_prompt.md", prompt);
49
- await agentReply(context, prompt);
50
- },
51
- { agent, experimental: true },
52
- );
@@ -1,31 +0,0 @@
1
- import { Alchemy, Network } from "alchemy-sdk";
2
-
3
- const settings = {
4
- apiKey: process.env.ALCHEMY_API_KEY, // Replace with your Alchemy API key
5
- network: Network.BASE_MAINNET, // Use the appropriate network
6
- };
7
-
8
- export async function checkNft(
9
- walletAddress: string,
10
- collectionSlug: string,
11
- ): Promise<boolean> {
12
- const alchemy = new Alchemy(settings);
13
- try {
14
- const nfts = await alchemy.nft.getNftsForOwner(walletAddress);
15
-
16
- const ownsNft = nfts.ownedNfts.some(
17
- (nft: any) =>
18
- nft.contract.name.toLowerCase() === collectionSlug.toLowerCase(),
19
- );
20
- // console.log(
21
- // `NFTs owned on ${Network.BASE_MAINNET}:`,
22
- // nfts.ownedNfts.length,
23
- // );
24
- console.log("is the nft owned: ", ownsNft);
25
- return ownsNft as boolean;
26
- } catch (error) {
27
- console.error("Error fetching NFTs from Alchemy:", error);
28
- }
29
-
30
- return false;
31
- }
@@ -1,26 +0,0 @@
1
- import fetch from "node-fetch";
2
-
3
- export async function sendLog(title: string, description: string) {
4
- const response = await fetch("https://api.minilog.dev/v1/logs/testlog", {
5
- method: "POST",
6
- headers: {
7
- "Content-Type": "application/json",
8
- Authorization: "Bearer pthsm38sccpux5acriqish7isz5inet7q73ef7br",
9
- },
10
- body: JSON.stringify({
11
- application: "myapp-1",
12
- severity: "DEBUG",
13
- data: title,
14
- metadata: {
15
- title,
16
- description,
17
- },
18
- }),
19
- });
20
- console.log(response);
21
- if (!response.ok) {
22
- console.error("Failed to send log:", response.statusText);
23
- } else {
24
- console.log("Log sent successfully");
25
- }
26
- }
@@ -1,99 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { generatePrivateKey } from "viem/accounts";
4
- import { ethers } from "ethers";
5
-
6
- // Define the Base network RPC URL
7
- const baseRpcUrl = "https://mainnet.base.org";
8
-
9
- // Create a provider
10
- const provider = new ethers.JsonRpcProvider(baseRpcUrl);
11
-
12
- // USDC contract address on Base (replace with actual address)
13
- const usdcAddress = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"; // Replace with the correct USDC contract address
14
-
15
- // ERC-20 ABI (balanceOf and transfer functions)
16
- const erc20Abi = [
17
- "function balanceOf(address owner) view returns (uint256)",
18
- "function transfer(address to, uint256 amount) returns (bool)",
19
- ];
20
-
21
- export class USDCWallet {
22
- walletDir: string;
23
- senderAddress: string;
24
- privateKey: string;
25
- agentAddress: string;
26
- usdcContract: ethers.Contract;
27
- wallet: ethers.Wallet;
28
-
29
- constructor(senderAddress: string) {
30
- this.senderAddress = senderAddress;
31
- this.walletDir = path.join(process.cwd(), `./.data/usdcwallets`);
32
- if (!fs.existsSync(this.walletDir)) {
33
- fs.mkdirSync(this.walletDir, { recursive: true });
34
- console.warn("USDC wallet created and saved successfully.");
35
- }
36
-
37
- const walletFilePath = path.join(this.walletDir, `${senderAddress}.usdc`);
38
-
39
- if (fs.existsSync(walletFilePath)) {
40
- const walletData = fs.readFileSync(walletFilePath, "utf8");
41
- this.privateKey = walletData.match(/KEY=(.+)/)?.[1]?.trim() ?? "";
42
- } else {
43
- this.privateKey = generatePrivateKey();
44
- let usdcWallet = new ethers.Wallet(this.privateKey, provider);
45
- const walletData = `KEY=${this.privateKey}\nADDRESS=${usdcWallet.address}`;
46
- fs.writeFileSync(walletFilePath, walletData);
47
- }
48
-
49
- // Initialize wallet and USDC contract
50
- this.wallet = new ethers.Wallet(this.privateKey, provider);
51
- this.agentAddress = this.wallet.address;
52
- this.usdcContract = new ethers.Contract(usdcAddress, erc20Abi, this.wallet);
53
- }
54
-
55
- async checkBalances(): Promise<{ usdc: number; eth: number }> {
56
- try {
57
- // Check USDC balance
58
- console.log(this.agentAddress);
59
- const usdcBalance = await this.usdcContract.balanceOf(this.agentAddress);
60
- const formattedUsdcBalance = ethers.formatUnits(usdcBalance, 6); // USDC has 6 decimals
61
- console.warn(`USDC Balance: ${formattedUsdcBalance}`);
62
-
63
- // Check ETH balance
64
- const ethBalance = await provider.getBalance(this.agentAddress);
65
- const formattedEthBalance = ethers.formatUnits(ethBalance, 18);
66
- console.warn(`ETH Balance: ${formattedEthBalance}`);
67
-
68
- return {
69
- usdc: parseFloat(formattedUsdcBalance),
70
- eth: parseFloat(formattedEthBalance),
71
- };
72
- } catch (error) {
73
- console.error("Error fetching balances:", error);
74
- return { usdc: 0, eth: 0 };
75
- }
76
- }
77
- async transferUsdc(to: string, amount: number) {
78
- if (!ethers.isAddress(to)) {
79
- throw new Error("Invalid recipient address");
80
- } else if (typeof amount !== "number" || amount <= 0) {
81
- throw new Error("Invalid transfer amount");
82
- }
83
- try {
84
- const amountInWei = ethers.parseUnits(amount.toString(), 6); // USDC has 6 decimals
85
- const adminAgent = new USDCWallet(to);
86
- const tx = await this.usdcContract.transfer(
87
- adminAgent.agentAddress,
88
- amountInWei,
89
- );
90
- const receipt = await tx.wait();
91
- if (receipt.status !== 1) {
92
- throw new Error("Transaction failed or was reverted");
93
- }
94
- } catch (error) {
95
- console.warn(`Transferred ${amount} USDC to ${to}.`);
96
- throw error;
97
- }
98
- }
99
- }