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.
Files changed (90) hide show
  1. package/index.js +19 -17
  2. package/package.json +1 -1
  3. package/templates/coinbase-agent/.cursorrules +290 -0
  4. package/templates/coinbase-agent/.env.example +4 -0
  5. package/templates/coinbase-agent/.yarnrc.yml +9 -0
  6. package/templates/coinbase-agent/package.json +22 -0
  7. package/templates/coinbase-agent/src/index.ts +31 -0
  8. package/templates/coinbase-agent/src/plugins/learnweb3.ts +96 -0
  9. package/templates/coinbase-agent/src/plugins/redis.ts +15 -0
  10. package/templates/coinbase-agent/src/prompt.ts +64 -0
  11. package/templates/coinbase-agent/src/skills/drip.ts +83 -0
  12. package/templates/coinbase-agent/src/skills/mint.ts +99 -0
  13. package/templates/coinbase-agent/src/skills/pay.ts +35 -0
  14. package/templates/coinbase-agent/src/skills/swap.ts +52 -0
  15. package/templates/ens/.env.example +1 -0
  16. package/templates/ens/.yarnrc.yml +5 -0
  17. package/templates/ens/src/index.ts +1 -1
  18. package/templates/ens/src/prompt.ts +1 -14
  19. package/templates/faucet/.cursorrules +290 -0
  20. package/templates/faucet/.env.example +5 -0
  21. package/templates/faucet/.yarnrc.yml +9 -0
  22. package/templates/faucet/package.json +22 -0
  23. package/templates/faucet/src/index.ts +39 -0
  24. package/templates/faucet/src/plugins/learnweb3.ts +96 -0
  25. package/templates/faucet/src/plugins/redis.ts +15 -0
  26. package/templates/faucet/src/prompt.ts +11 -0
  27. package/templates/faucet/src/skills/faucet.ts +140 -0
  28. package/templates/gated-group/.cursorrules +290 -0
  29. package/templates/gated-group/.env.example +3 -0
  30. package/templates/gated-group/.yarnrc.yml +9 -0
  31. package/templates/gated-group/package.json +23 -0
  32. package/templates/gated-group/src/index.ts +17 -0
  33. package/templates/gated-group/src/plugins/alchemy.ts +27 -0
  34. package/templates/gated-group/src/plugins/xmtp.ts +137 -0
  35. package/templates/gated-group/src/prompt.ts +11 -0
  36. package/templates/gated-group/src/skills/gated.ts +88 -0
  37. package/templates/gm/.cursorrules +290 -0
  38. package/templates/gm/.env.example +2 -0
  39. package/templates/gm/.yarnrc.yml +9 -0
  40. package/templates/gm/package.json +20 -0
  41. package/templates/gm/src/index.ts +8 -0
  42. package/templates/playground/.cursorrules +290 -0
  43. package/templates/playground/.env.example +6 -0
  44. package/templates/playground/.yarnrc.yml +9 -0
  45. package/templates/playground/package.json +26 -0
  46. package/templates/playground/src/index.ts +40 -0
  47. package/templates/playground/src/plugins/alchemy.ts +27 -0
  48. package/templates/playground/src/plugins/minilog.ts +26 -0
  49. package/templates/playground/src/plugins/usdc.ts +99 -0
  50. package/templates/playground/src/plugins/xmtp.ts +137 -0
  51. package/templates/playground/src/prompt.ts +11 -0
  52. package/templates/playground/src/skills/broadcast.ts +39 -0
  53. package/templates/playground/src/skills/cash.ts +122 -0
  54. package/templates/playground/src/skills/cryptoPrice.ts +63 -0
  55. package/templates/playground/src/skills/dalle.ts +61 -0
  56. package/templates/playground/src/skills/gated.ts +88 -0
  57. package/templates/playground/src/skills/search.ts +159 -0
  58. package/templates/playground/src/skills/todo.ts +79 -0
  59. package/templates/playground/src/skills/token.ts +57 -0
  60. package/templates/playground/src/skills/web.ts +83 -0
  61. package/templates/playground/src/skills/wordle.ts +96 -0
  62. package/templates/simple/.env.example +1 -0
  63. package/templates/simple/.yarnrc.yml +5 -0
  64. package/templates/simple/src/index.ts +1 -1
  65. package/templates/simple/src/prompt.ts +2 -0
  66. package/templates/thegeneralstore/.cursorrules +290 -0
  67. package/templates/thegeneralstore/.env.example +9 -0
  68. package/templates/thegeneralstore/.yarnrc.yml +9 -0
  69. package/templates/thegeneralstore/package.json +24 -0
  70. package/templates/thegeneralstore/src/data/db.json +812 -0
  71. package/templates/thegeneralstore/src/index.ts +37 -0
  72. package/templates/thegeneralstore/src/plugins/learnweb3.ts +96 -0
  73. package/templates/thegeneralstore/src/plugins/lowdb.ts +11 -0
  74. package/templates/thegeneralstore/src/plugins/notion.ts +89 -0
  75. package/templates/thegeneralstore/src/plugins/redis.ts +15 -0
  76. package/templates/thegeneralstore/src/prompt.md +51 -0
  77. package/templates/thegeneralstore/src/prompt.ts +3 -0
  78. package/templates/thegeneralstore/src/skills/faucet.ts +114 -0
  79. package/templates/thegeneralstore/src/skills/notion.ts +17 -0
  80. package/templates/thegeneralstore/src/skills/poap.ts +48 -0
  81. package/templates/thegeneralstore/src/skills.ts +37 -0
  82. package/templates/toss/.cursorrules +290 -0
  83. package/templates/toss/.env.example +7 -0
  84. package/templates/toss/.yarnrc.yml +9 -0
  85. package/templates/toss/package.json +21 -0
  86. package/templates/toss/src/index.ts +33 -0
  87. package/templates/toss/src/plugins/helpers.ts +185 -0
  88. package/templates/toss/src/plugins/redis.ts +78 -0
  89. package/templates/toss/src/prompt.ts +54 -0
  90. package/templates/toss/src/skills/toss.ts +489 -0
@@ -0,0 +1,489 @@
1
+ import { Skill, XMTPContext, getUserInfo } from "@xmtp/message-kit";
2
+ import { TimeoutError } from "@coinbase/coinbase-sdk";
3
+ import { getRedisClient } from "../plugins/redis.js";
4
+ import {
5
+ checkTossCorrect,
6
+ extractWinners,
7
+ TossData,
8
+ generateTossMessage,
9
+ generateEndTossMessage,
10
+ generateTossStatusMessage,
11
+ DM_HELP_MESSAGE,
12
+ } from "../plugins/helpers.js";
13
+
14
+ const tossDBClient = await getRedisClient();
15
+
16
+ export const toss: Skill[] = [
17
+ {
18
+ skill: "/end [option]",
19
+ description: "End a toss.",
20
+ handler: handleEndToss,
21
+ examples: ["/end yes", "/end no"],
22
+ params: {
23
+ option: {
24
+ type: "string",
25
+ },
26
+ },
27
+ },
28
+ {
29
+ skill: "/create",
30
+ description: "Create an agent wallet.",
31
+ handler: handleDM,
32
+ examples: ["/create"],
33
+ params: {},
34
+ },
35
+ {
36
+ skill: "/fund [amount]",
37
+ description: "Fund your account.",
38
+ handler: handleDM,
39
+ examples: ["/fund 10"],
40
+ params: {
41
+ amount: {
42
+ type: "number",
43
+ },
44
+ },
45
+ },
46
+ {
47
+ skill: "/withdraw [amount]",
48
+ description: "Withdraw funds from your account.",
49
+ handler: handleDM,
50
+ examples: ["/withdraw 10"],
51
+ params: {
52
+ amount: {
53
+ type: "number",
54
+ },
55
+ },
56
+ },
57
+ {
58
+ skill: "/help",
59
+ description: "Get help with tossing.",
60
+ handler: handleDM,
61
+ examples: ["/help"],
62
+ params: {},
63
+ },
64
+ {
65
+ skill: "/cancel",
66
+ description: "Cancel a toss.",
67
+ handler: handleCancelToss,
68
+ examples: ["/cancel"],
69
+ params: {},
70
+ },
71
+ {
72
+ skill: "/balance",
73
+ description: "Check your balance.",
74
+ handler: handleDM,
75
+ examples: ["/balance"],
76
+ params: {},
77
+ },
78
+ {
79
+ skill: "/join [response]",
80
+ description: "Join a toss.",
81
+ params: {
82
+ response: {
83
+ type: "string",
84
+ },
85
+ },
86
+ handler: handleJoinToss,
87
+ examples: ["/join yes", "/join no"],
88
+ },
89
+ {
90
+ skill: "/status",
91
+ description: "Check the status of the toss.",
92
+ handler: handleTossStatus,
93
+ examples: ["/status"],
94
+ params: {},
95
+ },
96
+ {
97
+ skill:
98
+ "/toss [description] [options (separated by comma)] [amount] [judge(optional)] [endTime(optional)]",
99
+ description:
100
+ "Create a toss with a description, options, amount and judge(optional).",
101
+ handler: handleTossCreation,
102
+ examples: [
103
+ "/toss 'Shane vs John at pickeball' 'Yes,No' 10",
104
+ "/toss 'Will argentina win the world cup' 'Yes,No' 10",
105
+ "/toss 'Race to the end' 'Fabri,John' 10 @fabri",
106
+ "/toss 'Will argentina win the world cup' 'Yes,No' 5 '27 Oct 2023 23:59:59 GMT'",
107
+ "/toss 'Will the niks win on sunday?' 'Yes,No' 10 vitalik.eth '27 Oct 2023 23:59:59 GMT'",
108
+ "/toss 'Will it rain tomorrow' 'Yes,No' 0",
109
+ ],
110
+ params: {
111
+ description: {
112
+ type: "quoted",
113
+ },
114
+ options: {
115
+ default: "Yes, No",
116
+ type: "quoted",
117
+ },
118
+ amount: {
119
+ type: "number",
120
+ },
121
+ judge: {
122
+ type: "username",
123
+ },
124
+ endTime: {
125
+ type: "quoted",
126
+ },
127
+ },
128
+ },
129
+ ];
130
+
131
+ export async function handleTossCreation(context: XMTPContext) {
132
+ const {
133
+ message: {
134
+ content: { params },
135
+ sender,
136
+ },
137
+ walletService,
138
+ group,
139
+ } = context;
140
+ if (!group) {
141
+ await context.reply("This command can only be used in a group.");
142
+ return;
143
+ }
144
+
145
+ if (params.description && params.options && !isNaN(Number(params.amount))) {
146
+ const keys = await tossDBClient.keys("*");
147
+ let tossId = keys.length + 1;
148
+ const createdTossWallet = await walletService.createTempWallet(
149
+ tossId.toString(),
150
+ );
151
+
152
+ let tossData: TossData = {
153
+ toss_id: tossId.toString(),
154
+ description: params.description,
155
+ options: params.options,
156
+ amount: params.amount,
157
+ group_id: group.id,
158
+ admin_name:
159
+ (await getUserInfo(params.judge ?? sender.address))?.preferredName ??
160
+ "",
161
+ admin_address: params.judge ?? sender.address,
162
+ created_at: new Date().toLocaleString(),
163
+ end_time: params.endTime
164
+ ? new Date(params.endTime).toLocaleString()
165
+ : new Date(Date.now() + 24 * 60 * 60 * 1000).toLocaleString(),
166
+ encrypted_participants: [],
167
+ participants: [],
168
+ toss_wallet_address: createdTossWallet?.address,
169
+ };
170
+ await tossDBClient.set(
171
+ "toss:" + walletService.encrypt(tossId.toString()),
172
+ walletService.encrypt(tossData),
173
+ );
174
+
175
+ if (tossId !== undefined) {
176
+ await context.send(generateTossMessage(tossData));
177
+ } else {
178
+ await context.reply(
179
+ `An error occurred while creating the toss. ${JSON.stringify(tossId)}`,
180
+ );
181
+ }
182
+ }
183
+ }
184
+
185
+ export async function handleJoinToss(context: XMTPContext) {
186
+ const tossData = await checkTossCorrect(context);
187
+ if (!tossData) {
188
+ return;
189
+ }
190
+
191
+ const { toss_id, participants, encrypted_participants, amount } = tossData;
192
+
193
+ const {
194
+ message: {
195
+ sender,
196
+ content: {
197
+ params: { response },
198
+ },
199
+ },
200
+ group,
201
+ walletService,
202
+ } = context;
203
+
204
+ if (participants?.some((p) => p.address === sender.address)) {
205
+ await context.reply("You have already joined this toss.");
206
+ return;
207
+ }
208
+
209
+ const tossWallet = await walletService.getTempWallet(toss_id);
210
+ if (!tossWallet) {
211
+ await context.reply("Toss wallet not found");
212
+ return;
213
+ }
214
+ const balance = await walletService.checkBalance(sender.address);
215
+
216
+ if (balance < amount) {
217
+ await context.send("You need to fund your account. Check your DMs:");
218
+ await walletService.requestFunds(context, amount);
219
+ return;
220
+ }
221
+
222
+ try {
223
+ const senderWallet = await walletService.getUserWallet(sender.address);
224
+ if (!senderWallet) {
225
+ await context.reply("Sender wallet not found");
226
+ return;
227
+ }
228
+ const transfer = await walletService.transfer(
229
+ senderWallet,
230
+ tossWallet,
231
+ amount,
232
+ );
233
+ console.log("Transfer:", transfer.getTransactionHash());
234
+ const encryptedParticipant = walletService.encrypt({
235
+ address: sender.address,
236
+ agent_address: senderWallet.address,
237
+ response: response,
238
+ name:
239
+ (await context.getUserInfo(sender.address))?.preferredName ??
240
+ sender.address,
241
+ });
242
+ encrypted_participants.push(encryptedParticipant as string);
243
+
244
+ await tossDBClient.set(
245
+ `toss:${walletService.encrypt(toss_id)}`,
246
+ walletService.encrypt(
247
+ JSON.stringify({ ...tossData, encrypted_participants }),
248
+ ),
249
+ );
250
+
251
+ await context.reply("Successfully joined the toss!");
252
+ await context.sendTo(
253
+ `Your balance was deducted by $${amount}. Now is $${balance - amount}. You can check your balance with /balance`,
254
+ [sender.address],
255
+ );
256
+ await context.executeSkill(`/status ${toss_id}`);
257
+ } catch (error) {
258
+ console.error(error);
259
+ await context.reply("Failed to process your entry. Please try again.");
260
+ }
261
+ }
262
+
263
+ export async function handleEndToss(context: XMTPContext) {
264
+ const tossData = await checkTossCorrect(context);
265
+ if (!tossData) return;
266
+ const { toss_id, admin_address, options, participants } = tossData;
267
+
268
+ const {
269
+ message: {
270
+ sender,
271
+ content: {
272
+ params: { option },
273
+ },
274
+ },
275
+ walletService,
276
+ } = context;
277
+
278
+ if (participants?.length === 0) {
279
+ await context.reply("No participants for this toss.");
280
+ return;
281
+ } else if (admin_address.toLowerCase() !== sender.address.toLowerCase()) {
282
+ await context.reply("Only the admin can end the toss.");
283
+ return;
284
+ } else if (
285
+ !options
286
+ .split(",")
287
+ .map((o) => o.toLowerCase())
288
+ .includes(option.toLowerCase())
289
+ ) {
290
+ await context.reply("Invalid option selected.");
291
+ return;
292
+ }
293
+ const { winners, losers } = await extractWinners(participants ?? [], option);
294
+
295
+ if (winners.length === 0) {
296
+ await context.reply("No winners for this toss.");
297
+ return;
298
+ }
299
+
300
+ const prize =
301
+ (tossData.amount * (participants?.length ?? 0)) / (winners.length ?? 1);
302
+
303
+ try {
304
+ for (const winner of winners) {
305
+ const tossWallet = await walletService.getTempWallet(toss_id);
306
+
307
+ if (!tossWallet) {
308
+ await context.reply("Toss wallet not found");
309
+ return;
310
+ }
311
+ const winnerWallet = await walletService.getUserWallet(
312
+ winner.address,
313
+ winner.address,
314
+ );
315
+ if (!winnerWallet) {
316
+ await context.reply("Winner wallet not found");
317
+ return;
318
+ }
319
+ const transfer = await walletService.transfer(
320
+ tossWallet,
321
+ winnerWallet,
322
+ prize,
323
+ );
324
+ console.log("Transfer:", transfer.getTransactionHash());
325
+ await tossDBClient.set(
326
+ `toss:${walletService.encrypt(toss_id)}`,
327
+ walletService.encrypt(
328
+ JSON.stringify({ ...tossData, status: "closed" }),
329
+ ),
330
+ );
331
+ }
332
+ // Clean up
333
+ //await walletService.deleteTempWallet(tossWalletRedis, tossId.toString());
334
+ if (winners.length > 0) {
335
+ await context.reply(generateEndTossMessage(winners, losers, prize));
336
+ }
337
+
338
+ await context.sendTo(
339
+ `You received $${prize} from the toss! Check your balance with /balance`,
340
+ winners.map((w) => w.address),
341
+ );
342
+ } catch (error) {
343
+ await context.reply(`Failed to send prize to ${winners.length} winners`);
344
+ }
345
+ }
346
+
347
+ export async function handleCancelToss(context: XMTPContext) {
348
+ const tossData = await checkTossCorrect(context);
349
+ if (!tossData) return;
350
+
351
+ const { toss_id, admin_address, participants, amount } = tossData;
352
+
353
+ const {
354
+ message: { sender },
355
+ walletService,
356
+ } = context;
357
+
358
+ if (participants?.length === 0) {
359
+ await context.reply("No participants for this toss.");
360
+ return;
361
+ } else if (admin_address.toLowerCase() !== sender.address.toLowerCase()) {
362
+ await context.reply("Only the admin can cancel the toss.");
363
+ return;
364
+ }
365
+
366
+ for (const participant of participants ?? []) {
367
+ try {
368
+ const tossWallet = await walletService.getTempWallet(toss_id);
369
+
370
+ if (!tossWallet) {
371
+ await context.reply("Toss wallet not found");
372
+ return;
373
+ }
374
+
375
+ const participantWallet = await walletService.getUserWallet(
376
+ participant.address,
377
+ );
378
+ if (!participantWallet) {
379
+ await context.reply("Participant wallet not found");
380
+ return;
381
+ }
382
+ const transfer = await walletService.transfer(
383
+ tossWallet,
384
+ participantWallet,
385
+ amount,
386
+ );
387
+ console.log("Transfer:", transfer.getTransactionHash());
388
+ } catch (error) {
389
+ console.error(`Failed to send prize to ${participant.address}:`, error);
390
+ await context.reply(`Failed to send prize to ${participant.address}`);
391
+ }
392
+ }
393
+
394
+ // Clean up
395
+ //await walletService.deleteTempWallet(tossWalletRedis, tossId.toString());
396
+
397
+ await tossDBClient.set(
398
+ `toss:${walletService.encrypt(toss_id)}`,
399
+ walletService.encrypt(JSON.stringify({ ...tossData, status: "cancelled" })),
400
+ );
401
+
402
+ await context.reply(
403
+ `Toss cancelled successfully.\nFunds distributed to participants:\n
404
+ ${participants?.map((p) => `${p.name} - $${amount}`).join("\n")}`,
405
+ );
406
+ }
407
+ export async function handleTossStatus(context: XMTPContext) {
408
+ const tossData = await checkTossCorrect(context);
409
+ if (!tossData) return;
410
+ await context.reply(await generateTossStatusMessage(tossData));
411
+ }
412
+
413
+ export async function handleDM(context: XMTPContext) {
414
+ const {
415
+ message: {
416
+ content: {
417
+ skill,
418
+ params: { amount },
419
+ },
420
+ sender,
421
+ },
422
+ group,
423
+ walletService,
424
+ } = context;
425
+ if (group && skill == "help") {
426
+ await context.reply("Check your DM's");
427
+ await context.sendTo(DM_HELP_MESSAGE, [sender.address]);
428
+ return;
429
+ }
430
+ if (skill === "help") {
431
+ await context.send(DM_HELP_MESSAGE);
432
+ } else if (skill === "create") {
433
+ const walletExist = await walletService.getUserWallet(sender.address);
434
+ if (walletExist) {
435
+ await context.reply("You already have an agent wallet.");
436
+ return;
437
+ }
438
+ const userWallet = await walletService.createUserWallet(sender.address);
439
+ await context.reply(
440
+ `Your agent wallet address is ${userWallet.address}\nBalance: $${await walletService.checkBalance(sender.address)}`,
441
+ );
442
+ } else if (skill === "balance") {
443
+ const userWallet = await walletService.getUserWallet(sender.address);
444
+
445
+ context.sendTo(
446
+ `Your agent wallet address is ${userWallet?.address}\nBalance: $${await walletService.checkBalance(sender.address)}`,
447
+ [sender.address],
448
+ );
449
+ } else if (skill === "fund") {
450
+ const balance = await walletService.checkBalance(sender.address);
451
+ if (balance === 10) {
452
+ await context.reply("You have maxed out your funds.");
453
+ return;
454
+ } else if (amount) {
455
+ if (amount + balance <= 10) {
456
+ await walletService.requestFunds(context, Number(amount));
457
+ return;
458
+ } else {
459
+ await context.send("Wrong amount. Max 10 USDC.");
460
+ return;
461
+ }
462
+ }
463
+ await context.reply(
464
+ `You have $${balance} in your account. You can fund up to $${10 - balance} more.`,
465
+ );
466
+ const options = Array.from({ length: Math.floor(10 - balance) }, (_, i) =>
467
+ (i + 1).toString(),
468
+ );
469
+ const response = await context.awaitResponse(
470
+ `Please specify the amount of USDC to prefund (1 to ${10 - balance}):`,
471
+ options,
472
+ );
473
+ await walletService.requestFunds(context, Number(response));
474
+ } else if (skill === "withdraw") {
475
+ const balance = await walletService.checkBalance(sender.address);
476
+ if (balance === 0) {
477
+ await context.reply("You have no funds to withdraw.");
478
+ return;
479
+ }
480
+ const options = Array.from({ length: Math.floor(balance) }, (_, i) =>
481
+ (i + 1).toString(),
482
+ );
483
+ const response = await context.awaitResponse(
484
+ `Please specify the amount of USDC to withdraw (1 to ${balance}):`,
485
+ options,
486
+ );
487
+ await walletService.withdrawFunds(sender.address, Number(response));
488
+ }
489
+ }