Skip to content

Cash (USDC)

Check your balance, fund your wallet, and transfer USDC.

Check out the USDC plugin for more information.

src/skills/cash.ts
import { Context, baselinks } from "@xmtp/message-kit";
import type { Skill } from "@xmtp/message-kit";
import { USDCWallet } from "../plugins/usdc.js";
 
export const cash: Skill[] = [
  {
    skill: "balance",
    handler: balanceHandler,
    examples: ["/balance"],
    description: "Check your balance.",
  },
  {
    skill: "fund",
    handler: fundHandler,
    examples: ["/fund 1", "/fund 10"],
    params: {
      amount: {
        type: "number",
        default: "",
      },
    },
    description: "Fund your wallet. Returns a url to fund your wallet.",
  },
  {
    skill: "transfer",
    handler: transferHandler,
    examples: ["/transfer 0x40f08f0f853d1c42c61815652b7ccd5a50f0be09 1"],
    params: {
      address: {
        type: "address",
        default: "",
      },
      amount: {
        type: "number",
        default: "",
      },
    },
    description: "Transfer USDC to another address.",
  },
];
 
async function balanceHandler(context: Context) {
  const {
    message: { sender },
  } = context;
  const usdcWallet = new USDCWallet(sender.address);
  const { usdc } = await usdcWallet.checkBalances();
  await context.send({
    message: `Your balance is ${usdc} USDC. let me know if you want check again or to fund your wallet.`,
    originalMessage: context.message,
  });
}
 
async function fundHandler(context: Context) {
  try {
    const {
      message: {
        sender,
        content: {
          params: { amount },
        },
      },
    } = context;
    const usdcWallet = new USDCWallet(sender.address);
    const { usdc } = await usdcWallet.checkBalances();
    const MAX_USDC = 10;
 
    if (usdc >= MAX_USDC) {
      await context.send({
        message: `Your balance is maxed out at ${MAX_USDC} USDC.`,
        originalMessage: context.message,
      });
      return;
    }
 
    const remainingLimit = MAX_USDC - usdc;
    let fundAmount: number;
 
    if (!amount) {
      const options = Array.from(
        { length: Math.floor(remainingLimit) },
        (_, i) => (i + 1).toString(),
      );
      const response = await context.awaitResponse(
        `Please specify the amount of USDC to prefund (1 to ${remainingLimit}):`,
        options,
      );
      fundAmount = parseInt(response);
    } else {
      fundAmount = parseInt(amount);
    }
 
    if (isNaN(fundAmount) || fundAmount <= 0 || fundAmount > remainingLimit) {
      await context.send({
        message: `Invalid amount. Please specify a value between 1 and ${remainingLimit} USDC.`,
        originalMessage: context.message,
      });
      return;
    }
 
    const url = baselinks.paymentLink(usdcWallet.agentAddress, fundAmount);
    await context.send({ message: url, originalMessage: context.message });
    await context.send({
      message: "After funding, let me know so I can check your balance.",
      originalMessage: context.message,
    });
  } catch (error) {
    await context.send({
      message:
        "An error occurred while processing your request. Please try again.",
      originalMessage: context.message,
    });
  }
}
 
async function transferHandler(context: Context) {
  const {
    message: {
      sender,
      content: {
        params: { address, amount },
      },
    },
  } = context;
  const usdcWallet = new USDCWallet(sender.address);
  if (amount > 10) {
    await context.send({
      message: "You can only transfer up to 10 USDC at a time.",
      originalMessage: context.message,
    });
    return;
  }
  await usdcWallet.transferUsdc(address, amount);
}