create-message-kit 1.2.7 → 1.2.9
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/index.js +1 -1
- package/package.json +2 -3
- package/templates/agent/.cursorrules +3 -5
- package/templates/agent/src/index.ts +0 -2
- package/templates/experimental/.cursorrules +3 -5
- package/templates/experimental/.env.example +5 -1
- package/templates/experimental/package.json +2 -0
- package/templates/experimental/src/index.ts +16 -5
- package/templates/experimental/src/lib/alchemy.ts +4 -4
- package/templates/experimental/src/lib/minilog.ts +26 -0
- package/templates/experimental/src/lib/usdc.ts +99 -0
- package/templates/experimental/src/lib/xmtp.ts +14 -13
- package/templates/experimental/src/skills/broadcast.ts +3 -2
- package/templates/experimental/src/skills/cash.ts +114 -0
- package/templates/experimental/src/skills/gated.ts +14 -25
- package/templates/experimental/src/skills/todo.ts +2 -2
- package/templates/experimental/src/skills/wordle.ts +97 -0
- package/templates/gpt/.cursorrules +3 -5
- package/templates/agent/src/skills/game.ts +0 -58
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.9";
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
12
12
|
|
13
13
|
// Read package.json to get the version
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "create-message-kit",
|
3
|
-
"version": "1.2.
|
3
|
+
"version": "1.2.9",
|
4
4
|
"license": "MIT",
|
5
5
|
"type": "module",
|
6
6
|
"main": "index.js",
|
@@ -12,7 +12,6 @@
|
|
12
12
|
],
|
13
13
|
"scripts": {
|
14
14
|
"clean": "rm -rf .turbo && rm -rf node_modules",
|
15
|
-
"copy": "node copyTemplates.js",
|
16
15
|
"format": "yarn format:base -w .",
|
17
16
|
"format:base": "prettier --ignore-path ../../.gitignore",
|
18
17
|
"format:check": "yarn format:base -c ."
|
@@ -38,4 +37,4 @@
|
|
38
37
|
"access": "public",
|
39
38
|
"registry": "https://registry.npmjs.org/"
|
40
39
|
}
|
41
|
-
}
|
40
|
+
}
|
@@ -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
|
+
|
@@ -13,7 +13,6 @@ import { register } from "./skills/register.js";
|
|
13
13
|
import { renew } from "./skills/renew.js";
|
14
14
|
import { pay } from "./skills/pay.js";
|
15
15
|
import { reset } from "./skills/reset.js";
|
16
|
-
import { game } from "./skills/game.js";
|
17
16
|
import fs from "fs";
|
18
17
|
|
19
18
|
// [!region skills]
|
@@ -29,7 +28,6 @@ export const agent: Agent = {
|
|
29
28
|
...renew,
|
30
29
|
...reset,
|
31
30
|
...pay,
|
32
|
-
...game,
|
33
31
|
],
|
34
32
|
};
|
35
33
|
// [!endregion skills]
|
@@ -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
|
@@ -4,26 +4,37 @@ import {
|
|
4
4
|
replaceVariables,
|
5
5
|
XMTPContext,
|
6
6
|
Agent,
|
7
|
+
xmtpClient,
|
7
8
|
} from "@xmtp/message-kit";
|
8
|
-
import { systemPrompt } from "./prompt.js";
|
9
9
|
import fs from "fs";
|
10
|
-
|
10
|
+
import { systemPrompt } from "./prompt.js";
|
11
11
|
import { token } from "./skills/token.js";
|
12
12
|
import { todo } from "./skills/todo.js";
|
13
|
-
import { gated } from "./skills/gated.js";
|
13
|
+
import { gated, startGatedGroupServer } from "./skills/gated.js";
|
14
14
|
import { broadcast } from "./skills/broadcast.js";
|
15
|
+
import { wordle } from "./skills/wordle.js";
|
15
16
|
|
16
17
|
export const agent: Agent = {
|
17
18
|
name: "Experimental Agent",
|
18
|
-
tag: "@
|
19
|
+
tag: "@bot",
|
19
20
|
description: "An experimental agent with a lot of skills.",
|
20
21
|
skills: [
|
21
22
|
...token,
|
22
23
|
...(process?.env?.RESEND_API_KEY ? todo : []),
|
23
24
|
...(process?.env?.ALCHEMY_SDK ? gated : []),
|
24
25
|
...broadcast,
|
26
|
+
...wordle,
|
25
27
|
],
|
26
28
|
};
|
29
|
+
|
30
|
+
// [!region gated]
|
31
|
+
const { client } = await xmtpClient({
|
32
|
+
hideInitLogMessage: true,
|
33
|
+
});
|
34
|
+
|
35
|
+
startGatedGroupServer(client);
|
36
|
+
// [!endregion gated]
|
37
|
+
|
27
38
|
run(
|
28
39
|
async (context: XMTPContext) => {
|
29
40
|
const {
|
@@ -37,5 +48,5 @@ run(
|
|
37
48
|
fs.writeFileSync("example_prompt.md", prompt);
|
38
49
|
await agentReply(context, prompt);
|
39
50
|
},
|
40
|
-
{ agent },
|
51
|
+
{ agent, experimental: true },
|
41
52
|
);
|
@@ -17,10 +17,10 @@ export async function checkNft(
|
|
17
17
|
(nft: any) =>
|
18
18
|
nft.contract.name.toLowerCase() === collectionSlug.toLowerCase(),
|
19
19
|
);
|
20
|
-
console.log(
|
21
|
-
|
22
|
-
|
23
|
-
);
|
20
|
+
// console.log(
|
21
|
+
// `NFTs owned on ${Network.BASE_MAINNET}:`,
|
22
|
+
// nfts.ownedNfts.length,
|
23
|
+
// );
|
24
24
|
console.log("is the nft owned: ", ownsNft);
|
25
25
|
return ownsNft as boolean;
|
26
26
|
} catch (error) {
|
@@ -0,0 +1,26 @@
|
|
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
|
+
}
|
@@ -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
|
+
}
|
@@ -20,7 +20,7 @@ export async function createGroup(
|
|
20
20
|
member.accountAddresses.includes(senderAddress.toLowerCase()),
|
21
21
|
);
|
22
22
|
if (senderMember) {
|
23
|
-
|
23
|
+
senderInboxId = senderMember.inboxId;
|
24
24
|
console.log("Sender's inboxId:", senderInboxId);
|
25
25
|
} else {
|
26
26
|
console.log("Sender not found in members list");
|
@@ -91,26 +91,27 @@ export async function removeFromGroup(
|
|
91
91
|
export async function addToGroup(
|
92
92
|
groupId: string,
|
93
93
|
client: V3Client,
|
94
|
-
|
95
|
-
|
94
|
+
address: string,
|
95
|
+
asAdmin: boolean = false,
|
96
96
|
): Promise<{ code: number; message: string }> {
|
97
97
|
try {
|
98
|
-
let lowerAddress =
|
99
|
-
const { v2, v3 } = await isOnXMTP(client,
|
98
|
+
let lowerAddress = address.toLowerCase();
|
99
|
+
const { v2, v3 } = await isOnXMTP(client, null, lowerAddress);
|
100
100
|
if (!v3)
|
101
101
|
return {
|
102
102
|
code: 400,
|
103
103
|
message: "You don't seem to have a v3 identity ",
|
104
104
|
};
|
105
|
-
const
|
106
|
-
|
107
|
-
|
108
|
-
await
|
109
|
-
//DON'T TOUCH THIS LINE
|
110
|
-
await conversation?.addMembers([lowerAddress]);
|
105
|
+
const group = await client.conversations.getConversationById(groupId);
|
106
|
+
console.warn("Adding to group", group?.id);
|
107
|
+
await group?.sync();
|
108
|
+
await group?.addMembers([lowerAddress]);
|
111
109
|
console.warn("Added member to group");
|
112
|
-
await
|
113
|
-
|
110
|
+
await group?.sync();
|
111
|
+
if (asAdmin) {
|
112
|
+
await group?.addSuperAdmin(lowerAddress);
|
113
|
+
}
|
114
|
+
const members = await group?.members();
|
114
115
|
console.warn("Number of members", members?.length);
|
115
116
|
|
116
117
|
if (members) {
|
@@ -18,12 +18,13 @@ export const broadcast: Skill[] = [
|
|
18
18
|
async function handler(context: XMTPContext) {
|
19
19
|
const {
|
20
20
|
message: {
|
21
|
-
content: {
|
21
|
+
content: {
|
22
|
+
params: { message },
|
23
|
+
},
|
22
24
|
},
|
23
25
|
} = context;
|
24
26
|
|
25
27
|
const fakeSubscribers = ["0x93E2fc3e99dFb1238eB9e0eF2580EFC5809C7204"];
|
26
|
-
const { message } = params;
|
27
28
|
await context.send("This is how your message will look like:");
|
28
29
|
await context.send(message);
|
29
30
|
const emailResponse = await context.awaitResponse(
|
@@ -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
|
+
}
|
@@ -2,7 +2,7 @@ import { XMTPContext, Skill, V3Client } from "@xmtp/message-kit";
|
|
2
2
|
import { createGroup } from "../lib/xmtp.js";
|
3
3
|
import express from "express";
|
4
4
|
import { checkNft } from "../lib/alchemy.js";
|
5
|
-
|
5
|
+
import { addToGroup } from "../lib/xmtp.js";
|
6
6
|
export const gated: Skill[] = [
|
7
7
|
{
|
8
8
|
skill: "/create",
|
@@ -12,14 +12,6 @@ export const gated: Skill[] = [
|
|
12
12
|
params: {},
|
13
13
|
description: "Create a new group.",
|
14
14
|
},
|
15
|
-
{
|
16
|
-
skill: "/id",
|
17
|
-
examples: ["/id"],
|
18
|
-
handler: handler,
|
19
|
-
adminOnly: true,
|
20
|
-
params: {},
|
21
|
-
description: "Get group id.",
|
22
|
-
},
|
23
15
|
];
|
24
16
|
|
25
17
|
async function handler(context: XMTPContext) {
|
@@ -29,23 +21,18 @@ async function handler(context: XMTPContext) {
|
|
29
21
|
content: { skill },
|
30
22
|
},
|
31
23
|
client,
|
32
|
-
group,
|
33
24
|
} = context;
|
34
25
|
|
35
|
-
if (skill
|
36
|
-
console.log(group?.id);
|
37
|
-
} else if (skill === "create") {
|
38
|
-
console.log(client, sender.address, client.accountAddress);
|
26
|
+
if (skill === "create") {
|
39
27
|
const group = await createGroup(
|
40
28
|
client,
|
41
29
|
sender.address,
|
42
30
|
client.accountAddress,
|
43
31
|
);
|
44
32
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
//startServer(client);
|
33
|
+
await context.send(
|
34
|
+
`Group created!\n- ID: ${group?.id}\n- Group Frame URL: https://converse.xyz/group/${group?.id}: \n- This url will deelink to the group inside Converse\n- Once in the other group you can share the invite with your friends.`,
|
35
|
+
);
|
49
36
|
return;
|
50
37
|
} else {
|
51
38
|
await context.send(
|
@@ -54,22 +41,24 @@ async function handler(context: XMTPContext) {
|
|
54
41
|
}
|
55
42
|
}
|
56
43
|
|
57
|
-
export function
|
44
|
+
export function startGatedGroupServer(client: V3Client) {
|
58
45
|
async function addWalletToGroup(
|
59
46
|
walletAddress: string,
|
60
47
|
groupId: string,
|
61
48
|
): Promise<string> {
|
62
|
-
const
|
63
|
-
await client.conversations.getConversationById(groupId);
|
64
|
-
const verified = await checkNft(walletAddress, "XMTPeople");
|
49
|
+
const verified = true; //await checkNft(walletAddress, "XMTPeople");
|
65
50
|
if (!verified) {
|
66
51
|
console.log("User cant be added to the group");
|
67
52
|
return "not verified";
|
68
53
|
} else {
|
69
54
|
try {
|
70
|
-
await
|
71
|
-
|
72
|
-
|
55
|
+
const added = await addToGroup(groupId, client, walletAddress);
|
56
|
+
if (added.code === 200) {
|
57
|
+
console.log(`Added wallet address: ${walletAddress} to the group`);
|
58
|
+
return "success";
|
59
|
+
} else {
|
60
|
+
return added.message;
|
61
|
+
}
|
73
62
|
} catch (error: any) {
|
74
63
|
console.log(error.message);
|
75
64
|
return "error";
|
@@ -54,9 +54,9 @@ export async function handler(context: XMTPContext) {
|
|
54
54
|
try {
|
55
55
|
let { reply } = await context.textGeneration(
|
56
56
|
email,
|
57
|
-
"Make this summary concise and to the point to be sent in an
|
57
|
+
"Make this summary concise and to the point to be sent in an email.\n msg: " +
|
58
58
|
previousMsg,
|
59
|
-
"You are an expert at summarizing to-dos.",
|
59
|
+
"You are an expert at summarizing to-dos. Return in format html and just the content inside the body tag. Dont return `html` or `body` tags",
|
60
60
|
);
|
61
61
|
if (typeof reply === "string") {
|
62
62
|
let content = {
|
@@ -0,0 +1,97 @@
|
|
1
|
+
import { XMTPContext } from "@xmtp/message-kit";
|
2
|
+
import type { Skill } from "@xmtp/message-kit";
|
3
|
+
|
4
|
+
export const wordle: Skill[] = [
|
5
|
+
{
|
6
|
+
skill: "/wordle",
|
7
|
+
handler: handler,
|
8
|
+
examples: ["/wordle"],
|
9
|
+
description: "Play wordle.",
|
10
|
+
params: {},
|
11
|
+
},
|
12
|
+
{
|
13
|
+
skill: "/arena [word count] [audience size]",
|
14
|
+
examples: ["/arena 3 15"],
|
15
|
+
handler: handler,
|
16
|
+
description: "Play arena.",
|
17
|
+
params: {
|
18
|
+
wordCount: {
|
19
|
+
default: 3,
|
20
|
+
type: "number",
|
21
|
+
},
|
22
|
+
audienceSize: {
|
23
|
+
default: 15,
|
24
|
+
type: "number",
|
25
|
+
},
|
26
|
+
},
|
27
|
+
},
|
28
|
+
];
|
29
|
+
|
30
|
+
async function handler(context: XMTPContext) {
|
31
|
+
const {
|
32
|
+
message: {
|
33
|
+
content: { skill },
|
34
|
+
},
|
35
|
+
} = context;
|
36
|
+
|
37
|
+
if (skill === "arena") {
|
38
|
+
await handleArenaMessage(context);
|
39
|
+
} else if (skill === "wordle") {
|
40
|
+
await context.send("https://framedl.xyz");
|
41
|
+
} else if (skill === "help") {
|
42
|
+
await context.send(
|
43
|
+
"For using this bot you can use the following commands:\n\n" +
|
44
|
+
"/wordle, @wordle, 🔍, 🔎 - To start the game\n" +
|
45
|
+
"/arena <word count> <audience size> - To start the arena game\n" +
|
46
|
+
"/help - To see commands",
|
47
|
+
);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
async function handleArenaMessage(context: XMTPContext) {
|
51
|
+
const {
|
52
|
+
message: {
|
53
|
+
content: { text },
|
54
|
+
},
|
55
|
+
members,
|
56
|
+
} = context;
|
57
|
+
|
58
|
+
const apiKey = process.env.FRAMEDL_API_KEY;
|
59
|
+
if (!apiKey) {
|
60
|
+
console.log("FRAMEDL_API_KEY is not set");
|
61
|
+
await context.send("https://www.framedl.xyz/games/arena/create");
|
62
|
+
return;
|
63
|
+
}
|
64
|
+
const participantCount = members && members.length ? members.length - 1 : 0;
|
65
|
+
const args = text?.split(" ") ?? [];
|
66
|
+
const wordCountArg = args[1] ? parseInt(args[1], 10) : 3;
|
67
|
+
const audienceSizeArg = args[2] ? parseInt(args[2], 10) : participantCount;
|
68
|
+
if (isNaN(wordCountArg) || isNaN(audienceSizeArg)) {
|
69
|
+
await context.send(
|
70
|
+
"usage: /arena <word count> <audience size>\n\n" +
|
71
|
+
"word count: number of words in the arena (default: 3, min: 1, max: 9)\n" +
|
72
|
+
"audience size: number of audience members (default: number of participants excluding wordle bot, min: 1, max: 15)",
|
73
|
+
);
|
74
|
+
return;
|
75
|
+
}
|
76
|
+
|
77
|
+
const audienceSize = Math.max(1, Math.min(15, audienceSizeArg));
|
78
|
+
const wordCount = Math.max(1, Math.min(9, wordCountArg));
|
79
|
+
|
80
|
+
try {
|
81
|
+
const response = await fetch("https://www.framedl.xyz/api/arenas", {
|
82
|
+
method: "POST",
|
83
|
+
body: JSON.stringify({ wordCount, audienceSize }),
|
84
|
+
headers: {
|
85
|
+
"Content-Type": "application/json",
|
86
|
+
"x-framedl-api-key": apiKey,
|
87
|
+
},
|
88
|
+
});
|
89
|
+
|
90
|
+
const data = (await response.json()) as { arenaUrl: string };
|
91
|
+
|
92
|
+
await context.send(data.arenaUrl);
|
93
|
+
} catch (error) {
|
94
|
+
console.error(error);
|
95
|
+
await context.send("https://www.framedl.xyz/games/arena/create");
|
96
|
+
}
|
97
|
+
}
|
@@ -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,58 +0,0 @@
|
|
1
|
-
import { XMTPContext } from "@xmtp/message-kit";
|
2
|
-
import type { Skill } from "@xmtp/message-kit";
|
3
|
-
|
4
|
-
export const game: Skill[] = [
|
5
|
-
{
|
6
|
-
skill: "/game [game]",
|
7
|
-
handler: handler,
|
8
|
-
description: "Play a game.",
|
9
|
-
examples: ["/game wordle", "/game slot", "/game help"],
|
10
|
-
params: {
|
11
|
-
game: {
|
12
|
-
default: "",
|
13
|
-
type: "string",
|
14
|
-
values: ["wordle", "slot", "help"],
|
15
|
-
},
|
16
|
-
},
|
17
|
-
},
|
18
|
-
];
|
19
|
-
|
20
|
-
export async function handler(context: XMTPContext) {
|
21
|
-
const {
|
22
|
-
message: {
|
23
|
-
content: { skill, params, text },
|
24
|
-
},
|
25
|
-
} = context;
|
26
|
-
if (!skill) {
|
27
|
-
if (text === "🔎" || text === "🔍") {
|
28
|
-
// Send the URL for the requested game
|
29
|
-
context.reply("https://framedl.xyz/");
|
30
|
-
}
|
31
|
-
return;
|
32
|
-
}
|
33
|
-
// URLs for each game type
|
34
|
-
const gameUrls: { [key: string]: string } = {
|
35
|
-
wordle: "https://framedl.xyz",
|
36
|
-
slot: "https://slot-machine-frame.vercel.app",
|
37
|
-
};
|
38
|
-
let returnText = "";
|
39
|
-
switch (params.game) {
|
40
|
-
case "wordle":
|
41
|
-
case "slot":
|
42
|
-
// Retrieve the URL for the requested game using a simplified variable assignment
|
43
|
-
const gameUrl = gameUrls[params.game];
|
44
|
-
// Send the URL for the requested game
|
45
|
-
returnText = gameUrl;
|
46
|
-
break;
|
47
|
-
|
48
|
-
case "help":
|
49
|
-
returnText = "Available games: \n/game wordle\n/game slot";
|
50
|
-
break;
|
51
|
-
default:
|
52
|
-
// Inform the user about unrecognized skills and provide available options
|
53
|
-
returnText =
|
54
|
-
"Skill not recognized. Available games: wordle, slot, or help.";
|
55
|
-
break;
|
56
|
-
}
|
57
|
-
return { code: 200, message: returnText };
|
58
|
-
}
|