Group chat
This is a reference app that will allow you to understand the potential and all of its features. Through many handlers, you will be able to understand different use cases:
- AI: Reply with GPT when called by
/agent
. - Tipping: Tip when a user reacts with the
π©
emoji, replies10 $degen
and/tip
. - Betting: Create a new group inside a group with
/bet
- Games: Handle frame games like
/game slot
,/game wordle
- Transactions: Handle commands like
/send
,/swap
,/mint
,/show
. - Admin: Handle admin commands like
/add
,/remove
,/name
Structure
Check out the repository for the full code.
group/
βββ src/
β βββ index.ts # Index file of the app.
β βββ command.ts # For handling commands.
β βββ handler/
β βββ agent.ts # Handles gpt agent.
β βββ tipping.ts # Handles tipping.
β βββ betting.ts # Handles betting.
β βββ game.ts # Handles game frames.
β βββ admin.ts # Handles moderation.
β βββ payment.ts # Handles split payments.
β βββ transactions.ts # Handles the transaction frame.
β βββ lib/
β βββ openai.ts # Handles the openai logic.
βββ package.json
βββ tsconfig.json
βββ .env
Main code
src/index.ts
import { run, HandlerContext, CommandHandlers } from "@xmtp/message-kit";
import { commands } from "./commands.js";
import { handler as bet } from "./handler/betting.js";
import { handler as tipping } from "./handler/tipping.js";
import { handler as agent } from "./handler/agent.js";
import { handler as transaction } from "./handler/transaction.js";
import { handler as splitpayment } from "./handler/payment.js";
import { handler as games } from "./handler/game.js";
import { handler as admin } from "./handler/admin.js";
import { handler as loyalty } from "./handler/loyalty.js";
// Define command handlers
const commandHandlers: CommandHandlers = {
"/tip": tipping,
"/agent": agent,
"/bet": bet,
"/send": transaction,
"/swap": transaction,
"/mint": transaction,
"/show": transaction,
"/points": loyalty,
"/leaderboard": loyalty,
"/game": games,
"/add": admin,
"/remove": admin,
"/name": admin,
"/help": async (context: HandlerContext) => {
const intro =
"Available experiences:\n" +
commands
.flatMap((app) => app.commands)
.map((command) => `${command.command} - ${command.description}`)
.join("\n") +
"\nUse these commands to interact with specific apps.";
context.reply(intro);
},
"/apps": async (context: HandlerContext) => {
const intro =
"Decentralized secure messaging. Built for crypto.\n" +
"Welcome to the Apps Directory\n\n" +
"- π§ faucetbot.eth : Delivers Faucet funds to devs on Testnet\n\n\n" +
"- ποΈ thegeneralstore.eth : Simple ecommerce storefront for hackathon goods\n\n\n" +
"- π
Β wordlebot.eth : Play daily to the WORDLE game through messaging.\n\n\n" +
"- πͺ¨ urltomint.eth : Turn a Zora url into a mint frame.\n\n\n" +
"To learn how to build your own app, visit MessageKit: https://message-kit.vercel.app/\n\n" +
"To publish your app, visit Directory: https://message-kit.vercel.app/directory\n\n" +
"You are currently inside Message Kit Group Starter. You can type:\n/help command to see available commands\n/apps to trigger the directory.";
context.reply(intro);
},
};
// App configuration
const appConfig = {
commands: commands,
commandHandlers: commandHandlers,
};
// Main function to run the app
run(async (context: HandlerContext) => {
const {
message: { typeId },
} = context;
try {
switch (typeId) {
case "reaction":
handleReaction(context);
loyalty(context);
break;
case "reply":
handleReply(context);
break;
case "group_updated":
admin(context);
loyalty(context);
break;
case "remoteStaticAttachment":
handleAttachment(context);
break;
case "text":
handleTextMessage(context);
loyalty(context, true);
break;
default:
console.warn(`Unhandled message type: ${typeId}`);
}
} catch (error) {
console.error("Error handling message:", error);
}
}, appConfig);
// Handle reaction messages
async function handleReaction(context: HandlerContext) {
const {
content: { content: emoji, action },
} = context.message;
if (action === "added" && (emoji === "degen" || emoji === "π©")) {
await tipping(context);
}
}
// Handle reply messages
async function handleReply(context: HandlerContext) {
const {
content: { content: reply },
} = context.message;
if (reply.includes("degen")) {
await tipping(context);
}
}
// Handle attachment messages
async function handleAttachment(context: HandlerContext) {
await splitpayment(context);
}
// Handle text messages
async function handleTextMessage(context: HandlerContext) {
const {
content: { content: text },
} = context.message;
if (text.includes("@bot")) {
await agent(context);
} else if (text.startsWith("/")) {
await context.intent(text);
}
}
Run the app
Follow the steps below to run the app
Setup
cmd
# Clone the repo
git clone https://github.com/ephemeraHQ/message-kit
# Go to the examples/group folder
cd examples/group
# Install the dependencies
yarn install
# Run the app
yarn dev
Variables
Set up these variables in your app
cmd
KEY= # 0x... the private key of the bot wallet (with the 0x prefix)
OPEN_AI_API_KEY= # your openai api key
STACK_API_KEY= # stack api key
MSG_LOG= # true to log all messages