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-tokenReading 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_usdAPI Endpoints (If Available)
Token Information
bash
GET /api/token/:mintAddressResponse:
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/reflectionsResponse:
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/jackpotResponse:
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
- Solana Web3.js: https://solana-labs.github.io/solana-web3.js/
- SPL Token: https://spl.solana.com/token
- Anchor: https://www.anchor-lang.com/
Tools
- Solana Explorer: https://explorer.solana.com
- Solscan: https://solscan.io
- XRAY: https://xray.helius.xyz
Documentation
- Token-2022 Guide: https://spl.solana.com/token-2022
- Solana Cookbook: https://solanacookbook.com
- Anchor Book: https://book.anchor-lang.com
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)
