create-message-kit 1.2.23 → 1.2.25
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 +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
|
-
}
|