Skip to content

Loyalty

Create incentives for users to interact with group chats.

Commands

Here are the commands to manage loyalty:

cmd
# Add a member
/points
 
# Check the leaderboard
/leaderboard

Main code

Incentives

In this example we used the following incentives:

  • 10 points for adding a member
  • 1 point for each reaction on a message
src/handler/loyalty.ts
import { HandlerContext, User } from "@xmtp/message-kit";
import { getStackClient, StackClient } from "../lib/stack.js";
 
export async function handler(context: HandlerContext) {
  const stack = getStackClient();
  const {
    members,
    getMessageById,
    message: { id, content, sender, typeId },
  } = context;
  if (typeId === "text") {
    const { command } = content;
    if (command === "points") {
      const points = await stack?.getPoints(sender.address);
      context.reply(`You have ${points} points`);
    } else if (command === "leaderboard") {
      const leaderboard = await stack?.getLeaderboard();
      const formattedLeaderboard = leaderboard?.leaderboard
        .map(
          (entry, index) =>
            `${index + 1}. Address: ${`${entry.address.slice(
              0,
              6,
            )}...${entry.address.slice(-4)}`}, Points: ${entry.points}`,
        )
        .join("\n");
      context.reply(
        `Leaderboard:\n\n${formattedLeaderboard}\n\nCheck out the public leaderboard\nhttps://www.stack.so/leaderboard/degen-group`,
      );
    }
  } else if (typeId === "group_updated") {
    const { initiatedByInboxId, addedInboxes } = content;
    const adminAddress = members?.find(
      (member: User) => member.inboxId === initiatedByInboxId,
    );
    if (addedInboxes && addedInboxes.length > 0) {
      //if add someone to the group
      await stack?.track("referral", {
        points: 10,
        account: adminAddress?.address ?? "",
        uniqueId: adminAddress?.username ?? "",
      });
    }
  } else if (typeId === "reaction") {
    const { content: emoji, action } = content;
    const msg = await getMessageById(content.reference);
    if (action === "added") {
      const adminAddress = members?.find(
        (member: User) => member.inboxId === msg?.senderInboxId,
      );
      let points = 1;
      if (emoji === "👎") {
        points = -10;
      } else if (emoji === "🎩") {
        points = 10;
      }
      await stack?.track("reaction", {
        points,
        account: adminAddress?.address ?? "",
        uniqueId: adminAddress?.username ?? "",
      });
    }
  }
}

Stack.so middleware

Connect to Stack.so for managing your loyalty program.

cmd
npm install @stackso/js-core

Add your API key to environment variables.

STACK_API_KEY= #your api key

Connect to Stack.so

src/lib/stack.ts
import { StackClient } from "@stackso/js-core";
 
let stack: StackClient | null = null;
 
export function getStackClient(): StackClient | null {
  if (!process?.env?.STACK_API_KEY) {
    console.log("No STACK_API_KEY found in .env");
    return null;
  }
  if (!stack) {
    stack = new StackClient({
      apiKey: process.env.STACK_API_KEY as string,
      pointSystemId: 2893,
    });
  }
  return stack;
}
export type { StackClient };