Skip to content

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, replies 10 $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