Skip to content

Developer Integration Guide

Date: 2025-01-12 Audience: Developers integrating MintCraft tokens Reading Time: 15 minutes


Overview

This guide covers how to integrate MintCraft tokens into your dApp, read token data, interact with features like reflections and jackpots, and use the Token-2022 standard.


Token-2022 SDK Basics

Installation

bash
npm install @solana/web3.js @solana/spl-token

Reading Token Info

typescript
import { Connection, PublicKey } from '@solana/web3.js';
import { getMint, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';

const connection = new Connection('https://api.mainnet-beta.solana.com');
const mintAddress = new PublicKey('YOUR_MINT_ADDRESS');

// Get mint info
const mintInfo = await getMint(
  connection,
  mintAddress,
  'confirmed',
  TOKEN_2022_PROGRAM_ID
);

console.log('Decimals:', mintInfo.decimals);
console.log('Supply:', mintInfo.supply.toString());
console.log('Mint Authority:', mintInfo.mintAuthority?.toString() || 'Revoked');

Reading Transfer Fee Config

typescript
import { getTransferFeeConfig, unpackAccount } from '@solana/spl-token';

// Get mint account data
const accountInfo = await connection.getAccountInfo(mintAddress);
const mint = unpackAccount(mintAddress, accountInfo, TOKEN_2022_PROGRAM_ID);

// Extract transfer fee config
const transferFeeConfig = getTransferFeeConfig(mint);

if (transferFeeConfig) {
  const { transferFeeBasisPoints, maximumFee } = 
    transferFeeConfig.newerTransferFee;
  
  console.log('Fee BPS:', transferFeeBasisPoints); // e.g., 250 = 2.5%
  console.log('Max Fee:', maximumFee.toString());
}

Checking Token Balance

typescript
import { getAssociatedTokenAddressSync, getAccount } from '@solana/spl-token';

const walletAddress = new PublicKey('WALLET_ADDRESS');

// Get ATA address
const ata = getAssociatedTokenAddressSync(
  mintAddress,
  walletAddress,
  false,
  TOKEN_2022_PROGRAM_ID
);

// Get account info
const accountInfo = await connection.getAccountInfo(ata);
const tokenAccount = unpackAccount(ata, accountInfo, TOKEN_2022_PROGRAM_ID);

console.log('Balance:', tokenAccount.amount.toString());

Reflection System Integration

Reading Reflection Config

typescript
import { PublicKey } from '@solana/web3.js';

const MINTCRAFT_PROGRAM_ID = new PublicKey(
  'Hbcw8A9kdqWHt1p5C6XY1864t4PjNWa8zaiysfZMqBn4'
);

// Derive reflection config PDA
function getReflectionConfigPDA(mint: PublicKey): PublicKey {
  const [pda] = PublicKey.findProgramAddressSync(
    [Buffer.from('reflection-config'), mint.toBuffer()],
    MINTCRAFT_PROGRAM_ID
  );
  return pda;
}

// Get reflection config
const reflectionConfigPDA = getReflectionConfigPDA(mintAddress);
const configAccount = await connection.getAccountInfo(reflectionConfigPDA);

if (configAccount) {
  // Parse account data (implement based on your needs)
  // First 8 bytes: discriminator
  // Next 32 bytes: authority
  // Next 32 bytes: mint
  // Next 32 bytes: reward_token_mint
  // Next 8 bytes: min_holding (u64)
  // Next 2 bytes: gas_rebate_bps (u16)
  
  console.log('Reflection config exists');
}

Checking Holder Eligibility

typescript
async function isEligibleForReflections(
  connection: Connection,
  mint: PublicKey,
  wallet: PublicKey,
  minHolderValueUsd: number,
  tokenPriceUsd: number
): Promise<boolean> {
  // Get token balance
  const ata = getAssociatedTokenAddressSync(
    mint,
    wallet,
    false,
    TOKEN_2022_PROGRAM_ID
  );
  
  const accountInfo = await connection.getAccountInfo(ata);
  if (!accountInfo) return false;
  
  const tokenAccount = unpackAccount(ata, accountInfo, TOKEN_2022_PROGRAM_ID);
  const balance = Number(tokenAccount.amount);
  
  // Get mint info for decimals
  const mintInfo = await getMint(connection, mint, 'confirmed', TOKEN_2022_PROGRAM_ID);
  const decimals = mintInfo.decimals;
  
  // Calculate USD value
  const tokenAmount = balance / Math.pow(10, decimals);
  const usdValue = tokenAmount * tokenPriceUsd;
  
  // Check minimum
  return usdValue >= minHolderValueUsd;
}

// Usage
const eligible = await isEligibleForReflections(
  connection,
  mintAddress,
  walletAddress,
  5, // $5 minimum
  0.0001 // $0.0001 per token
);

Claiming Stealth Reflections

typescript
import { Transaction } from '@solana/web3.js';

async function claimStealthReflections(
  wallet: PublicKey,
  mint: PublicKey,
  merkleProof: Buffer[],
  amount: bigint,
  index: number
): Promise<string> {
  const transaction = new Transaction();
  
  // Add claim instruction
  // (Implementation depends on your merkle tree structure)
  
  // Send transaction
  const signature = await connection.sendTransaction(transaction, [/* signers */]);
  await connection.confirmTransaction(signature);
  
  return signature;
}

Jackpot System Integration

Reading Jackpot Treasury Balance

typescript
function getJackpotTreasuryPDA(mint: PublicKey): PublicKey {
  const [pda] = PublicKey.findProgramAddressSync(
    [Buffer.from('jackpot-treasury'), mint.toBuffer()],
    MINTCRAFT_PROGRAM_ID
  );
  return pda;
}

async function getJackpotBalance(
  connection: Connection,
  mint: PublicKey
): Promise<bigint> {
  const jackpotPDA = getJackpotTreasuryPDA(mint);
  
  // Get jackpot treasury's token account
  const jackpotATA = getAssociatedTokenAddressSync(
    mint,
    jackpotPDA,
    true, // allowOwnerOffCurve (for PDAs)
    TOKEN_2022_PROGRAM_ID
  );
  
  const accountInfo = await connection.getAccountInfo(jackpotATA);
  if (!accountInfo) return BigInt(0);
  
  const tokenAccount = unpackAccount(jackpotATA, accountInfo, TOKEN_2022_PROGRAM_ID);
  return tokenAccount.amount;
}

// Usage
const jackpotBalance = await getJackpotBalance(connection, mintAddress);
console.log('Current jackpot:', jackpotBalance.toString());

Checking Drawing Time

typescript
async function getNextDrawingTime(
  connection: Connection,
  mint: PublicKey
): Promise<Date | null> {
  const jackpotConfigPDA = getJackpotTreasuryPDA(mint);
  const account = await connection.getAccountInfo(jackpotConfigPDA);
  
  if (!account) return null;
  
  // Parse last_drawing_time and drawing_frequency from account data
  // (Implementation depends on struct layout)
  
  const lastDrawing = 0; // Parse from data
  const frequency = 86400; // Parse from data (seconds)
  
  const nextDrawing = new Date((lastDrawing + frequency) * 1000);
  return nextDrawing;
}

Auto-LP Integration

Monitoring LP Growth

typescript
async function getAutoLPStats(
  connection: Connection,
  mint: PublicKey
): Promise<{
  treasuryBalance: bigint;
  totalInjected: bigint;
  lastInjection: Date | null;
}> {
  const autoLpPDA = PublicKey.findProgramAddressSync(
    [Buffer.from('autolp-treasury'), mint.toBuffer()],
    MINTCRAFT_PROGRAM_ID
  )[0];
  
  // Get treasury token balance
  const treasuryATA = getAssociatedTokenAddressSync(
    mint,
    autoLpPDA,
    true,
    TOKEN_2022_PROGRAM_ID
  );
  
  const accountInfo = await connection.getAccountInfo(treasuryATA);
  const tokenAccount = unpackAccount(treasuryATA, accountInfo, TOKEN_2022_PROGRAM_ID);
  
  return {
    treasuryBalance: tokenAccount.amount,
    totalInjected: BigInt(0), // Parse from config PDA
    lastInjection: null // Parse from config PDA
  };
}

Pool Integration

Getting Pool Information

typescript
// Meteora DAMM v2 pool interaction
import { PublicKey } from '@solana/web3.js';

async function getPoolInfo(
  connection: Connection,
  poolAddress: PublicKey
) {
  const accountInfo = await connection.getAccountInfo(poolAddress);
  
  if (!accountInfo) {
    throw new Error('Pool not found');
  }
  
  // Parse pool data based on Meteora DAMM v2 structure
  // (Use Meteora SDK for easier parsing)
  
  return {
    tokenAReserve: BigInt(0), // Parse from data
    tokenBReserve: BigInt(0), // Parse from data
    currentFee: 0, // Parse fee tier
    // ... other fields
  };
}

Getting Token Price from Pool

typescript
async function getTokenPriceFromPool(
  connection: Connection,
  poolAddress: PublicKey,
  tokenMint: PublicKey,
  quoteMint: PublicKey,
  decimals: number
): Promise<number> {
  // This is simplified - use actual Meteora SDK for production
  const poolInfo = await getPoolInfo(connection, poolAddress);
  
  // Calculate price based on reserves
  const tokenReserve = Number(poolInfo.tokenAReserve);
  const quoteReserve = Number(poolInfo.tokenBReserve);
  
  const price = quoteReserve / tokenReserve;
  return price;
}

React Integration Examples

Token Balance Hook

typescript
import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { useState, useEffect } from 'react';
import { PublicKey } from '@solana/web3.js';
import { getAssociatedTokenAddressSync, getAccount, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';

export function useTokenBalance(mintAddress: string) {
  const { connection } = useConnection();
  const { publicKey } = useWallet();
  const [balance, setBalance] = useState<number>(0);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!publicKey) {
      setBalance(0);
      setLoading(false);
      return;
    }

    const mint = new PublicKey(mintAddress);
    const ata = getAssociatedTokenAddressSync(
      mint,
      publicKey,
      false,
      TOKEN_2022_PROGRAM_ID
    );

    connection.getAccountInfo(ata).then(accountInfo => {
      if (accountInfo) {
        const account = unpackAccount(ata, accountInfo, TOKEN_2022_PROGRAM_ID);
        setBalance(Number(account.amount));
      }
      setLoading(false);
    });
  }, [connection, publicKey, mintAddress]);

  return { balance, loading };
}

Reflection Eligibility Hook

typescript
export function useReflectionEligibility(
  mintAddress: string,
  minValueUsd: number,
  priceUsd: number
) {
  const { balance, loading } = useTokenBalance(mintAddress);
  const [eligible, setEligible] = useState(false);

  useEffect(() => {
    if (loading) return;
    
    // Assume 9 decimals for calculation
    const tokenAmount = balance / 1e9;
    const usdValue = tokenAmount * priceUsd;
    
    setEligible(usdValue >= minValueUsd);
  }, [balance, loading, minValueUsd, priceUsd]);

  return eligible;
}

Python Integration

Basic Token Info

python
from solana.rpc.api import Client
from solders.pubkey import Pubkey
from spl.token.constants import TOKEN_2022_PROGRAM_ID

# Connect
client = Client("https://api.mainnet-beta.solana.com")

# Get mint info
mint = Pubkey.from_string("YOUR_MINT_ADDRESS")
response = client.get_account_info(mint)

if response.value:
    # Parse account data
    data = response.value.data
    # ... parse Token-2022 mint structure
    
    print(f"Supply: {supply}")
    print(f"Decimals: {decimals}")

Checking Holder Eligibility

python
def is_eligible_for_reflections(
    client: Client,
    mint: Pubkey,
    wallet: Pubkey,
    min_value_usd: float,
    price_usd: float
) -> bool:
    # Get ATA
    ata = get_associated_token_address(wallet, mint, TOKEN_2022_PROGRAM_ID)
    
    # Get balance
    response = client.get_token_account_balance(ata)
    if not response.value:
        return False
    
    balance = float(response.value.amount)
    decimals = response.value.decimals
    
    # Calculate USD value
    token_amount = balance / (10 ** decimals)
    usd_value = token_amount * price_usd
    
    return usd_value >= min_value_usd

API Endpoints (If Available)

Token Information

bash
GET /api/token/:mintAddress

Response:

json
{
  "mint": "ABC...123",
  "name": "My Token",
  "symbol": "MTK",
  "decimals": 9,
  "supply": "1000000000000000000",
  "transferFeeBps": 250,
  "features": {
    "reflections": true,
    "jackpot": true,
    "autoLp": true,
    "burn": true
  }
}

Reflection Status

bash
GET /api/token/:mintAddress/reflections

Response:

json
{
  "enabled": true,
  "mode": "stealth",
  "minHolderValueUsd": 5,
  "antiWhalePercent": 2,
  "lastDistribution": "2025-01-12T10:00:00Z",
  "nextDistribution": "2025-01-12T11:00:00Z"
}

Jackpot Status

bash
GET /api/token/:mintAddress/jackpot

Response:

json
{
  "enabled": true,
  "currentBalance": "500000000000000",
  "lastWinner": "7xUW...abc",
  "lastDrawing": "2025-01-11T12:00:00Z",
  "nextDrawing": "2025-01-12T12:00:00Z"
}

Best Practices

Error Handling

typescript
async function safeGetTokenBalance(
  connection: Connection,
  mint: PublicKey,
  wallet: PublicKey
): Promise<bigint | null> {
  try {
    const ata = getAssociatedTokenAddressSync(
      mint,
      wallet,
      false,
      TOKEN_2022_PROGRAM_ID
    );
    
    const accountInfo = await connection.getAccountInfo(ata);
    if (!accountInfo) return null;
    
    const tokenAccount = unpackAccount(ata, accountInfo, TOKEN_2022_PROGRAM_ID);
    return tokenAccount.amount;
  } catch (error) {
    console.error('Error getting token balance:', error);
    return null;
  }
}

Caching

typescript
import { LRUCache } from 'lru-cache';

const priceCache = new LRUCache<string, number>({
  max: 100,
  ttl: 60000 // 1 minute
});

async function getCachedTokenPrice(
  mint: string
): Promise<number> {
  const cached = priceCache.get(mint);
  if (cached !== undefined) return cached;
  
  const price = await fetchTokenPrice(mint);
  priceCache.set(mint, price);
  
  return price;
}

Rate Limiting

typescript
import pLimit from 'p-limit';

const limit = pLimit(5); // Max 5 concurrent requests

async function batchGetBalances(
  connection: Connection,
  mint: PublicKey,
  wallets: PublicKey[]
): Promise<Map<string, bigint>> {
  const results = await Promise.all(
    wallets.map(wallet =>
      limit(() => safeGetTokenBalance(connection, mint, wallet))
    )
  );
  
  const balanceMap = new Map();
  wallets.forEach((wallet, i) => {
    if (results[i] !== null) {
      balanceMap.set(wallet.toString(), results[i]);
    }
  });
  
  return balanceMap;
}

Testing

Unit Tests

typescript
import { describe, it, expect } from 'vitest';
import { Connection, PublicKey } from '@solana/web3.js';

describe('Token Integration', () => {
  const connection = new Connection('https://api.devnet.solana.com');
  const testMint = new PublicKey('YOUR_TEST_MINT');
  
  it('should read token info', async () => {
    const mintInfo = await getMint(
      connection,
      testMint,
      'confirmed',
      TOKEN_2022_PROGRAM_ID
    );
    
    expect(mintInfo.decimals).toBe(9);
    expect(mintInfo.supply).toBeGreaterThan(0n);
  });
  
  it('should check reflection eligibility', async () => {
    const wallet = new PublicKey('TEST_WALLET');
    const eligible = await isEligibleForReflections(
      connection,
      testMint,
      wallet,
      5, // $5 min
      0.0001 // $0.0001 price
    );
    
    expect(typeof eligible).toBe('boolean');
  });
});

Additional Resources

SDKs

Tools

Documentation


Next Steps

Integration Checklist:

  • [ ] Add Token-2022 support
  • [ ] Implement balance checking
  • [ ] Add reflection eligibility checks
  • [ ] Display jackpot information
  • [ ] Test on devnet
  • [ ] Deploy to production

Learn More:

  • Getting Started (01) → Platform overview
  • Token Creation (02) → How tokens are created
  • Managing Tokens (03) → Creator perspective
  • Security (07) → Best practices
  • Glossary (10) → Terms reference

Last Updated: 2025-01-12 Previous: FAQ (08) Next: Glossary (10)

The Best Pump.fun Alternative - Built on Solana Token-2022