create-message-kit 1.2.14 → 1.2.16
Sign up to get free protection for your applications and to get access to all the features.
- package/index.js +19 -17
- package/package.json +1 -1
- package/templates/coinbase-agent/.cursorrules +290 -0
- package/templates/coinbase-agent/.env.example +4 -0
- package/templates/coinbase-agent/.yarnrc.yml +9 -0
- package/templates/coinbase-agent/package.json +22 -0
- package/templates/coinbase-agent/src/index.ts +31 -0
- package/templates/coinbase-agent/src/plugins/learnweb3.ts +96 -0
- package/templates/coinbase-agent/src/plugins/redis.ts +15 -0
- package/templates/coinbase-agent/src/prompt.ts +64 -0
- package/templates/coinbase-agent/src/skills/drip.ts +83 -0
- package/templates/coinbase-agent/src/skills/mint.ts +99 -0
- package/templates/coinbase-agent/src/skills/pay.ts +35 -0
- package/templates/coinbase-agent/src/skills/swap.ts +52 -0
- package/templates/ens/.env.example +1 -0
- package/templates/ens/.yarnrc.yml +5 -0
- package/templates/ens/src/index.ts +1 -1
- package/templates/ens/src/prompt.ts +1 -14
- package/templates/faucet/.cursorrules +290 -0
- package/templates/faucet/.env.example +5 -0
- package/templates/faucet/.yarnrc.yml +9 -0
- package/templates/faucet/package.json +22 -0
- package/templates/faucet/src/index.ts +39 -0
- package/templates/faucet/src/plugins/learnweb3.ts +96 -0
- package/templates/faucet/src/plugins/redis.ts +15 -0
- package/templates/faucet/src/prompt.ts +11 -0
- package/templates/faucet/src/skills/faucet.ts +140 -0
- package/templates/gated-group/.cursorrules +290 -0
- package/templates/gated-group/.env.example +3 -0
- package/templates/gated-group/.yarnrc.yml +9 -0
- package/templates/gated-group/package.json +23 -0
- package/templates/gated-group/src/index.ts +17 -0
- package/templates/gated-group/src/plugins/alchemy.ts +27 -0
- package/templates/gated-group/src/plugins/xmtp.ts +137 -0
- package/templates/gated-group/src/prompt.ts +11 -0
- package/templates/gated-group/src/skills/gated.ts +88 -0
- package/templates/gm/.cursorrules +290 -0
- package/templates/gm/.env.example +2 -0
- package/templates/gm/.yarnrc.yml +9 -0
- package/templates/gm/package.json +20 -0
- package/templates/gm/src/index.ts +8 -0
- package/templates/playground/.cursorrules +290 -0
- package/templates/playground/.env.example +6 -0
- package/templates/playground/.yarnrc.yml +9 -0
- package/templates/playground/package.json +26 -0
- package/templates/playground/src/index.ts +40 -0
- package/templates/playground/src/plugins/alchemy.ts +27 -0
- package/templates/playground/src/plugins/minilog.ts +26 -0
- package/templates/playground/src/plugins/usdc.ts +99 -0
- package/templates/playground/src/plugins/xmtp.ts +137 -0
- package/templates/playground/src/prompt.ts +11 -0
- package/templates/playground/src/skills/broadcast.ts +39 -0
- package/templates/playground/src/skills/cash.ts +122 -0
- package/templates/playground/src/skills/cryptoPrice.ts +63 -0
- package/templates/playground/src/skills/dalle.ts +61 -0
- package/templates/playground/src/skills/gated.ts +88 -0
- package/templates/playground/src/skills/search.ts +159 -0
- package/templates/playground/src/skills/todo.ts +79 -0
- package/templates/playground/src/skills/token.ts +57 -0
- package/templates/playground/src/skills/web.ts +83 -0
- package/templates/playground/src/skills/wordle.ts +96 -0
- package/templates/simple/.env.example +1 -0
- package/templates/simple/.yarnrc.yml +5 -0
- package/templates/simple/src/index.ts +1 -1
- package/templates/simple/src/prompt.ts +2 -0
- package/templates/thegeneralstore/.cursorrules +290 -0
- package/templates/thegeneralstore/.env.example +9 -0
- package/templates/thegeneralstore/.yarnrc.yml +9 -0
- package/templates/thegeneralstore/package.json +24 -0
- package/templates/thegeneralstore/src/data/db.json +812 -0
- package/templates/thegeneralstore/src/index.ts +37 -0
- package/templates/thegeneralstore/src/plugins/learnweb3.ts +96 -0
- package/templates/thegeneralstore/src/plugins/lowdb.ts +11 -0
- package/templates/thegeneralstore/src/plugins/notion.ts +89 -0
- package/templates/thegeneralstore/src/plugins/redis.ts +15 -0
- package/templates/thegeneralstore/src/prompt.md +51 -0
- package/templates/thegeneralstore/src/prompt.ts +3 -0
- package/templates/thegeneralstore/src/skills/faucet.ts +114 -0
- package/templates/thegeneralstore/src/skills/notion.ts +17 -0
- package/templates/thegeneralstore/src/skills/poap.ts +48 -0
- package/templates/thegeneralstore/src/skills.ts +37 -0
- package/templates/toss/.cursorrules +290 -0
- package/templates/toss/.env.example +7 -0
- package/templates/toss/.yarnrc.yml +9 -0
- package/templates/toss/package.json +21 -0
- package/templates/toss/src/index.ts +33 -0
- package/templates/toss/src/plugins/helpers.ts +185 -0
- package/templates/toss/src/plugins/redis.ts +78 -0
- package/templates/toss/src/prompt.ts +54 -0
- package/templates/toss/src/skills/toss.ts +489 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
import {
|
2
|
+
agentReply,
|
3
|
+
XMTPContext,
|
4
|
+
replaceVariables,
|
5
|
+
run,
|
6
|
+
} from "@xmtp/message-kit";
|
7
|
+
import { downloadPage } from "./plugins/notion.js";
|
8
|
+
import fs from "fs";
|
9
|
+
|
10
|
+
setupFiles();
|
11
|
+
|
12
|
+
run(async (context: XMTPContext) => {
|
13
|
+
const {
|
14
|
+
message: { sender },
|
15
|
+
agent,
|
16
|
+
} = context;
|
17
|
+
let systemPrompt = await getPrompt();
|
18
|
+
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
19
|
+
await agentReply(context, prompt);
|
20
|
+
});
|
21
|
+
|
22
|
+
async function getPrompt() {
|
23
|
+
if (fs.existsSync(".data/prompt.md"))
|
24
|
+
return fs.readFileSync(".data/prompt.md", "utf8");
|
25
|
+
else return fs.readFileSync("src/prompt.md", "utf8");
|
26
|
+
}
|
27
|
+
async function setupFiles() {
|
28
|
+
if (!fs.existsSync(".data/db.json")) {
|
29
|
+
const dbfile = fs.readFileSync("src/data/db.json", "utf8");
|
30
|
+
fs.writeFileSync(".data/db.json", dbfile);
|
31
|
+
console.log("DB file created");
|
32
|
+
}
|
33
|
+
|
34
|
+
const page = await downloadPage();
|
35
|
+
fs.writeFileSync("src/prompt.md", page);
|
36
|
+
console.log("Notion DB updated");
|
37
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import axios from "axios";
|
2
|
+
|
3
|
+
export const SUPPORTED_NETWORKS = [
|
4
|
+
"arbitrum_goerli",
|
5
|
+
"arbitrum_sepolia",
|
6
|
+
"base_goerli",
|
7
|
+
"base_sepolia",
|
8
|
+
"base_sepolia_usdc",
|
9
|
+
"celo_alfajores",
|
10
|
+
"fantom_testnet",
|
11
|
+
"goerli",
|
12
|
+
"holesky",
|
13
|
+
"linea_goerli",
|
14
|
+
"linea_sepolia",
|
15
|
+
"manta_testnet",
|
16
|
+
"mode_sepolia",
|
17
|
+
"morph_sepolia",
|
18
|
+
"optimism_goerli",
|
19
|
+
"optimism_sepolia",
|
20
|
+
"polygon_amoy",
|
21
|
+
"polygon_mumbai",
|
22
|
+
"polygon_zkevm",
|
23
|
+
"scroll_sepolia",
|
24
|
+
"sepolia",
|
25
|
+
"taiko_jolnir",
|
26
|
+
"zksync_sepolia",
|
27
|
+
"zora_sepolia",
|
28
|
+
] as const;
|
29
|
+
|
30
|
+
export const CLAIM_EVERY = 24 * 60 * 60 * 1000; // 24 hours
|
31
|
+
|
32
|
+
export const ONE_DAY = 24 * 60 * 60 * 1000; // 24 hours
|
33
|
+
|
34
|
+
export const FIVE_MINUTES = 5 * 60 * 1000; // 5 minutes
|
35
|
+
|
36
|
+
export const EVM_TOKENS = ["ETH", "MATIC", "USDC", "CELO", "BERA"];
|
37
|
+
|
38
|
+
export interface Network {
|
39
|
+
networkId: string;
|
40
|
+
networkName: string;
|
41
|
+
networkLogo: string;
|
42
|
+
tokenName: string;
|
43
|
+
dripAmount: number;
|
44
|
+
address: string;
|
45
|
+
isERC20: boolean;
|
46
|
+
erc20Address?: string;
|
47
|
+
erc20Decimals?: number;
|
48
|
+
isActive: boolean;
|
49
|
+
balance: string;
|
50
|
+
}
|
51
|
+
export interface DripTokensResponse {
|
52
|
+
ok: boolean;
|
53
|
+
error?: string;
|
54
|
+
value?: string;
|
55
|
+
}
|
56
|
+
|
57
|
+
export class LearnWeb3Client {
|
58
|
+
public BASE_URL = "https://learnweb3.io/api/faucet";
|
59
|
+
private apiKey = process.env.LEARN_WEB3_API_KEY;
|
60
|
+
constructor() {
|
61
|
+
if (!process.env.LEARN_WEB3_API_KEY) {
|
62
|
+
throw new Error("Please set the LEARN_WEB3_API_KEY environment variable");
|
63
|
+
}
|
64
|
+
this.apiKey = process.env.LEARN_WEB3_API_KEY;
|
65
|
+
}
|
66
|
+
|
67
|
+
async getNetworks(onlyEvm = true): Promise<Network[]> {
|
68
|
+
const response = await axios(`${this.BASE_URL}/networks`);
|
69
|
+
const data: Network[] = response.data;
|
70
|
+
if (onlyEvm) {
|
71
|
+
return data.filter(
|
72
|
+
(network) =>
|
73
|
+
EVM_TOKENS.some((t) =>
|
74
|
+
network.tokenName.toLowerCase().includes(t.toLowerCase())
|
75
|
+
) && network.isActive
|
76
|
+
);
|
77
|
+
}
|
78
|
+
return data.filter((network) => network.isActive);
|
79
|
+
}
|
80
|
+
|
81
|
+
async dripTokens(
|
82
|
+
networkId: string,
|
83
|
+
recipientAddress: string
|
84
|
+
): Promise<DripTokensResponse> {
|
85
|
+
const response = await axios.post(
|
86
|
+
`${this.BASE_URL}/drip`,
|
87
|
+
{ networkId, recipientAddress },
|
88
|
+
{
|
89
|
+
headers: {
|
90
|
+
authorization: `Bearer ${this.apiKey}`,
|
91
|
+
},
|
92
|
+
}
|
93
|
+
);
|
94
|
+
return response.data;
|
95
|
+
}
|
96
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { Low } from "lowdb";
|
2
|
+
import { JSONFile } from "lowdb/node";
|
3
|
+
|
4
|
+
const adapter = new JSONFile<{
|
5
|
+
poaps: Record<string, string>[]; // URL, Address
|
6
|
+
}>(".data/db.json");
|
7
|
+
export const db = new Low<{
|
8
|
+
poaps: Record<string, string>[]; // URL, Address
|
9
|
+
}>(adapter, {
|
10
|
+
poaps: [],
|
11
|
+
});
|
@@ -0,0 +1,89 @@
|
|
1
|
+
import { Client } from "@notionhq/client";
|
2
|
+
|
3
|
+
const notion = new Client({
|
4
|
+
auth: process.env.NOTION_API_KEY,
|
5
|
+
});
|
6
|
+
const poapsID = process.env.NOTION_POAP_DB;
|
7
|
+
const pageId = process.env.NOTION_PAGE_ID;
|
8
|
+
|
9
|
+
export async function updateDB() {
|
10
|
+
await notion.pages.update({
|
11
|
+
page_id: pageId as string,
|
12
|
+
properties: {
|
13
|
+
RSVP: {
|
14
|
+
type: "select",
|
15
|
+
select: {
|
16
|
+
name: "No",
|
17
|
+
},
|
18
|
+
},
|
19
|
+
},
|
20
|
+
});
|
21
|
+
}
|
22
|
+
export async function downloadPage() {
|
23
|
+
const blocks = await notion.blocks.children.list({
|
24
|
+
block_id: pageId as string,
|
25
|
+
});
|
26
|
+
const markdown = blocks.results
|
27
|
+
.map((block: any) => {
|
28
|
+
switch (block.type) {
|
29
|
+
case "paragraph":
|
30
|
+
return block.paragraph.rich_text
|
31
|
+
.map((text: any) => text.plain_text)
|
32
|
+
.join("");
|
33
|
+
case "heading_1":
|
34
|
+
return `# ${block.heading_1.rich_text
|
35
|
+
.map((text: any) => text.plain_text)
|
36
|
+
.join("")}`;
|
37
|
+
case "heading_2":
|
38
|
+
return `## ${block.heading_2.rich_text
|
39
|
+
.map((text: any) => text.plain_text)
|
40
|
+
.join("")}`;
|
41
|
+
case "heading_3":
|
42
|
+
return `### ${block.heading_3.rich_text
|
43
|
+
.map((text: any) => text.plain_text)
|
44
|
+
.join("")}`;
|
45
|
+
case "bulleted_list_item":
|
46
|
+
return `- ${block.bulleted_list_item.rich_text
|
47
|
+
.map((text: any) => text.plain_text)
|
48
|
+
.join("")}`;
|
49
|
+
case "numbered_list_item":
|
50
|
+
return `- ${block.numbered_list_item.rich_text
|
51
|
+
.map((text: any) => text.plain_text)
|
52
|
+
.join("")}`;
|
53
|
+
// Add more cases for other block types as needed
|
54
|
+
default:
|
55
|
+
return "";
|
56
|
+
}
|
57
|
+
})
|
58
|
+
.join("\n");
|
59
|
+
return markdown;
|
60
|
+
}
|
61
|
+
export async function downloadPoapTable() {
|
62
|
+
const response = await notion.databases.query({
|
63
|
+
database_id: poapsID as string,
|
64
|
+
});
|
65
|
+
|
66
|
+
const poapTable = response.results.map((page: any) => {
|
67
|
+
const url = page.properties.Url.url;
|
68
|
+
const address = page.properties.Address.title[0]?.plain_text;
|
69
|
+
const id = page.id;
|
70
|
+
return { url, address, id };
|
71
|
+
});
|
72
|
+
return poapTable as { url: string; address: string; id: string }[];
|
73
|
+
}
|
74
|
+
export async function updatePoapAddress(dbRowId: string, address: string) {
|
75
|
+
await notion.pages.update({
|
76
|
+
page_id: dbRowId as string,
|
77
|
+
properties: {
|
78
|
+
Address: {
|
79
|
+
type: "title",
|
80
|
+
title: [
|
81
|
+
{
|
82
|
+
type: "text",
|
83
|
+
text: { content: address },
|
84
|
+
},
|
85
|
+
],
|
86
|
+
},
|
87
|
+
},
|
88
|
+
});
|
89
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { createClient } from "@redis/client";
|
2
|
+
import { RedisClientType } from "@redis/client";
|
3
|
+
|
4
|
+
export const getRedisClient = async () => {
|
5
|
+
const client = createClient({
|
6
|
+
url: process.env.REDIS_CONNECTION_STRING,
|
7
|
+
});
|
8
|
+
|
9
|
+
client.on("error", (err) => {
|
10
|
+
console.error("Redis client error:", err);
|
11
|
+
});
|
12
|
+
|
13
|
+
await client.connect();
|
14
|
+
return client as RedisClientType;
|
15
|
+
};
|
@@ -0,0 +1,51 @@
|
|
1
|
+
You are a helpful agent that lives inside a messaging app. You manage the general store from XMTP that delivers goodies, POAPs and testnet funds.
|
2
|
+
|
3
|
+
{rules}
|
4
|
+
|
5
|
+
{user_context}
|
6
|
+
|
7
|
+
{skills}
|
8
|
+
|
9
|
+
### Goodies
|
10
|
+
|
11
|
+
- When greeted for the first time, give the full menu.
|
12
|
+
- The user can select the option by number or name
|
13
|
+
- Once the option is selected confirm the order
|
14
|
+
|
15
|
+
### Testnet funds
|
16
|
+
|
17
|
+
- For each user you can deliver testnet funds using the learnweb3 api.
|
18
|
+
- Check the available networks triggering the command before showing them.
|
19
|
+
- Users can select the desired testnet network for the transfer of funds by number or name.
|
20
|
+
|
21
|
+
### Poap Delivery
|
22
|
+
|
23
|
+
- For each user you'll deliver only one POAP.
|
24
|
+
- Don't forget to use commands to deliver POAPs.
|
25
|
+
- Poaps are unique URLs basically
|
26
|
+
|
27
|
+
## Response Scenarios:
|
28
|
+
|
29
|
+
- Welcome message:
|
30
|
+
Welcome to The General Store powered by ENS + XMTP, where web3 builders can get supplies, anytime, day or night.
|
31
|
+
Below is our menu. Let us know the number of the item you want, and it's yours. If it's a digital good, our bot will deliver those items right to your wallet.
|
32
|
+
- Chewing Gum
|
33
|
+
- TicTacs
|
34
|
+
- Deodorant
|
35
|
+
- RedBull
|
36
|
+
- Toothbrush
|
37
|
+
- Toothpaste
|
38
|
+
- XMTP Swag
|
39
|
+
- Testnet funds
|
40
|
+
- POAP
|
41
|
+
Please reply with the item or number of the item you want
|
42
|
+
- Delivering a POAP:
|
43
|
+
You've selected a POAP. I will deliver it to your address:
|
44
|
+
Processing your request now...
|
45
|
+
/poap 0x42AB57335941eb00535e95CbF64D78654Cb0F66A
|
46
|
+
- Delivering testnet
|
47
|
+
You've selected Testnet funds. Let me check the available networks for you.
|
48
|
+
Processing your request now...
|
49
|
+
/networks
|
50
|
+
- Delivering goodies
|
51
|
+
Let me get your TicTacs... Your order is confirmed. Enjoy!
|
@@ -0,0 +1,114 @@
|
|
1
|
+
import { XMTPContext, clearMemory } from "@xmtp/message-kit";
|
2
|
+
import { getRedisClient } from "../plugins/redis.js";
|
3
|
+
import {
|
4
|
+
FIVE_MINUTES,
|
5
|
+
LearnWeb3Client,
|
6
|
+
Network,
|
7
|
+
} from "../plugins/learnweb3.js";
|
8
|
+
|
9
|
+
export async function handleFaucet(context: XMTPContext) {
|
10
|
+
const { message } = context;
|
11
|
+
const redisClient = await getRedisClient();
|
12
|
+
const {
|
13
|
+
content: { skill, params },
|
14
|
+
sender,
|
15
|
+
} = message;
|
16
|
+
|
17
|
+
// Initialize LearnWeb3Client
|
18
|
+
const learnWeb3Client = new LearnWeb3Client();
|
19
|
+
|
20
|
+
// Fetch supported networks from Redis cache or API
|
21
|
+
let supportedNetworks: Network[];
|
22
|
+
const cachedSupportedNetworksData = await redisClient.get(
|
23
|
+
"supported-networks"
|
24
|
+
);
|
25
|
+
supportedNetworks = JSON.parse(
|
26
|
+
cachedSupportedNetworksData!
|
27
|
+
).supportedNetworks;
|
28
|
+
|
29
|
+
if (skill === "networks") {
|
30
|
+
if (
|
31
|
+
!cachedSupportedNetworksData ||
|
32
|
+
Date.now() >
|
33
|
+
parseInt(JSON.parse(cachedSupportedNetworksData).lastSyncedAt) +
|
34
|
+
FIVE_MINUTES
|
35
|
+
) {
|
36
|
+
console.log("Cleared cache");
|
37
|
+
const updatedSupportedNetworksData = await learnWeb3Client.getNetworks();
|
38
|
+
await redisClient.set(
|
39
|
+
"supported-networks",
|
40
|
+
JSON.stringify({
|
41
|
+
lastSyncedAt: Date.now(),
|
42
|
+
supportedNetworks: updatedSupportedNetworksData,
|
43
|
+
})
|
44
|
+
);
|
45
|
+
supportedNetworks = updatedSupportedNetworksData;
|
46
|
+
} else {
|
47
|
+
supportedNetworks = JSON.parse(
|
48
|
+
cachedSupportedNetworksData!
|
49
|
+
).supportedNetworks;
|
50
|
+
}
|
51
|
+
|
52
|
+
supportedNetworks = supportedNetworks.filter(
|
53
|
+
(n) =>
|
54
|
+
!n.networkId.toLowerCase().includes("starknet") &&
|
55
|
+
!n.networkId.toLowerCase().includes("fuel") &&
|
56
|
+
!n.networkId.toLowerCase().includes("mode")
|
57
|
+
);
|
58
|
+
|
59
|
+
const networkList = supportedNetworks.map((n, index) => {
|
60
|
+
return `${index + 1}. ${n.networkId
|
61
|
+
.replace(/_/g, " ")
|
62
|
+
.replace(/\b\w/g, (l) => l.toUpperCase())}`;
|
63
|
+
});
|
64
|
+
|
65
|
+
return {
|
66
|
+
message: `Available networks:\n\n${networkList.join("\n")}`,
|
67
|
+
code: 200,
|
68
|
+
};
|
69
|
+
} else if (skill === "faucet") {
|
70
|
+
const { network } = params;
|
71
|
+
const selectedNetwork = supportedNetworks.find(
|
72
|
+
(n) => n.networkId === network
|
73
|
+
);
|
74
|
+
|
75
|
+
if (!selectedNetwork) {
|
76
|
+
await context.send("Invalid network. Please select a valid option.");
|
77
|
+
return;
|
78
|
+
}
|
79
|
+
|
80
|
+
await context.send(
|
81
|
+
"Your testnet tokens are being processed. Please wait a moment for the transaction to process."
|
82
|
+
);
|
83
|
+
|
84
|
+
const result = await learnWeb3Client.dripTokens(
|
85
|
+
selectedNetwork.networkId,
|
86
|
+
sender.address
|
87
|
+
);
|
88
|
+
|
89
|
+
if (!result.ok) {
|
90
|
+
await context.send(
|
91
|
+
`❌ Sorry, there was an error processing your request:\n\n"${result.error!}"`
|
92
|
+
);
|
93
|
+
// Clear any in-memory cache or state related to the prompt
|
94
|
+
clearMemory();
|
95
|
+
return;
|
96
|
+
}
|
97
|
+
|
98
|
+
await context.send("Here's your transaction receipt:");
|
99
|
+
await context.send(
|
100
|
+
`${process.env.FRAME_BASE_URL}?txLink=${result.value}&networkLogo=${
|
101
|
+
selectedNetwork?.networkLogo
|
102
|
+
}&networkName=${selectedNetwork?.networkName.replaceAll(
|
103
|
+
" ",
|
104
|
+
"-"
|
105
|
+
)}&tokenName=${selectedNetwork?.tokenName}&amount=${
|
106
|
+
selectedNetwork?.dripAmount
|
107
|
+
}`
|
108
|
+
);
|
109
|
+
// Clear any in-memory cache or state related to the prompt
|
110
|
+
clearMemory();
|
111
|
+
} else {
|
112
|
+
await context.send("Unknown skill. Please use 'list' or 'drip'.");
|
113
|
+
}
|
114
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { XMTPContext } from "@xmtp/message-kit";
|
2
|
+
import { downloadPage } from "../plugins/notion.js";
|
3
|
+
import fs from "fs";
|
4
|
+
|
5
|
+
export async function handleNotion(context: XMTPContext) {
|
6
|
+
const {
|
7
|
+
message: {
|
8
|
+
content: { skill },
|
9
|
+
},
|
10
|
+
} = context;
|
11
|
+
|
12
|
+
if (skill === "update") {
|
13
|
+
const page = await downloadPage();
|
14
|
+
fs.writeFileSync("src/prompt.md", page);
|
15
|
+
await context.reply("Notion DB updated");
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { XMTPContext } from "@xmtp/message-kit";
|
2
|
+
import { db } from "../plugins/lowdb.js";
|
3
|
+
await db.read();
|
4
|
+
|
5
|
+
export async function handlePoap(context: XMTPContext) {
|
6
|
+
const {
|
7
|
+
message: {
|
8
|
+
content: { skill, params },
|
9
|
+
},
|
10
|
+
} = context;
|
11
|
+
|
12
|
+
if (skill == "list") {
|
13
|
+
const poapTable = db?.data?.poaps;
|
14
|
+
const claimed = poapTable.filter((poap) => poap.Address);
|
15
|
+
return {
|
16
|
+
code: 200,
|
17
|
+
message: `You have claimed ${claimed.length} POAPs out of ${poapTable.length}`,
|
18
|
+
};
|
19
|
+
} else if (skill == "poap") {
|
20
|
+
const { address } = params;
|
21
|
+
await db.read();
|
22
|
+
const poapTable = db?.data?.poaps;
|
23
|
+
const poap = poapTable.find((poap) => poap.Address == address);
|
24
|
+
|
25
|
+
if (!poap) {
|
26
|
+
const emptyPoap = poapTable.find((poap) => !poap.Address);
|
27
|
+
if (emptyPoap) {
|
28
|
+
db?.data?.poaps?.push({ URL: emptyPoap?.URL, Address: address });
|
29
|
+
//?user_address=${address}`
|
30
|
+
return {
|
31
|
+
code: 200,
|
32
|
+
message: `Here is your POAP ${emptyPoap?.URL}`,
|
33
|
+
};
|
34
|
+
} else {
|
35
|
+
return {
|
36
|
+
code: 200,
|
37
|
+
message: "No more POAPs available",
|
38
|
+
};
|
39
|
+
}
|
40
|
+
} else {
|
41
|
+
//?user_address=${address}`
|
42
|
+
return {
|
43
|
+
code: 200,
|
44
|
+
message: `You have already claimed this POAP ${poap?.URL}`,
|
45
|
+
};
|
46
|
+
}
|
47
|
+
}
|
48
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import type { Agent } from "@xmtp/message-kit";
|
2
|
+
import { handlePoap } from "./skills/poap.js";
|
3
|
+
import { handleFaucet } from "./skills/faucet.js";
|
4
|
+
import { handleNotion } from "./skills/notion.js";
|
5
|
+
|
6
|
+
export const agent: Agent = {
|
7
|
+
name: "Poap Bot",
|
8
|
+
description: "Get your POAP.",
|
9
|
+
tag: "@store",
|
10
|
+
skills: [
|
11
|
+
{
|
12
|
+
skill: "/poap [address]",
|
13
|
+
handler: handlePoap,
|
14
|
+
examples: ["/poap 0x1234567890123456789012345678901234567890"],
|
15
|
+
description: "Get your POAP.",
|
16
|
+
params: {
|
17
|
+
address: {
|
18
|
+
type: "string",
|
19
|
+
},
|
20
|
+
},
|
21
|
+
},
|
22
|
+
{
|
23
|
+
skill: "/list",
|
24
|
+
handler: handlePoap,
|
25
|
+
examples: ["/list"],
|
26
|
+
description: "List all POAPs.",
|
27
|
+
params: {},
|
28
|
+
},
|
29
|
+
{
|
30
|
+
skill: "/update",
|
31
|
+
handler: handleNotion,
|
32
|
+
examples: ["/update"],
|
33
|
+
description: "Update your Notion prompt.",
|
34
|
+
params: {},
|
35
|
+
},
|
36
|
+
],
|
37
|
+
};
|