Skip to main content
This example demonstrates how to create a custom SPL token on Solana for testing x402 payment flows. This is useful when you want to test with your own token instead of using USDC. Source: GitHub › scripts/solana-example/create-token.ts

Full Example

import "dotenv/config";
import { logger } from "../logger";
import { clusterApiUrl, Connection, Keypair, PublicKey } from "@solana/web3.js";
import fs from "fs";
import {
  createMint,
  getOrCreateAssociatedTokenAccount,
  mintTo,
} from "@solana/spl-token";

const { PAYER_KEYPAIR_PATH } = process.env;

if (!PAYER_KEYPAIR_PATH) {
  throw new Error("PAYER_KEYPAIR_PATH must be set in your environment");
}

const payer = Keypair.fromSecretKey(
  Uint8Array.from(JSON.parse(fs.readFileSync(PAYER_KEYPAIR_PATH, "utf-8"))),
);

const { PAYTO_KEYPAIR_PATH } = process.env;

if (!PAYTO_KEYPAIR_PATH) {
  throw new Error("PAYTO_KEYPAIR_PATH must be set in your environment");
}

const payTo = Keypair.fromSecretKey(
  Uint8Array.from(JSON.parse(fs.readFileSync(PAYTO_KEYPAIR_PATH, "utf-8"))),
);

const decimals = 6;

const network = "devnet";
const connection = new Connection(clusterApiUrl(network), "confirmed");

const mint = await createMint(
  connection,
  payer,
  payer.publicKey,
  payer.publicKey,
  decimals,
);

logger.info(`Created new test token: ${mint.toString()}`);

async function sendMint(publicKey: PublicKey, amountToMint: number) {
  const tokenAccount = await getOrCreateAssociatedTokenAccount(
    connection,
    payer,
    mint,
    publicKey,
  );

  await mintTo(
    connection,
    payer,
    mint,
    tokenAccount.address,
    payer.publicKey,
    amountToMint,
  );

  logger.info(
    `Minted ${amountToMint} tokens for ${publicKey.toString()} to ${tokenAccount.address.toString()}`,
  );
}

const amountToMint = 1000000 * Math.pow(10, decimals);

await sendMint(payer.publicKey, amountToMint);
await sendMint(payTo.publicKey, amountToMint);

Step-by-Step Breakdown

1. Load Keypairs

const payer = Keypair.fromSecretKey(
  Uint8Array.from(JSON.parse(fs.readFileSync(PAYER_KEYPAIR_PATH, "utf-8"))),
);
Load the payer keypair (who will create and mint the token) and the recipient keypair (who will receive the minted tokens).

2. Create the Token Mint

const mint = await createMint(
  connection,
  payer,
  payer.publicKey,  // mint authority
  payer.publicKey,  // freeze authority
  decimals,          // number of decimals
);
This creates a new SPL token mint with:
  • Mint authority: controls who can mint new tokens (set to payer)
  • Freeze authority: controls who can freeze token accounts (set to payer)
  • Decimals: precision for token amounts (6 decimals, same as USDC)

3. Mint Tokens to Accounts

async function sendMint(publicKey: PublicKey, amountToMint: number) {
  const tokenAccount = await getOrCreateAssociatedTokenAccount(
    connection,
    payer,
    mint,
    publicKey,
  );

  await mintTo(
    connection,
    payer,
    mint,
    tokenAccount.address,
    payer.publicKey,
    amountToMint,
  );
}
For each recipient:
  1. Get or create their associated token account for this mint
  2. Mint the specified amount of tokens to that account

4. Use Your Token in Payments

Once you have the mint address, you can use it in your payment handlers:
import { createPaymentHandler } from "@faremeter/payment-solana/exact";

const mint = new PublicKey("YourMintAddressHere");
const paymentHandler = createPaymentHandler(wallet, mint, connection);

Environment Variables

  • PAYER_KEYPAIR_PATH: Path to the keypair file that will create and mint the token
  • PAYTO_KEYPAIR_PATH: Path to the keypair file that will receive minted tokens