create-message-kit 1.2.23 → 1.2.25
Sign up to get free protection for your applications and to get access to all the features.
- package/index.js +14 -13
- package/package.json +1 -2
- package/templates/ens/.cursorrules +0 -112
- package/templates/ens/package.json +1 -2
- package/templates/ens/src/index.ts +2 -16
- package/templates/ens/src/prompt.ts +1 -1
- package/templates/simple/.cursorrules +0 -112
- package/templates/simple/src/index.ts +0 -1
- package/templates/coinbase-agent/.cursorrules +0 -290
- package/templates/coinbase-agent/.env.example +0 -4
- package/templates/coinbase-agent/.yarnrc.yml +0 -9
- package/templates/coinbase-agent/package.json +0 -22
- package/templates/coinbase-agent/src/index.ts +0 -29
- package/templates/coinbase-agent/src/plugins/learnweb3.ts +0 -96
- package/templates/coinbase-agent/src/plugins/redis.ts +0 -15
- package/templates/coinbase-agent/src/prompt.ts +0 -64
- package/templates/coinbase-agent/src/skills/drip.ts +0 -83
- package/templates/coinbase-agent/src/skills/mint.ts +0 -99
- package/templates/coinbase-agent/src/skills/pay.ts +0 -35
- package/templates/coinbase-agent/src/skills/swap.ts +0 -52
- package/templates/faucet/.cursorrules +0 -290
- package/templates/faucet/.env.example +0 -5
- package/templates/faucet/.yarnrc.yml +0 -9
- package/templates/faucet/package.json +0 -22
- package/templates/faucet/src/index.ts +0 -28
- package/templates/faucet/src/plugins/learnweb3.ts +0 -96
- package/templates/faucet/src/plugins/redis.ts +0 -15
- package/templates/faucet/src/prompt.ts +0 -11
- package/templates/faucet/src/skills/faucet.ts +0 -140
- package/templates/gated-group/.cursorrules +0 -290
- package/templates/gated-group/.env.example +0 -3
- package/templates/gated-group/.yarnrc.yml +0 -9
- package/templates/gated-group/package.json +0 -23
- package/templates/gated-group/src/index.ts +0 -17
- package/templates/gated-group/src/plugins/alchemy.ts +0 -27
- package/templates/gated-group/src/plugins/xmtp.ts +0 -137
- package/templates/gated-group/src/prompt.ts +0 -11
- package/templates/gated-group/src/skills/gated.ts +0 -88
- package/templates/gm/.cursorrules +0 -290
- package/templates/gm/.env.example +0 -2
- package/templates/gm/.yarnrc.yml +0 -9
- package/templates/gm/package.json +0 -20
- package/templates/gm/src/index.ts +0 -16
- package/templates/hackathon-store/.cursorrules +0 -290
- package/templates/hackathon-store/.env.example +0 -6
- package/templates/hackathon-store/.yarnrc.yml +0 -9
- package/templates/hackathon-store/package.json +0 -20
- package/templates/hackathon-store/src/index.ts +0 -47
- package/templates/hackathon-store/src/plugins/notion.ts +0 -60
- package/templates/hackathon-store/src/prompt.md +0 -27
- package/templates/playground/.cursorrules +0 -290
- package/templates/playground/.env.example +0 -6
- package/templates/playground/.yarnrc.yml +0 -9
- package/templates/playground/package.json +0 -26
- package/templates/playground/src/index.ts +0 -38
- package/templates/playground/src/plugins/alchemy.ts +0 -27
- package/templates/playground/src/plugins/minilog.ts +0 -26
- package/templates/playground/src/plugins/usdc.ts +0 -99
- package/templates/playground/src/plugins/xmtp.ts +0 -137
- package/templates/playground/src/prompt.ts +0 -11
- package/templates/playground/src/skills/broadcast.ts +0 -39
- package/templates/playground/src/skills/cash.ts +0 -122
- package/templates/playground/src/skills/cryptoPrice.ts +0 -63
- package/templates/playground/src/skills/dalle.ts +0 -61
- package/templates/playground/src/skills/gated.ts +0 -88
- package/templates/playground/src/skills/search.ts +0 -159
- package/templates/playground/src/skills/todo.ts +0 -79
- package/templates/playground/src/skills/token.ts +0 -57
- package/templates/playground/src/skills/web.ts +0 -83
- package/templates/playground/src/skills/wordle.ts +0 -96
- package/templates/playground/src/vibes/chill.ts +0 -9
- package/templates/playground/src/vibes/friendly.ts +0 -9
- package/templates/playground/src/vibes/inquisitive.ts +0 -10
- package/templates/playground/src/vibes/playful.ts +0 -10
- package/templates/playground/src/vibes/professional.ts +0 -9
- package/templates/toss/.cursorrules +0 -290
- package/templates/toss/.env.example +0 -7
- package/templates/toss/.yarnrc.yml +0 -9
- package/templates/toss/package.json +0 -21
- package/templates/toss/src/index.ts +0 -29
- package/templates/toss/src/plugins/helpers.ts +0 -174
- package/templates/toss/src/plugins/redis.ts +0 -15
- package/templates/toss/src/prompt.ts +0 -54
- package/templates/toss/src/skills/toss.ts +0 -318
- package/templates/toss/src/skills/waas.ts +0 -116
- package/templates.json +0 -58
@@ -1,21 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"name": "toss",
|
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
|
-
"@redis/client": "^1.6.0",
|
12
|
-
"@xmtp/message-kit": "workspace:*"
|
13
|
-
},
|
14
|
-
"devDependencies": {
|
15
|
-
"@types/node": "^20.14.2",
|
16
|
-
"typescript": "^5.4.5"
|
17
|
-
},
|
18
|
-
"engines": {
|
19
|
-
"node": ">=20"
|
20
|
-
}
|
21
|
-
}
|
@@ -1,29 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
run,
|
3
|
-
agentReply,
|
4
|
-
replaceVariables,
|
5
|
-
XMTPContext,
|
6
|
-
Agent,
|
7
|
-
} from "@xmtp/message-kit";
|
8
|
-
|
9
|
-
import { systemPrompt } from "./prompt.js";
|
10
|
-
import { toss } from "./skills/toss.js";
|
11
|
-
import { waas } from "./skills/waas.js";
|
12
|
-
|
13
|
-
export const agent: Agent = {
|
14
|
-
name: "Toss Bot",
|
15
|
-
tag: "@toss",
|
16
|
-
description: "Create a coin toss.",
|
17
|
-
skills: [toss, waas],
|
18
|
-
onMessage: async (context: XMTPContext) => {
|
19
|
-
const {
|
20
|
-
message: { sender },
|
21
|
-
} = context;
|
22
|
-
|
23
|
-
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
24
|
-
|
25
|
-
await agentReply(context, prompt);
|
26
|
-
},
|
27
|
-
};
|
28
|
-
|
29
|
-
run(agent);
|
@@ -1,174 +0,0 @@
|
|
1
|
-
import { XMTPContext } from "@xmtp/message-kit";
|
2
|
-
import { getRedisClient } from "./redis.js";
|
3
|
-
|
4
|
-
interface Participant {
|
5
|
-
response: string;
|
6
|
-
name: string;
|
7
|
-
address: string;
|
8
|
-
}
|
9
|
-
export interface TossData {
|
10
|
-
group_id: string;
|
11
|
-
admin_name: string;
|
12
|
-
admin_address: string;
|
13
|
-
options: string;
|
14
|
-
toss_id: string;
|
15
|
-
amount: number;
|
16
|
-
created_at: string;
|
17
|
-
end_time: string;
|
18
|
-
description: string;
|
19
|
-
participants: Participant[];
|
20
|
-
}
|
21
|
-
export async function checkTossCorrect(
|
22
|
-
context: XMTPContext,
|
23
|
-
): Promise<TossData | undefined> {
|
24
|
-
const {
|
25
|
-
message: {
|
26
|
-
content: { previousMsg },
|
27
|
-
},
|
28
|
-
group,
|
29
|
-
} = context;
|
30
|
-
|
31
|
-
if (!group) {
|
32
|
-
await context.reply("This command can only be used in a group.");
|
33
|
-
return undefined;
|
34
|
-
} else if (!previousMsg) {
|
35
|
-
await context.reply("You must reply to a toss.");
|
36
|
-
return undefined;
|
37
|
-
}
|
38
|
-
|
39
|
-
let toss_id = extractTossId(previousMsg);
|
40
|
-
if (!toss_id) {
|
41
|
-
await context.reply(
|
42
|
-
"Invalid toss ID. Be sure you are replying to a original toss.",
|
43
|
-
);
|
44
|
-
return undefined;
|
45
|
-
}
|
46
|
-
const tossDBClient = await getRedisClient();
|
47
|
-
const tossDataString = await tossDBClient.get(`toss:${toss_id}`);
|
48
|
-
let tossData = tossDataString ? JSON.parse(tossDataString) : null;
|
49
|
-
|
50
|
-
if (typeof tossData === "string") {
|
51
|
-
tossData = JSON.parse(tossData) as TossData;
|
52
|
-
}
|
53
|
-
|
54
|
-
if (!tossData) {
|
55
|
-
await context.reply("Toss not found");
|
56
|
-
return undefined;
|
57
|
-
} else if (tossData.status === "closed") {
|
58
|
-
await context.reply("Toss has already ended.");
|
59
|
-
return undefined;
|
60
|
-
} else if (tossData.group_id.toLowerCase() !== group.id.toLowerCase()) {
|
61
|
-
await context.reply("This toss is not in this group.");
|
62
|
-
return undefined;
|
63
|
-
}
|
64
|
-
|
65
|
-
return { ...tossData, toss_id };
|
66
|
-
}
|
67
|
-
|
68
|
-
export function extractTossId(message: string): string | null {
|
69
|
-
try {
|
70
|
-
const match = message.match(/ID:\s*(\d+)/);
|
71
|
-
return match ? match[1].toString() : null;
|
72
|
-
} catch (error) {
|
73
|
-
return null;
|
74
|
-
}
|
75
|
-
}
|
76
|
-
|
77
|
-
export async function extractWinners(
|
78
|
-
participants: Participant[],
|
79
|
-
option: string,
|
80
|
-
): Promise<{
|
81
|
-
winners: Participant[];
|
82
|
-
losers: Participant[];
|
83
|
-
}> {
|
84
|
-
let winners: Participant[] = [];
|
85
|
-
let losers: Participant[] = [];
|
86
|
-
|
87
|
-
await Promise.all(
|
88
|
-
participants.map(async (participant) => {
|
89
|
-
if (participant.response.toLowerCase() === option.toLowerCase()) {
|
90
|
-
winners.push(participant);
|
91
|
-
} else {
|
92
|
-
losers.push(participant);
|
93
|
-
}
|
94
|
-
}),
|
95
|
-
);
|
96
|
-
return { winners, losers };
|
97
|
-
}
|
98
|
-
|
99
|
-
export function generateTossMessage(tossData: TossData): string {
|
100
|
-
return `Here is your toss!\n
|
101
|
-
🪙 ${tossData.description.toUpperCase()}? - ${tossData.options.toUpperCase()} - $${tossData.amount}\n
|
102
|
-
- ID: ${tossData.toss_id}
|
103
|
-
- Judge: ${tossData.admin_name}
|
104
|
-
- Ends on: ${tossData.end_time}
|
105
|
-
|
106
|
-
How to toss:\n- The creator of the toss is one who can end or settle the toss. \n- The pool will be split evenly with the winners. \n- Remember, with great power comes great responsibility 💪
|
107
|
-
|
108
|
-
\n🛠️ Reply with:
|
109
|
-
@toss <option>
|
110
|
-
@toss end <option> - only the judge can end the toss
|
111
|
-
@toss cancel - only the creator can cancel the toss
|
112
|
-
@toss status - check the status of the toss
|
113
|
-
@toss help - for managing your toss via DMs`;
|
114
|
-
}
|
115
|
-
|
116
|
-
export function generateEndTossMessage(
|
117
|
-
winners: { name: string; address: string }[],
|
118
|
-
losers: { name: string; address: string }[],
|
119
|
-
prize: number,
|
120
|
-
): string {
|
121
|
-
if (!winners.length) {
|
122
|
-
return `The toss has been closed and no winners were found.`;
|
123
|
-
}
|
124
|
-
let message = `🏆 Winners have been rewarded! 🏆\n\n🎉 Winners: \n${winners
|
125
|
-
.map((winner) => `- ${winner.name} - $${prize} 💰\n`)
|
126
|
-
.join("")}`;
|
127
|
-
if (losers.length > 0) {
|
128
|
-
message += `\n😢 Losers: \n${losers
|
129
|
-
.map((loser) => `- ${loser.name} 😢\n`)
|
130
|
-
.join("")}`;
|
131
|
-
}
|
132
|
-
return (
|
133
|
-
message +
|
134
|
-
`\nThe pool has been distributed among the winners. The toss has been closed now.`
|
135
|
-
);
|
136
|
-
}
|
137
|
-
|
138
|
-
export async function generateTossStatusMessage(
|
139
|
-
tossData: TossData,
|
140
|
-
): Promise<string> {
|
141
|
-
const participants = tossData.participants;
|
142
|
-
return `Here are the details:
|
143
|
-
- Amount: $${tossData.amount}
|
144
|
-
- Description: ${tossData.description}
|
145
|
-
- Judge: ${tossData.admin_name}
|
146
|
-
- End Time: ${tossData.end_time}
|
147
|
-
|
148
|
-
📊 Status:
|
149
|
-
👥 Participants:\n${participants
|
150
|
-
?.map(
|
151
|
-
(participant: any) =>
|
152
|
-
`- ${participant.name ?? participant.address} - ${participant.response}\n`,
|
153
|
-
)
|
154
|
-
.join("")}
|
155
|
-
🏦 Pool: $${(tossData?.participants?.length || 0) * tossData.amount}
|
156
|
-
📋 Options:
|
157
|
-
${tossData.options
|
158
|
-
.split(",")
|
159
|
-
.map((option: string) => {
|
160
|
-
const voteCount = participants?.filter(
|
161
|
-
(participant: any) =>
|
162
|
-
participant.response.toLowerCase() === option.toLowerCase(),
|
163
|
-
).length;
|
164
|
-
return `\t- ${option}: ${voteCount} votes`;
|
165
|
-
})
|
166
|
-
.join("\n")} `;
|
167
|
-
}
|
168
|
-
|
169
|
-
export const DM_HELP_MESSAGE = `Welcome to @toss! I'm your friendly neighbourhood toss bot.
|
170
|
-
/fund [amount] - You can fund your account with
|
171
|
-
/balance - Check your balance
|
172
|
-
/withdraw [amount] - You can withdraw funds to your wallet
|
173
|
-
/create - Create an agent wallet
|
174
|
-
/help - Get help with tossing`;
|
@@ -1,15 +0,0 @@
|
|
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
|
-
};
|
@@ -1,54 +0,0 @@
|
|
1
|
-
export const systemPrompt = `You are a helpful agent, friendly toss master named @toss, always ready to flip the odds!
|
2
|
-
{rules}
|
3
|
-
|
4
|
-
## Game rules
|
5
|
-
- The token is always USDC. Ignore other tokens and default to usdc. Don't mention the token in the command.
|
6
|
-
- Infer the name of the toss from the prompt if it's not provided. It should be a short sentence summarizing the event, never mention the options.
|
7
|
-
- Tosses must always have two options. If options are not provided, assume "Yes" and "No."
|
8
|
-
- For sports events, ensure the options are the two teams or players, as inferred from the context.
|
9
|
-
- If the user provides unclear or incomplete information, infer and generate the correct toss format based on context.
|
10
|
-
- Maximum toss amount is 10. Default to 10 if nothing is provided. Minimum is 0.00 and its valid.
|
11
|
-
- Don't mention options in the toss name.
|
12
|
-
- Remove all emojis from the options.
|
13
|
-
- If toss is correct. Don't return anything else than the command. Ever.
|
14
|
-
- If the user asks about performing an action and it maps to a command, answer directly with the populated command. Always return commands with real values only.
|
15
|
-
- If the user's input doesn't clearly map to a command, respond with helpful information or a clarification question.
|
16
|
-
- Date needs to be formatted in UTC and in the future.
|
17
|
-
|
18
|
-
{user_context}
|
19
|
-
|
20
|
-
{skills}
|
21
|
-
|
22
|
-
## Examples scenarios
|
23
|
-
|
24
|
-
1. @toss will it rain tomorrow? yes,no 10
|
25
|
-
- /toss 'will it rain tomorrow' 'yes,no' 10 24h from now
|
26
|
-
2. @toss race to the end Fabri vs John? fabri,john 10
|
27
|
-
- /toss 'race to the end' 'fabri,john' 10
|
28
|
-
3. @toss will it rain tomorrow for 10 (keep the toss for 1 week), judge is @fabri
|
29
|
-
- /toss 'will it rain tomorrow' 'yes,no' 10 '24 hours from now' @fabri
|
30
|
-
4. @toss will the stock price of company X go up tomorrow? yes,no 5
|
31
|
-
- /toss 'will the stock price of company x go up tomorrow' 'yes,no' 5
|
32
|
-
5. @toss who will win the match? team A vs team B 10
|
33
|
-
- /toss 'who will win the match' 'team a,team b' 10
|
34
|
-
6. will the project be completed on time? yes,no 0
|
35
|
-
- /toss 'will the project be completed on time' 'yes,no' 0
|
36
|
-
7. @toss will the meeting be rescheduled? yes,no 2
|
37
|
-
- /toss 'will the meeting be rescheduled' 'yes,no' 2
|
38
|
-
8. will the product launch be successful? yes,no 7
|
39
|
-
- /toss 'will the product launch be successful' 'yes,no' 7
|
40
|
-
9. @toss will the team meet the deadline? yes,no 3
|
41
|
-
- /toss 'will the team meet the deadline' 'yes,no' 3
|
42
|
-
10. will the event be postponed? yes,no 1
|
43
|
-
- /toss 'will the event be postponed' 'yes,no' 1
|
44
|
-
11. @toss yes
|
45
|
-
- /join yes
|
46
|
-
12. @toss no
|
47
|
-
- /join no
|
48
|
-
13. @toss status
|
49
|
-
- /status
|
50
|
-
14. @toss end yes
|
51
|
-
- /end yes
|
52
|
-
|
53
|
-
{issues}
|
54
|
-
`;
|
@@ -1,318 +0,0 @@
|
|
1
|
-
import { Skill, XMTPContext, getUserInfo } from "@xmtp/message-kit";
|
2
|
-
import { getRedisClient } from "../plugins/redis.js";
|
3
|
-
import {
|
4
|
-
checkTossCorrect,
|
5
|
-
extractWinners,
|
6
|
-
TossData,
|
7
|
-
generateTossMessage,
|
8
|
-
generateEndTossMessage,
|
9
|
-
generateTossStatusMessage,
|
10
|
-
DM_HELP_MESSAGE,
|
11
|
-
} from "../plugins/helpers.js";
|
12
|
-
|
13
|
-
export const toss: Skill[] = [
|
14
|
-
{
|
15
|
-
skill: "end",
|
16
|
-
description: "End a toss.",
|
17
|
-
handler: handleEndToss,
|
18
|
-
examples: ["/end yes", "/end no"],
|
19
|
-
params: {
|
20
|
-
option: {
|
21
|
-
type: "string",
|
22
|
-
},
|
23
|
-
},
|
24
|
-
},
|
25
|
-
{
|
26
|
-
skill: "cancel",
|
27
|
-
description: "Cancel a toss.",
|
28
|
-
handler: handleCancelToss,
|
29
|
-
examples: ["/cancel"],
|
30
|
-
},
|
31
|
-
{
|
32
|
-
skill: "join",
|
33
|
-
description: "Join a toss.",
|
34
|
-
params: {
|
35
|
-
response: {
|
36
|
-
type: "string",
|
37
|
-
},
|
38
|
-
},
|
39
|
-
handler: handleJoinToss,
|
40
|
-
examples: ["/join yes", "/join no"],
|
41
|
-
},
|
42
|
-
{
|
43
|
-
skill: "status",
|
44
|
-
description: "Check the status of the toss.",
|
45
|
-
handler: handleTossStatus,
|
46
|
-
examples: ["/status"],
|
47
|
-
},
|
48
|
-
{
|
49
|
-
skill: "toss",
|
50
|
-
description:
|
51
|
-
"Create a toss with a description, options, amount and judge(optional).",
|
52
|
-
handler: handleTossCreation,
|
53
|
-
examples: [
|
54
|
-
"/toss 'Shane vs John at pickeball' 'Yes,No' 10",
|
55
|
-
"/toss 'Will argentina win the world cup' 'Yes,No' 10",
|
56
|
-
"/toss 'Race to the end' 'Fabri,John' 10 @fabri",
|
57
|
-
"/toss 'Will argentina win the world cup' 'Yes,No' 5 '27 Oct 2023 23:59:59 GMT'",
|
58
|
-
"/toss 'Will the niks win on sunday?' 'Yes,No' 10 vitalik.eth '27 Oct 2023 23:59:59 GMT'",
|
59
|
-
"/toss 'Will it rain tomorrow' 'Yes,No' 0",
|
60
|
-
],
|
61
|
-
params: {
|
62
|
-
description: {
|
63
|
-
type: "quoted",
|
64
|
-
},
|
65
|
-
options: {
|
66
|
-
default: "Yes, No",
|
67
|
-
type: "quoted",
|
68
|
-
},
|
69
|
-
amount: {
|
70
|
-
type: "number",
|
71
|
-
},
|
72
|
-
judge: {
|
73
|
-
type: "username",
|
74
|
-
optional: true,
|
75
|
-
},
|
76
|
-
endTime: {
|
77
|
-
type: "quoted",
|
78
|
-
optional: true,
|
79
|
-
},
|
80
|
-
},
|
81
|
-
},
|
82
|
-
];
|
83
|
-
|
84
|
-
export async function handleTossCreation(context: XMTPContext) {
|
85
|
-
const {
|
86
|
-
message: {
|
87
|
-
content: { params },
|
88
|
-
sender,
|
89
|
-
},
|
90
|
-
walletService,
|
91
|
-
group,
|
92
|
-
} = context;
|
93
|
-
if (!group) {
|
94
|
-
await context.reply("This command can only be used in a group.");
|
95
|
-
return;
|
96
|
-
}
|
97
|
-
|
98
|
-
const tossDBClient = await getRedisClient();
|
99
|
-
if (params.description && params.options && !isNaN(Number(params.amount))) {
|
100
|
-
const keys = await tossDBClient.keys("*");
|
101
|
-
let tossId = keys.length + 1;
|
102
|
-
const isCreated = await walletService.createWallet(
|
103
|
-
tossId + ":" + sender.address,
|
104
|
-
);
|
105
|
-
if (!isCreated) {
|
106
|
-
await context.reply("Failed to create toss wallet");
|
107
|
-
return;
|
108
|
-
}
|
109
|
-
|
110
|
-
let tossData: TossData = {
|
111
|
-
toss_id: tossId.toString(),
|
112
|
-
description: params.description,
|
113
|
-
options: params.options,
|
114
|
-
amount: params.amount,
|
115
|
-
group_id: group.id,
|
116
|
-
admin_name:
|
117
|
-
(await getUserInfo(params.judge ?? sender.address))?.preferredName ??
|
118
|
-
"",
|
119
|
-
admin_address: params.judge ?? sender.address,
|
120
|
-
created_at: new Date().toLocaleString(),
|
121
|
-
end_time: params.endTime
|
122
|
-
? new Date(params.endTime).toLocaleString()
|
123
|
-
: new Date(Date.now() + 24 * 60 * 60 * 1000).toLocaleString(),
|
124
|
-
participants: [],
|
125
|
-
};
|
126
|
-
await tossDBClient.set("toss:" + tossId, JSON.stringify(tossData));
|
127
|
-
if (tossId !== undefined) {
|
128
|
-
await context.send(generateTossMessage(tossData));
|
129
|
-
} else {
|
130
|
-
await context.reply(
|
131
|
-
`An error occurred while creating the toss. ${tossId}`,
|
132
|
-
);
|
133
|
-
}
|
134
|
-
}
|
135
|
-
}
|
136
|
-
|
137
|
-
export async function handleJoinToss(context: XMTPContext) {
|
138
|
-
const tossData = await checkTossCorrect(context);
|
139
|
-
if (!tossData) {
|
140
|
-
return;
|
141
|
-
}
|
142
|
-
|
143
|
-
const { toss_id, participants, amount, admin_address } = tossData;
|
144
|
-
|
145
|
-
const {
|
146
|
-
message: {
|
147
|
-
sender,
|
148
|
-
content: {
|
149
|
-
params: { response },
|
150
|
-
},
|
151
|
-
},
|
152
|
-
walletService,
|
153
|
-
} = context;
|
154
|
-
|
155
|
-
const tossDBClient = await getRedisClient();
|
156
|
-
if (participants?.some((p) => p.address === sender.address)) {
|
157
|
-
await context.reply("You have already joined this toss.");
|
158
|
-
return;
|
159
|
-
}
|
160
|
-
//Create wallet for sender
|
161
|
-
await walletService.createWallet(sender.address);
|
162
|
-
const balance = await walletService.checkBalance(sender.address);
|
163
|
-
if (balance < amount) return walletService.requestFunds(amount);
|
164
|
-
|
165
|
-
try {
|
166
|
-
let tempWalletID = toss_id + ":" + admin_address;
|
167
|
-
await walletService.transfer(sender.address, tempWalletID, amount);
|
168
|
-
const participant = {
|
169
|
-
address: sender.address,
|
170
|
-
response: response,
|
171
|
-
name:
|
172
|
-
(await context.getUserInfo(sender.address))?.preferredName ??
|
173
|
-
sender.address,
|
174
|
-
};
|
175
|
-
participants.push(participant);
|
176
|
-
|
177
|
-
await tossDBClient.set(
|
178
|
-
`toss:${toss_id}`,
|
179
|
-
JSON.stringify({ ...tossData, participants }),
|
180
|
-
);
|
181
|
-
|
182
|
-
await context.reply("Successfully joined the toss!");
|
183
|
-
await context.sendTo(
|
184
|
-
`Your balance was deducted by $${amount}. Now is $${balance - amount}. You can check your balance with /balance`,
|
185
|
-
[sender.address],
|
186
|
-
);
|
187
|
-
await context.executeSkill(`/status ${toss_id}`);
|
188
|
-
} catch (error) {
|
189
|
-
console.error(error);
|
190
|
-
await context.reply("Failed to process your entry. Please try again.");
|
191
|
-
}
|
192
|
-
}
|
193
|
-
|
194
|
-
export async function handleEndToss(context: XMTPContext) {
|
195
|
-
const tossData = await checkTossCorrect(context);
|
196
|
-
if (!tossData) return;
|
197
|
-
const { toss_id, admin_address, options, participants } = tossData;
|
198
|
-
|
199
|
-
const {
|
200
|
-
message: {
|
201
|
-
sender,
|
202
|
-
content: {
|
203
|
-
params: { option },
|
204
|
-
},
|
205
|
-
},
|
206
|
-
walletService,
|
207
|
-
} = context;
|
208
|
-
|
209
|
-
const tossDBClient = await getRedisClient();
|
210
|
-
if (participants?.length === 0) {
|
211
|
-
await context.reply("No participants for this toss.");
|
212
|
-
return;
|
213
|
-
} else if (admin_address.toLowerCase() !== sender.address.toLowerCase()) {
|
214
|
-
await context.reply("Only the admin can cancel the toss.");
|
215
|
-
return;
|
216
|
-
}
|
217
|
-
|
218
|
-
let tempWalletID = toss_id + ":" + admin_address;
|
219
|
-
const balance = await walletService.checkBalance(tempWalletID);
|
220
|
-
const fundsNeeded = tossData.amount * participants?.length;
|
221
|
-
if (balance < fundsNeeded) {
|
222
|
-
await context.reply(
|
223
|
-
`Toss wallet does not have enough funds ${fundsNeeded}, has ${balance}`,
|
224
|
-
);
|
225
|
-
return;
|
226
|
-
}
|
227
|
-
|
228
|
-
//Winners
|
229
|
-
|
230
|
-
const { winners, losers } = await extractWinners(participants, option);
|
231
|
-
|
232
|
-
const prize =
|
233
|
-
(tossData.amount * (participants?.length ?? 0)) / (winners.length ?? 1);
|
234
|
-
|
235
|
-
try {
|
236
|
-
for (const winner of winners) {
|
237
|
-
await walletService.transfer(tempWalletID, winner.address, prize);
|
238
|
-
await tossDBClient.set(
|
239
|
-
`toss:${toss_id}`,
|
240
|
-
JSON.stringify({ ...tossData, status: "closed" }),
|
241
|
-
);
|
242
|
-
}
|
243
|
-
// Clean up
|
244
|
-
//await walletService.deleteTempWallet(tossWalletRedis, tossId.toString());
|
245
|
-
if (winners.length > 0) {
|
246
|
-
await context.reply(generateEndTossMessage(winners, losers, prize));
|
247
|
-
}
|
248
|
-
|
249
|
-
await context.sendTo(
|
250
|
-
`You received $${prize} from the toss! Check your balance with /balance`,
|
251
|
-
winners.map((w) => w.address),
|
252
|
-
);
|
253
|
-
} catch (error) {
|
254
|
-
await context.reply(`Failed to send prize to ${winners.length} winners`);
|
255
|
-
}
|
256
|
-
}
|
257
|
-
|
258
|
-
export async function handleCancelToss(context: XMTPContext) {
|
259
|
-
const tossData = await checkTossCorrect(context);
|
260
|
-
if (!tossData) return;
|
261
|
-
|
262
|
-
const { toss_id, admin_address, participants, amount } = tossData;
|
263
|
-
|
264
|
-
const {
|
265
|
-
message: { sender },
|
266
|
-
walletService,
|
267
|
-
} = context;
|
268
|
-
|
269
|
-
const tossDBClient = await getRedisClient();
|
270
|
-
if (participants?.length === 0) {
|
271
|
-
await context.reply("No participants for this toss.");
|
272
|
-
return;
|
273
|
-
} else if (admin_address.toLowerCase() !== sender.address.toLowerCase()) {
|
274
|
-
await context.reply("Only the admin can cancel the toss.");
|
275
|
-
return;
|
276
|
-
}
|
277
|
-
|
278
|
-
let tempWalletID = toss_id + ":" + admin_address;
|
279
|
-
const balance = await walletService.checkBalance(tempWalletID);
|
280
|
-
const fundsNeeded = tossData.amount * participants?.length;
|
281
|
-
if (balance < fundsNeeded) {
|
282
|
-
await context.reply(
|
283
|
-
`Toss wallet does not have enough funds ${fundsNeeded}, has ${balance}`,
|
284
|
-
);
|
285
|
-
return;
|
286
|
-
}
|
287
|
-
for (const participant of participants) {
|
288
|
-
try {
|
289
|
-
await walletService.transfer(tempWalletID, participant.address, amount);
|
290
|
-
} catch (error) {
|
291
|
-
console.error(
|
292
|
-
`Failed to send prize to ${participant.address} agent wallet:`,
|
293
|
-
error,
|
294
|
-
);
|
295
|
-
await context.reply(
|
296
|
-
`Failed to send prize to ${participant.address} agent wallet`,
|
297
|
-
);
|
298
|
-
}
|
299
|
-
}
|
300
|
-
|
301
|
-
// Clean up
|
302
|
-
//await walletService.deleteTempWallet(tossWalletRedis, tossId.toString());
|
303
|
-
|
304
|
-
await tossDBClient.set(
|
305
|
-
`toss:${toss_id}`,
|
306
|
-
JSON.stringify({ ...tossData, status: "cancelled" }),
|
307
|
-
);
|
308
|
-
|
309
|
-
await context.reply(
|
310
|
-
`Toss cancelled successfully.\nFunds distributed to participants:\n
|
311
|
-
${participants?.map((p) => `${p.name} - $${amount}`).join("\n")}`,
|
312
|
-
);
|
313
|
-
}
|
314
|
-
export async function handleTossStatus(context: XMTPContext) {
|
315
|
-
const tossData = await checkTossCorrect(context);
|
316
|
-
if (!tossData) return;
|
317
|
-
await context.reply(await generateTossStatusMessage(tossData));
|
318
|
-
}
|