Official TypeScript/JavaScript SDK for the migrate.fun token migration protocol on Solana.
Production-ready SDK for seamless token migration integration in your Solana applications
- Complete claim support - MFT claims, merkle claims, and refund claims with eligibility detection
- Browser-safe - Works in Next.js, Vite, React Native, and vanilla JavaScript
- TypeScript-first - Full type safety with comprehensive JSDoc documentation
- Dual-format - ESM and CommonJS support for maximum compatibility
- Tree-shakable - Optimized bundle sizes with proper exports
- React hooks - Optional React adapter for idiomatic integration including unified
useProjectSessionanduseClaim - Network-agnostic - Support for devnet and mainnet-beta
- Built-in caching - Intelligent RPC request optimization
- Error handling - User-friendly error messages with recovery actions
The SDK is organized by feature for better maintainability and scalability:
src/
├── core/ # Core SDK primitives
│ ├── program.ts # IDL loading, Program instances, network resolution
│ ├── pdas.ts # PDA derivation functions
│ └── types.ts # Core types and interfaces
├── transactions/ # Transaction builders
│ └── builders.ts # All transaction building logic (migrate, claim, refund)
├── queries/ # Data fetching operations
│ ├── balances.ts # Balance fetching & watching
│ ├── eligibility.ts # Claim eligibility determination
│ └── projects.ts # Project discovery & user migration records
└── utils/ # Utility functions
├── calculations.ts # Token calculations, exchange rates, penalties
├── errors.ts # Error parsing and handling
└── cache.ts # RPC throttling & caching
This structure provides:
- Clear separation of concerns - Each module has a single responsibility
- Easy navigation - Find functionality by category
- Better scalability - New features fit naturally into the structure
- Improved imports - More explicit and maintainable
# npm
npm install @migratefun/sdk
# yarn
yarn add @migratefun/sdk
# pnpm
pnpm add @migratefun/sdkThe SDK requires these peer dependencies (likely already in your project):
yarn add @coral-xyz/anchor@^0.31.0 @solana/web3.js@^1.95.4 @solana/spl-token@^0.4.9
# Optional: For React hooks
yarn add react@^18The SDK exports are organized but you can import from the main package:
// Core types and functions
import {
LoadedProject,
BalanceSnapshot,
SdkError
} from '@migratefun/sdk';
// Transaction builders
import {
buildMigrateTx,
buildClaimMftTx,
buildClaimMerkleTx
} from '@migratefun/sdk';
// Queries
import {
loadProject,
getBalances,
computeClaimEligibility
} from '@migratefun/sdk';
// React hooks
import {
useProjectSession,
useClaim,
useBalances
} from '@migratefun/sdk/react';All exports are available from the main package entry point - the internal organization is transparent to users.
A complete, production-ready demo application is included in the demo/ directory. Use it to:
- Test the SDK locally during development
- See real-world implementation patterns
- Provide a working reference for your team
# From SDK root directory
cd demo
# Install dependencies
npm install
# Configure environment (optional)
cp .env.example .env.local
# Edit .env.local with your settings
# Start demo app
npm run devThe demo automatically uses the local SDK via file:.. reference, so any changes you make to the SDK are immediately available in the demo.
- ✅ Complete SDK integration showcase
- ✅ All React hooks (useLoadedProject, useBalances, useMigrate, useProjectSession, useClaim)
- ✅ Real-time balance watching
- ✅ Transaction status tracking
- ✅ Claim eligibility detection
- ✅ Error handling examples
- ✅ Network switching (devnet/mainnet)
- ✅ Clean, simple component architecture
See demo/README.md for detailed documentation.
import { Connection, PublicKey } from '@solana/web3.js';
import { loadProject, getBalances, buildMigrateTx } from '@migratefun/sdk';
// Setup connection
const connection = new Connection('https://api.devnet.solana.com');
const projectId = new PublicKey('your-project-id');
const userWallet = new PublicKey('user-wallet-address');
// Load project metadata
const project = await loadProject(projectId, connection, {
network: 'devnet'
});
console.log(`Migration project: ${project.projectId.toString()}`);
console.log(`Exchange ratio: 1 old token = ${project.exchangeRatio} new tokens`);
// Get user balances
const balances = await getBalances(projectId, userWallet, connection, {
project // Optional: pass pre-loaded project to avoid re-fetching
});
console.log(`Old token balance: ${balances.oldToken.toString()}`);
console.log(`New token balance: ${balances.newToken.toString()}`);
console.log(`SOL balance: ${balances.sol.toString()}`);
// Build migration transaction
const amount = 1000000n; // Amount in token base units
const migrateTx = await buildMigrateTx({
projectId,
user: userWallet,
amount,
connection,
project // Optional
});
// Sign and send transaction (with your wallet adapter)
const signature = await wallet.sendTransaction(migrateTx, connection);
console.log(`Migration successful: ${signature}`);import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import {
useLoadedProject,
useBalances,
useMigrate,
parseTokenAmount
} from '@migratefun/sdk/react';
import { PublicKey } from '@solana/web3.js';
function MigrationComponent() {
const { connection } = useConnection();
const wallet = useWallet();
const projectId = new PublicKey('your-project-id');
// Load project with automatic caching
const { project, isLoading: loadingProject } = useLoadedProject(
projectId,
connection,
{ network: 'devnet' }
);
// Watch balances in real-time
const { balances, formatted, isLoading: loadingBalances } = useBalances(
projectId,
wallet.publicKey,
connection,
{ project }
);
// Migration hook with status tracking
const { migrate, isLoading, status, error } = useMigrate(
connection,
wallet,
{
onSuccess: (signature) => {
console.log(`Migration complete: ${signature}`);
},
onError: (err) => {
console.error('Migration failed:', err.message);
}
}
);
const handleMigrate = async () => {
if (!project || !wallet.publicKey) return;
const amount = parseTokenAmount(100, project.oldTokenDecimals);
await migrate(projectId, amount, project);
};
if (loadingProject) return <div>Loading project...</div>;
if (!project) return <div>Project not found</div>;
return (
<div>
<h2>Token Migration</h2>
<p>Exchange Rate: 1 : {project.exchangeRatio}</p>
{loadingBalances ? (
<div>Loading balances...</div>
) : (
<div>
<p>Old Token: {formatted?.oldToken.toFixed(2)}</p>
<p>New Token: {formatted?.newToken.toFixed(2)}</p>
<p>MFT: {formatted?.mft.toFixed(2)}</p>
<p>SOL: {formatted?.sol.toFixed(4)}</p>
</div>
)}
<button
onClick={handleMigrate}
disabled={isLoading || !wallet.connected}
>
{isLoading ? `${status}...` : 'Migrate 100 Tokens'}
</button>
{error && <div className="error">{error.message}</div>}
</div>
);
}Fetches complete project configuration from the blockchain.
Parameters:
projectId: PublicKey- The project's unique identifierconnection: Connection- Solana RPC connectionoptions?: objectnetwork?: 'devnet' | 'mainnet-beta'- Override network detectionidlSource?: 'bundle' | 'onchain'- IDL source preferencecommitment?: Commitment- Transaction confirmation level
Returns: Promise<LoadedProject>
interface LoadedProject {
projectId: PublicKey;
authority: PublicKey;
oldTokenMint: PublicKey;
newTokenMint: PublicKey;
mftMint: PublicKey;
oldTokenDecimals: number;
newTokenDecimals: number;
mftDecimals: number;
exchangeRatio: number;
currentPhase: MigrationPhase;
isPaused: boolean;
// ... additional fields
}Example:
const project = await loadProject(
new PublicKey('project-id'),
connection,
{ network: 'devnet' }
);
console.log(`Paused: ${project.isPaused}`);
console.log(`Phase: ${project.currentPhase}`);Fetches all token balances for a user in a specific project.
Parameters:
projectId: PublicKey- The project identifieruser: PublicKey- User's wallet addressconnection: Connection- Solana RPC connectionoptions?: objectproject?: LoadedProject- Pre-loaded project (avoids re-fetch)network?: Networkcommitment?: Commitment
Returns: Promise<BalanceSnapshot>
interface BalanceSnapshot {
sol: bigint; // Lamports
oldToken: bigint; // Base units
newToken: bigint; // Base units
mft: bigint; // Base units
oldTokenProgram: PublicKey;
newTokenProgram: PublicKey;
}Example:
const balances = await getBalances(
projectId,
wallet.publicKey,
connection,
{ project } // Pass pre-loaded project
);
// Convert to human-readable format
const oldTokenFormatted = Number(balances.oldToken) / Math.pow(10, project.oldTokenDecimals);
console.log(`Old token balance: ${oldTokenFormatted}`);Subscribes to real-time balance updates with polling.
Parameters:
options: objectprojectId: PublicKeyuser: PublicKeyconnection: ConnectiononChange: (balances: BalanceSnapshot) => void- Callback for updatesonError?: (error: Error) => void- Error handlerintervalMs?: number- Polling interval (default: 150ms)project?: LoadedProjectnetwork?: Network
Returns: () => void - Unsubscribe function
Example:
const unsubscribe = watchBalances({
projectId,
user: wallet.publicKey,
connection,
onChange: (balances) => {
console.log('Balances updated:', balances);
},
onError: (error) => {
console.error('Balance watch error:', error);
},
intervalMs: 1000 // Poll every second
});
// Later: cleanup
unsubscribe();Builds an unsigned migration transaction.
Parameters:
params: objectprojectId: PublicKeyuser: PublicKeyamount: bigint- Amount in base units (e.g., lamports for 9 decimals)connection: Connectionproject?: LoadedProject- Pre-loaded projectnetwork?: NetworkcomputeBudget?: number- Custom compute units
Returns: Promise<Transaction>
Example:
import { parseTokenAmount } from '@migratefun/sdk';
// Parse human-readable amount to base units
const amount = parseTokenAmount(100.5, project.oldTokenDecimals);
const transaction = await buildMigrateTx({
projectId,
user: wallet.publicKey,
amount,
connection,
project
});
// Sign and send
const signature = await wallet.sendTransaction(transaction, connection);
await connection.confirmTransaction(signature, 'confirmed');Builds a transaction to claim new tokens using MFT (Migration Future Tokens). No penalty applied.
Parameters:
- Same as
buildMigrateTx
Returns: Promise<Transaction>
Example:
const claimTx = await buildClaimMftTx({
projectId,
user: wallet.publicKey,
amount: balances.mft, // Claim all MFT
connection,
project
});
const signature = await wallet.sendTransaction(claimTx, connection);Builds a transaction to claim tokens via merkle proof (late migration with penalty).
Parameters:
connection: Connection- Solana RPC connectionuser: PublicKey- User wallet public keyprojectId: string- Project identifieramount: bigint- Amount of old tokens to claim (in base units)proof: Buffer[]- Merkle proof (array of 32-byte buffers)project: LoadedProject- Pre-loaded project configurationoptions?: object- Optional configuration
Returns: Promise<BuildClaimMerkleTxResult>
Example:
import { buildClaimMerkleTx } from '@migratefun/sdk';
// Get merkle proof from API/cache
const proof = getMerkleProof(wallet.publicKey);
const { transaction, expectedNewTokens, penaltyAmount } = await buildClaimMerkleTx(
connection,
wallet.publicKey,
projectId,
oldTokenAmount,
proof,
project
);
console.log(`Penalty: ${penaltyAmount}, Expected: ${expectedNewTokens}`);
const signature = await wallet.sendTransaction(transaction, connection);Builds a transaction to claim a refund for a failed migration.
Parameters:
connection: Connection- Solana RPC connectionuser: PublicKey- User wallet public keyprojectId: string- Project identifierproject: LoadedProject- Pre-loaded project configurationoptions?: object- Optional configuration
Returns: Promise<BuildClaimRefundTxResult>
Example:
import { buildClaimRefundTx } from '@migratefun/sdk';
const { transaction, expectedRefundAmount } = await buildClaimRefundTx(
connection,
wallet.publicKey,
projectId,
project
);
console.log(`Refund amount: ${expectedRefundAmount}`);
const signature = await wallet.sendTransaction(transaction, connection);Converts base units to human-readable format.
const formatted = formatTokenAmount(1000000n, 6); // "1.000000"Converts human-readable amount to base units.
const baseUnits = parseTokenAmount(100.5, 9); // 100500000000nChecks if a project is paused.
if (isProjectPaused(project)) {
console.log('Migration is currently paused');
}Checks if a project is in active migration phase.
if (isProjectActive(project)) {
console.log('Migration is active');
}Loads project metadata with automatic caching.
Returns:
{
project: LoadedProject | null;
isLoading: boolean;
error: Error | null;
refetch: () => Promise<void>;
}Options:
network?: Networkenabled?: boolean- Disable auto-fetch (default: true)refetchInterval?: number- Auto-refetch interval in msonSuccess?: (project: LoadedProject) => voidonError?: (error: Error) => void
Example:
const { project, isLoading, error, refetch } = useLoadedProject(
projectId,
connection,
{
network: 'devnet',
refetchInterval: 60000, // Refresh every minute
onSuccess: (proj) => console.log('Project loaded:', proj.projectId)
}
);
// Manual refetch
<button onClick={refetch}>Refresh Project</button>Watches user balances in real-time.
Returns:
{
balances: BalanceSnapshot | null;
formatted: FormattedBalances | null;
isLoading: boolean;
error: Error | null;
refetch: () => Promise<void>;
}
interface FormattedBalances {
sol: number;
oldToken: number;
newToken: number;
mft: number;
}Options:
project?: LoadedProject- Pre-loaded projectnetwork?: Networkenabled?: booleanrefetchInterval?: number- Polling interval (default: 150ms)onBalanceChange?: (balances: BalanceSnapshot) => void
Example:
const { balances, formatted, isLoading } = useBalances(
projectId,
wallet.publicKey,
connection,
{
project,
refetchInterval: 1000,
onBalanceChange: (bal) => {
if (bal.oldToken > previousBalance) {
toast.success('Tokens received!');
}
}
}
);
<div>SOL: {formatted?.sol.toFixed(4)}</div>Executes migration transactions with status tracking.
Returns:
{
migrate: (projectId: PublicKey, amount: bigint, project?: LoadedProject) => Promise<string>;
isLoading: boolean;
status: MigrateStatus;
signature: string | null;
error: Error | null;
}
type MigrateStatus =
| 'idle'
| 'preparing'
| 'signing'
| 'sending'
| 'confirming'
| 'confirmed'
| 'error';Options:
onSuccess?: (signature: string) => voidonError?: (error: Error) => voidonStatusChange?: (status: MigrateStatus) => voidcomputeBudget?: number
Example:
const { migrate, isLoading, status, signature, error } = useMigrate(
connection,
wallet,
{
onSuccess: (sig) => {
toast.success(`Migration successful! ${sig}`);
router.push('/success');
},
onError: (err) => {
if (err.code === 'INSUFFICIENT_BALANCE') {
toast.error('Insufficient balance');
}
},
onStatusChange: (status) => {
console.log('Migration status:', status);
}
}
);
const handleMigrate = async () => {
try {
const amount = parseTokenAmount(100, project.oldTokenDecimals);
const sig = await migrate(projectId, amount, project);
console.log('Signature:', sig);
} catch (err) {
// Error already handled by onError callback
}
};Unified hook combining project loading, balance watching, and claim eligibility detection.
Features:
- ✅ Combines three operations: project loading, balance watching, eligibility detection
- ✅ Automatic race condition handling (balances can arrive before project metadata)
- ✅ Built-in safety features: timeout protection (30s), concurrent fetch prevention, debug logging
- ✅ Auto-refetch with configurable interval (default: 5 seconds)
- ✅ Works with or without a connected user (anonymous mode)
Returns:
{
project: LoadedProject | null;
balances: BalanceSnapshot | null;
formatted: FormattedBalances | null;
claimType: ClaimType; // 'mft' | 'merkle' | 'refund' | null
claimEligibility: ClaimEligibility | null;
redirect: ProjectRedirectIntent | null;
isLoading: boolean;
error: Error | null;
refresh: () => Promise<void>;
}Options:
network?: NetworkrefetchInterval?: number- Auto-refetch interval (default: 5000ms)enabled?: boolean
Example:
import { useProjectSession } from '@migratefun/sdk/react';
const {
project,
balances,
formatted,
claimType,
isLoading
} = useProjectSession(projectId, connection, wallet.publicKey);
if (isLoading) return <div>Loading...</div>;
// Automatically determine which UI to show
switch (claimType) {
case 'mft':
return <MftClaimButton />;
case 'merkle':
return <MerkleClaimButton />;
case 'refund':
return <RefundClaimButton />;
default:
return <div>No claims available</div>;
}Unified hook for executing all types of claim transactions.
Returns:
{
claimMft: (projectId: string, amount: bigint, project: LoadedProject) => Promise<string>;
claimMerkle: (projectId: string, amount: bigint, proof: Buffer[], project: LoadedProject) => Promise<string>;
claimRefund: (projectId: string, project: LoadedProject) => Promise<string>;
isLoading: boolean;
status: ClaimStatus;
error: Error | null;
signature: string | null;
reset: () => void;
}
type ClaimStatus =
| 'idle'
| 'preparing'
| 'signing'
| 'sending'
| 'confirming'
| 'confirmed'
| 'error';Options:
onSuccess?: (result: TransactionResult) => voidonError?: (error: Error) => voidonStatusChange?: (status: ClaimStatus) => void
Example:
import { useClaim, useProjectSession } from '@migratefun/sdk/react';
function ClaimButton() {
const { project, balances, claimType } = useProjectSession(projectId, connection, wallet.publicKey);
const { claimMft, claimMerkle, claimRefund, isLoading, status } = useClaim(
connection,
wallet,
{
onSuccess: (result) => {
toast.success(`Claim successful! ${result.signature}`);
}
}
);
const handleClaim = async () => {
if (!project || !balances) return;
if (claimType === 'mft') {
await claimMft(projectId, balances.mft, project);
} else if (claimType === 'merkle') {
const proof = await getMerkleProof(wallet.publicKey);
await claimMerkle(projectId, balances.oldToken, proof, project);
} else if (claimType === 'refund') {
await claimRefund(projectId, project);
}
};
return (
<button onClick={handleClaim} disabled={isLoading}>
{isLoading ? `${status}...` : 'Claim Tokens'}
</button>
);
}The SDK provides typed errors with user-friendly messages and recovery actions.
enum SdkErrorCode {
// Wallet errors
WALLET_NOT_CONNECTED = 'WALLET_NOT_CONNECTED',
WALLET_SIGNATURE_REJECTED = 'WALLET_SIGNATURE_REJECTED',
// Network errors
RPC_ERROR = 'RPC_ERROR',
TRANSACTION_FAILED = 'TRANSACTION_FAILED',
NETWORK_ERROR = 'NETWORK_ERROR',
// Program errors
PROJECT_PAUSED = 'PROJECT_PAUSED',
MIGRATION_WINDOW_CLOSED = 'MIGRATION_WINDOW_CLOSED',
INSUFFICIENT_BALANCE = 'INSUFFICIENT_BALANCE',
INVALID_AMOUNT = 'INVALID_AMOUNT',
UNAUTHORIZED = 'UNAUTHORIZED',
// Other
UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}import { parseError, isSdkError, SdkErrorCode } from '@migratefun/sdk';
try {
const tx = await buildMigrateTx({ ... });
await wallet.sendTransaction(tx, connection);
} catch (err) {
const sdkError = parseError(err);
if (isSdkError(sdkError)) {
console.error(sdkError.message); // User-friendly message
console.log(sdkError.code); // Error code
console.log(sdkError.details); // Additional context
// Handle specific errors
if (sdkError.code === SdkErrorCode.PROJECT_PAUSED) {
alert('Migration is temporarily paused. Please try again later.');
} else if (sdkError.code === SdkErrorCode.INSUFFICIENT_BALANCE) {
alert('You do not have enough tokens to migrate this amount.');
}
}
}Each error includes:
message- User-friendly descriptioncode- Typed error codedetails- Additional contextisRetryable- Whether the operation can be retriedoriginalError- Original error for debugging
The SDK respects these environment variables:
# Network selection (default: mainnet-beta)
SOLANA_NETWORK=devnet
# Override default program ID (optional)
MIGRATION_PROGRAM_OVERRIDE=your-program-id
# IDL source preference (optional)
MIGRATEFUN_IDL_SOURCE=bundle # or 'onchain'The SDK works seamlessly with Next.js 13+ App Router. Use React hooks in Client Components:
// app/migrate/page.tsx
'use client';
import { useLoadedProject, useBalances } from '@migratefun/sdk/react';
import { useConnection, useWallet } from '@solana/wallet-adapter-react';
export default function MigratePage() {
const { connection } = useConnection();
const wallet = useWallet();
const { project } = useLoadedProject(projectId, connection);
const { formatted } = useBalances(projectId, wallet.publicKey, connection);
return <div>Old Token: {formatted?.oldToken}</div>;
}Important: Always use 'use client' directive when using React hooks.
RPC Proxy Pattern (Recommended):
Create an API route to proxy RPC requests and protect API keys:
// app/api/rpc/route.ts
import { Connection } from '@solana/web3.js';
export async function POST(request: Request) {
const { method, params } = await request.json();
const connection = new Connection(
process.env.HELIUS_RPC_URL!, // Server-side only
'confirmed'
);
// Forward RPC call
const result = await connection._rpcRequest(method, params);
return Response.json(result);
}Then use the proxy on client side:
const connection = new Connection('/api/rpc');The SDK works out-of-the-box with Vite. No special configuration needed.
Optional optimization for faster builds:
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
optimizeDeps: {
include: [
'@migratefun/sdk',
'@coral-xyz/anchor',
'@solana/web3.js',
'@solana/spl-token'
]
}
});The SDK is browser-safe and should work in React Native with proper polyfills:
yarn add react-native-get-random-values// index.js (before other imports)
import 'react-native-get-random-values';Note: React Native support is experimental. Please report issues.
import { Connection } from '@solana/web3.js';
import { loadProject } from '@migratefun/sdk';
const connection = new Connection(
'https://your-custom-rpc-endpoint.com',
{
commitment: 'confirmed',
confirmTransactionInitialTimeout: 60000
}
);
const project = await loadProject(projectId, connection);import { simulateTransaction } from '@migratefun/sdk';
const transaction = await buildMigrateTx({ ... });
const simulation = await simulateTransaction(
transaction,
connection,
wallet.publicKey
);
console.log('Logs:', simulation.logs);
console.log('Units consumed:', simulation.unitsConsumed);
console.log('Error:', simulation.err);const transaction = await buildMigrateTx({
projectId,
user: wallet.publicKey,
amount,
connection,
computeBudget: 400000 // Custom compute units
});import { Connection, Transaction } from '@solana/web3.js';
import { buildMigrateTx } from '@migratefun/sdk';
// Build multiple migration transactions
const tx1 = await buildMigrateTx({ projectId: project1, ... });
const tx2 = await buildMigrateTx({ projectId: project2, ... });
// Combine into single transaction (if compute units allow)
const batchTx = new Transaction()
.add(...tx1.instructions)
.add(...tx2.instructions);
await wallet.sendTransaction(batchTx, connection);The SDK implements intelligent caching:
- Balances: 30-second TTL
- Metadata: 5-minute TTL
- Project configs: 1-hour TTL
Caching is automatic and requires no configuration.
Built-in throttling prevents rate limiting:
- Minimum 100ms delay between RPC calls
- Automatic request coalescing
- Batch-friendly design
| Package | Size (gzipped) |
|---|---|
| Core SDK | ~50KB |
| React Adapter | ~10KB |
Enable tree-shaking in your bundler for optimal sizes.
Solution: Make sure React is installed as a peer dependency.
yarn add react@^18Solution: Use 'use client' directive in components using hooks.
'use client';
import { useLoadedProject } from '@migratefun/sdk/react';Solution: Check that the user has enough SOL for transaction fees and enough tokens for the migration amount.
const balances = await getBalances(projectId, wallet.publicKey, connection);
if (balances.sol < 5000n) {
console.error('Need at least 0.000005 SOL for fees');
}
if (balances.oldToken < amount) {
console.error('Insufficient token balance');
}Solution: Use an RPC proxy (Next.js) or premium RPC provider (Helius, Alchemy).
// Use API route proxy
const connection = new Connection('/api/rpc');Solution: Check project status before attempting migration.
const project = await loadProject(projectId, connection);
if (project.isPaused) {
alert('Migration is currently paused by the project authority.');
return;
}A complete demo application is available in the demo/ directory:
- Complete Demo App -
demo/- Production-ready Next.js 15 app showcasing all SDK features with clean component architecture
Minimal examples are available in the examples/ directory:
- Next.js Example -
examples/nextjs-demo/- Basic Next.js integration - Vite Example -
examples/vite-demo/- Basic Vite integration
The SDK is written in TypeScript and includes comprehensive type definitions.
import type {
LoadedProject,
BalanceSnapshot,
SdkError,
Network
} from '@migratefun/sdk';
const handleProject = (project: LoadedProject) => {
console.log(project.exchangeRatio); // Type-safe access
};Run SDK tests:
cd sdk
yarn testRun tests in watch mode:
yarn test:watchContributions are welcome! Please see CONTRIBUTING.md for guidelines.
MIT License - see LICENSE for details.
- Documentation: https://docs.migrate.fun
- Issues: GitHub Issues
- Discord: Join our community
See CHANGELOG.md for version history.
Built with:
- Anchor - Solana smart contract framework
- Solana Web3.js - Solana JavaScript SDK
- tsup - TypeScript bundler
Made with ❤️ by the migrate.fun team