create-message-kit 1.2.8 → 1.2.10
Sign up to get free protection for your applications and to get access to all the features.
- package/index.js +1 -1
- package/package.json +1 -1
- package/templates/agent/.cursorrules +3 -5
- package/templates/experimental/.cursorrules +3 -5
- package/templates/experimental/.env.example +5 -1
- package/templates/experimental/package.json +1 -0
- package/templates/experimental/src/index.ts +1 -2
- package/templates/experimental/src/lib/usdc.ts +99 -0
- package/templates/experimental/src/lib/xmtp.ts +4 -1
- package/templates/experimental/src/skills/cash.ts +114 -0
- package/templates/gpt/.cursorrules +3 -5
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.
|
10
|
+
const defVersion = "1.2.10";
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
12
12
|
|
13
13
|
// Read package.json to get the version
|
package/package.json
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
### Check if a Domain is Available
|
6
6
|
|
7
|
-
|
7
|
+
|
8
8
|
import { ensUrl } from "../index.js";
|
9
9
|
import { XMTPContext } from "@xmtp/message-kit";
|
10
10
|
import type { Skill } from "@xmtp/message-kit";
|
@@ -54,7 +54,7 @@ export async function handler(context: XMTPContext) {
|
|
54
54
|
|
55
55
|
### Generate a payment request
|
56
56
|
|
57
|
-
|
57
|
+
|
58
58
|
import { XMTPContext } from "@xmtp/message-kit";
|
59
59
|
import type { Skill } from "@xmtp/message-kit";
|
60
60
|
|
@@ -111,12 +111,10 @@ export async function handler(context: XMTPContext) {
|
|
111
111
|
|
112
112
|
await context.requestPayment(amount, token, receiverAddress);
|
113
113
|
}
|
114
|
-
```
|
115
114
|
|
116
115
|
|
117
116
|
## Types
|
118
117
|
|
119
|
-
```typescript
|
120
118
|
import { XMTPContext } from "../lib/xmtp.js";
|
121
119
|
import { ClientOptions, GroupMember } from "@xmtp/node-sdk";
|
122
120
|
import { ContentTypeId } from "@xmtp/content-type-primitives";
|
@@ -224,4 +222,4 @@ export interface AbstractedMember {
|
|
224
222
|
|
225
223
|
export type MetadataValue = string | number | boolean;
|
226
224
|
export type Metadata = Record<string, MetadataValue | MetadataValue[]>;
|
227
|
-
|
225
|
+
|
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
### Check if a Domain is Available
|
6
6
|
|
7
|
-
|
7
|
+
|
8
8
|
import { ensUrl } from "../index.js";
|
9
9
|
import { XMTPContext } from "@xmtp/message-kit";
|
10
10
|
import type { Skill } from "@xmtp/message-kit";
|
@@ -54,7 +54,7 @@ export async function handler(context: XMTPContext) {
|
|
54
54
|
|
55
55
|
### Generate a payment request
|
56
56
|
|
57
|
-
|
57
|
+
|
58
58
|
import { XMTPContext } from "@xmtp/message-kit";
|
59
59
|
import type { Skill } from "@xmtp/message-kit";
|
60
60
|
|
@@ -111,12 +111,10 @@ export async function handler(context: XMTPContext) {
|
|
111
111
|
|
112
112
|
await context.requestPayment(amount, token, receiverAddress);
|
113
113
|
}
|
114
|
-
```
|
115
114
|
|
116
115
|
|
117
116
|
## Types
|
118
117
|
|
119
|
-
```typescript
|
120
118
|
import { XMTPContext } from "../lib/xmtp.js";
|
121
119
|
import { ClientOptions, GroupMember } from "@xmtp/node-sdk";
|
122
120
|
import { ContentTypeId } from "@xmtp/content-type-primitives";
|
@@ -224,4 +222,4 @@ export interface AbstractedMember {
|
|
224
222
|
|
225
223
|
export type MetadataValue = string | number | boolean;
|
226
224
|
export type Metadata = Record<string, MetadataValue | MetadataValue[]>;
|
227
|
-
|
225
|
+
|
@@ -1,2 +1,6 @@
|
|
1
|
+
OPENAI_API_KEY= # the API key for OpenAI
|
2
|
+
TEST_ENCRYPTION_KEY= # the encryption key for the test wallet
|
1
3
|
KEY= # the private key of the wallet
|
2
|
-
|
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
|
@@ -5,7 +5,6 @@ import {
|
|
5
5
|
XMTPContext,
|
6
6
|
Agent,
|
7
7
|
xmtpClient,
|
8
|
-
V3Client,
|
9
8
|
} from "@xmtp/message-kit";
|
10
9
|
import fs from "fs";
|
11
10
|
import { systemPrompt } from "./prompt.js";
|
@@ -49,5 +48,5 @@ run(
|
|
49
48
|
fs.writeFileSync("example_prompt.md", prompt);
|
50
49
|
await agentReply(context, prompt);
|
51
50
|
},
|
52
|
-
{ agent },
|
51
|
+
{ agent, experimental: true },
|
53
52
|
);
|
@@ -0,0 +1,99 @@
|
|
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
|
+
}
|
@@ -92,6 +92,7 @@ export async function addToGroup(
|
|
92
92
|
groupId: string,
|
93
93
|
client: V3Client,
|
94
94
|
address: string,
|
95
|
+
asAdmin: boolean = false,
|
95
96
|
): Promise<{ code: number; message: string }> {
|
96
97
|
try {
|
97
98
|
let lowerAddress = address.toLowerCase();
|
@@ -104,10 +105,12 @@ export async function addToGroup(
|
|
104
105
|
const group = await client.conversations.getConversationById(groupId);
|
105
106
|
console.warn("Adding to group", group?.id);
|
106
107
|
await group?.sync();
|
107
|
-
//DON'T TOUCH THIS LINE
|
108
108
|
await group?.addMembers([lowerAddress]);
|
109
109
|
console.warn("Added member to group");
|
110
110
|
await group?.sync();
|
111
|
+
if (asAdmin) {
|
112
|
+
await group?.addSuperAdmin(lowerAddress);
|
113
|
+
}
|
111
114
|
const members = await group?.members();
|
112
115
|
console.warn("Number of members", members?.length);
|
113
116
|
|
@@ -0,0 +1,114 @@
|
|
1
|
+
import { XMTPContext } from "@xmtp/message-kit";
|
2
|
+
import type { Skill } from "@xmtp/message-kit";
|
3
|
+
import { USDCWallet } from "../lib/usdc.js";
|
4
|
+
|
5
|
+
export const cash: Skill[] = [
|
6
|
+
{
|
7
|
+
skill: "/balance",
|
8
|
+
handler: balanceHandler,
|
9
|
+
examples: ["/balance"],
|
10
|
+
params: {},
|
11
|
+
description: "Check your balance.",
|
12
|
+
},
|
13
|
+
{
|
14
|
+
skill: "/fund [amount]",
|
15
|
+
handler: fundHandler,
|
16
|
+
examples: ["/fund 1", "/fund 10"],
|
17
|
+
params: {
|
18
|
+
amount: {
|
19
|
+
type: "number",
|
20
|
+
default: "",
|
21
|
+
},
|
22
|
+
},
|
23
|
+
description: "Fund your wallet. Returns a url to fund your wallet.",
|
24
|
+
},
|
25
|
+
{
|
26
|
+
skill: "/transfer [address] [amount]",
|
27
|
+
handler: transferHandler,
|
28
|
+
examples: ["/transfer 0x40f08f0f853d1c42c61815652b7ccd5a50f0be09 1"],
|
29
|
+
params: {},
|
30
|
+
description: "Transfer USDC to another address.",
|
31
|
+
},
|
32
|
+
];
|
33
|
+
|
34
|
+
async function balanceHandler(context: XMTPContext) {
|
35
|
+
const {
|
36
|
+
message: { sender },
|
37
|
+
} = context;
|
38
|
+
const usdcWallet = new USDCWallet(sender.address);
|
39
|
+
const { usdc } = await usdcWallet.checkBalances();
|
40
|
+
await context.send(
|
41
|
+
`Your balance is ${usdc} USDC. let me know if you want check again or to fund your wallet.`,
|
42
|
+
);
|
43
|
+
}
|
44
|
+
|
45
|
+
async function fundHandler(context: XMTPContext) {
|
46
|
+
try {
|
47
|
+
const {
|
48
|
+
message: {
|
49
|
+
sender,
|
50
|
+
content: {
|
51
|
+
params: { amount },
|
52
|
+
},
|
53
|
+
},
|
54
|
+
} = context;
|
55
|
+
const usdcWallet = new USDCWallet(sender.address);
|
56
|
+
const { usdc } = await usdcWallet.checkBalances();
|
57
|
+
const MAX_USDC = 10;
|
58
|
+
|
59
|
+
if (usdc >= MAX_USDC) {
|
60
|
+
await context.send(`Your balance is maxed out at ${MAX_USDC} USDC.`);
|
61
|
+
return;
|
62
|
+
}
|
63
|
+
|
64
|
+
const remainingLimit = MAX_USDC - usdc;
|
65
|
+
let fundAmount: number;
|
66
|
+
|
67
|
+
if (!amount) {
|
68
|
+
const options = Array.from(
|
69
|
+
{ length: Math.floor(remainingLimit) },
|
70
|
+
(_, i) => (i + 1).toString(),
|
71
|
+
);
|
72
|
+
const response = await context.awaitResponse(
|
73
|
+
`Please specify the amount of USDC to prefund (1 to ${remainingLimit}):`,
|
74
|
+
options,
|
75
|
+
);
|
76
|
+
fundAmount = parseInt(response);
|
77
|
+
} else {
|
78
|
+
fundAmount = parseInt(amount);
|
79
|
+
}
|
80
|
+
|
81
|
+
if (isNaN(fundAmount) || fundAmount <= 0 || fundAmount > remainingLimit) {
|
82
|
+
await context.send(
|
83
|
+
`Invalid amount. Please specify a value between 1 and ${remainingLimit} USDC.`,
|
84
|
+
);
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
|
88
|
+
await context.requestPayment(fundAmount, "USDC", usdcWallet.agentAddress);
|
89
|
+
await context.send(
|
90
|
+
"After funding, let me know so I can check your balance.",
|
91
|
+
);
|
92
|
+
} catch (error) {
|
93
|
+
await context.send(
|
94
|
+
"An error occurred while processing your request. Please try again.",
|
95
|
+
);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
async function transferHandler(context: XMTPContext) {
|
100
|
+
const {
|
101
|
+
message: {
|
102
|
+
sender,
|
103
|
+
content: {
|
104
|
+
params: { address, amount },
|
105
|
+
},
|
106
|
+
},
|
107
|
+
} = context;
|
108
|
+
const usdcWallet = new USDCWallet(sender.address);
|
109
|
+
if (amount > 10) {
|
110
|
+
await context.send("You can only transfer up to 10 USDC at a time.");
|
111
|
+
return;
|
112
|
+
}
|
113
|
+
await usdcWallet.transferUsdc(address, amount);
|
114
|
+
}
|
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
### Check if a Domain is Available
|
6
6
|
|
7
|
-
|
7
|
+
|
8
8
|
import { ensUrl } from "../index.js";
|
9
9
|
import { XMTPContext } from "@xmtp/message-kit";
|
10
10
|
import type { Skill } from "@xmtp/message-kit";
|
@@ -54,7 +54,7 @@ export async function handler(context: XMTPContext) {
|
|
54
54
|
|
55
55
|
### Generate a payment request
|
56
56
|
|
57
|
-
|
57
|
+
|
58
58
|
import { XMTPContext } from "@xmtp/message-kit";
|
59
59
|
import type { Skill } from "@xmtp/message-kit";
|
60
60
|
|
@@ -111,12 +111,10 @@ export async function handler(context: XMTPContext) {
|
|
111
111
|
|
112
112
|
await context.requestPayment(amount, token, receiverAddress);
|
113
113
|
}
|
114
|
-
```
|
115
114
|
|
116
115
|
|
117
116
|
## Types
|
118
117
|
|
119
|
-
```typescript
|
120
118
|
import { XMTPContext } from "../lib/xmtp.js";
|
121
119
|
import { ClientOptions, GroupMember } from "@xmtp/node-sdk";
|
122
120
|
import { ContentTypeId } from "@xmtp/content-type-primitives";
|
@@ -224,4 +222,4 @@ export interface AbstractedMember {
|
|
224
222
|
|
225
223
|
export type MetadataValue = string | number | boolean;
|
226
224
|
export type Metadata = Record<string, MetadataValue | MetadataValue[]>;
|
227
|
-
|
225
|
+
|