UNPKG

@flipflop-sdk/node

Version:

FlipFlop Node.js SDK for programmatic token operations

858 lines (710 loc) 20.9 kB
# @flipflop-sdk/node A comprehensive Node.js SDK for FlipFlop token operations on Solana. This library provides programmatic access to token launches, Universal Referral Code (URC) management, batch minting operations, and metadata management. ## Installation ```bash npm install @flipflop-sdk/node # or yarn add @flipflop-sdk/node ``` ## Quick Start ### Basic Usage ```javascript const { launchToken, mintToken, setUrc, getMintData, getUrcData, getSystemConfig, generateMetadataUri, validateImageFile } = require('@flipflop-sdk/node'); async function example() { // Generate metadata URI first const metadataResult = await generateMetadataUri({ rpc: 'https://api.devnet.solana.com', name: 'My Token', symbol: 'MTK', description: 'A sample token for demonstration', imagePath: './path/to/token-logo.png' }); if (metadataResult.success) { console.log('Metadata URI:', metadataResult.metadataUrl); console.log('Image URI:', metadataResult.imageUrl); } // Launch a new token with metadata const launchResult = await launchToken({ rpc: 'https://api.devnet.solana.com', name: 'My Token', symbol: 'MTK', tokenType: 'meme', // or 'standard' uri: metadataResult.metadataUrl, // Use generated metadata URI keypairBs58: 'your-base58-private-key' }); console.log('Token launched:', launchResult.mintAddress.toString()); console.log('Transaction:', launchResult.transactionHash); // Set URC code const urcResult = await setUrc({ rpc: 'https://api.devnet.solana.com', mint: launchResult.mintAddress.toString(), urc: 'MYCODE2024', keypairBs58: 'your-base58-private-key' }); console.log('URC set:', urcResult.urc); console.log('Usage count:', urcResult.usageCount); // Mint tokens const mintResult = await mintToken({ rpc: 'https://api.devnet.solana.com', mint: launchResult.mintAddress.toString(), urc: 'MYCODE2024', keypairBs58: 'minter-base58-private-key' }); if (mintResult.success) { console.log('Mint successful:', mintResult.data?.tx); console.log('Token account:', mintResult.data?.tokenAccount.toString()); } // Get token information const tokenInfo = await getMintData({ rpc: 'https://api.devnet.solana.com', mint: launchResult.mintAddress.toString() }); console.log('Token name:', tokenInfo.name); console.log('Token symbol:', tokenInfo.symbol); console.log('Current supply:', tokenInfo.currentSupply); console.log('Max supply:', tokenInfo.maxSupply); // Get URC information const urcInfo = await getUrcData({ rpc: 'https://api.devnet.solana.com', urc: 'MYCODE2024' }); console.log('URC valid:', urcInfo.isValid); console.log('Referrer:', urcInfo.referrerMain.toString()); console.log('Usage count:', urcInfo.usageCount); // Get system configuration const systemConfig = await getSystemConfig({ rpc: 'https://api.devnet.solana.com' }); console.log('System manager:', systemConfig.systemManagerAccount.toString()); console.log('Protocol fee rate:', systemConfig.graduateFeeRate); } ### TypeScript Usage ```typescript import { launchToken, mintToken, setUrc, getMintData, getUrcData, getSystemConfig, generateMetadataUri, validateImageFile, LaunchTokenOptions, LaunchTokenResponse, MintTokenOptions, MintTokenResponse, SetUrcOptions, SetUrcResponse, GetMintDataOptions, GetMintDataResponse, GetUrcDataOptions, GetUrcDataResponse, SystemConfigAccountOptions, SystemConfigAccountData, GenerateMetadataUriOptions, MetadataUploadResponse } from '@flipflop-sdk/node'; async function example() { // Generate metadata with type safety const metadataOptions: GenerateMetadataUriOptions = { rpc: 'https://api.devnet.solana.com', name: 'TypeScript Token', symbol: 'TST', description: 'A TypeScript token example', imagePath: './assets/logo.png' }; const metadataResult: MetadataUploadResponse = await generateMetadataUri(metadataOptions); // Launch token with type safety const launchOptions: LaunchTokenOptions = { rpc: 'https://api.devnet.solana.com', name: 'TypeScript Token', symbol: 'TST', tokenType: 'standard', uri: metadataResult.metadataUrl, keypairBs58: 'your-base58-private-key' }; const launchResult: LaunchTokenResponse = await launchToken(launchOptions); // Set URC with type safety const setUrcOptions: SetUrcOptions = { rpc: 'https://api.devnet.solana.com', mint: launchResult.mintAddress.toString(), urc: 'TST_CODE', keypairBs58: 'your-base58-private-key' }; const urcResult: SetUrcResponse = await setUrc(setUrcOptions); // Mint tokens with type safety const mintOptions: MintTokenOptions = { rpc: 'https://api.devnet.solana.com', mint: launchResult.mintAddress.toString(), urc: 'TST_CODE', keypairBs58: 'minter-base58-private-key' }; const mintResult: MintTokenResponse = await mintToken(mintOptions); } ``` ## API Reference ### Core Functions #### `generateMetadataUri(options: GenerateMetadataUriOptions): Promise<MetadataUploadResponse>` **NEW** - Generate metadata URI by uploading image and metadata to Irys network. **Parameters:** ```typescript interface GenerateMetadataUriOptions { rpc: string; // RPC endpoint URL name: string; // Token name symbol: string; // Token symbol description?: string; // Token description (optional) imagePath: string; // Path to image file } ``` **Returns:** ```typescript interface MetadataUploadResponse { success: boolean; metadataUrl?: string; // Irys gateway URL for metadata JSON imageUrl?: string; // Irys gateway URL for uploaded image error?: string; // Error message if upload failed } ``` **Image Requirements:** - **Supported formats**: JPEG, PNG, GIF, WebP, AVIF - **Maximum size**: 250KB - **File validation**: Automatic type and size checking **Example:** ```javascript const result = await generateMetadataUri({ rpc: 'https://api.devnet.solana.com', name: 'My Awesome Token', symbol: 'MAT', description: 'This is an awesome token for the community', imagePath: './assets/token-logo.png' }); if (result.success) { console.log('Metadata URL:', result.metadataUrl); console.log('Image URL:', result.imageUrl); } else { console.error('Upload failed:', result.error); } ``` #### `validateImageFile(imagePath: string): { valid: boolean; error?: string }` **NEW** - Validate image file before upload. **Parameters:** - `imagePath`: Path to the image file **Returns:** - `valid`: Boolean indicating if file is valid - `error`: Error message if validation fails **Example:** ```javascript const validation = validateImageFile('./logo.png'); if (!validation.valid) { console.error('Image validation failed:', validation.error); } ``` #### `launchToken(options: LaunchTokenOptions): Promise<LaunchTokenResponse>` Launch a new token with specified parameters. **Parameters:** ```typescript interface LaunchTokenOptions { rpc: string; // RPC endpoint URL name: string; // Token name symbol: string; // Token symbol tokenType: string; // 'meme' or 'standard' uri?: string; // Metadata URI (optional, use generateMetadataUri) keypairBs58?: string; // Base58 encoded private key keypairFile?: string; // Path to keypair file } ``` **Returns:** ```typescript interface LaunchTokenResponse { success: boolean; transactionHash: string; mintAddress: PublicKey; configAddress: PublicKey; metadata: TokenMetadata; configuration: ConfigAccountData; } ``` **Example:** ```javascript const result = await launchToken({ rpc: 'https://api.devnet.solana.com', name: 'My Token', symbol: 'MTK', tokenType: 'meme', uri: 'https://gateway.irys.xyz/your-metadata-id', // From generateMetadataUri keypairBs58: 'your-base58-private-key' }); ``` #### `setUrc(options: SetUrcOptions): Promise<SetUrcResponse>` Set Universal Referral Code for a token. **Parameters:** ```typescript interface SetUrcOptions { rpc: string; // RPC endpoint URL urc: string; // Universal Referral Code mint: string; // Token mint address keypairBs58?: string; // Base58 encoded private key keypairFile?: string; // Path to keypair file } ``` **Returns:** ```typescript interface SetUrcResponse { transactionHash: string; urc: string; mint: PublicKey; referrer: PublicKey; referrerTokenAccount: PublicKey; codeHash: PublicKey; usageCount: number; activatedAt: number; } ``` **Example:** ```javascript const result = await setUrc({ rpc: 'https://api.devnet.solana.com', mint: 'TokenMintAddress', urc: 'UNIQUECODE', keypairBs58: 'your-base58-private-key' }); ``` #### `mintToken(options: MintTokenOptions): Promise<MintTokenResponse>` Mint tokens using a URC code. **Parameters:** ```typescript interface MintTokenOptions { rpc: string; // RPC endpoint URL mint: string; // Token mint address urc: string; // Universal Referral Code keypairBs58?: string; // Base58 encoded private key keypairFile?: string; // Path to keypair file } ``` **Returns:** ```typescript interface MintTokenResponse { success: boolean; message?: string; data?: { tx: string; owner: PublicKey; tokenAccount: PublicKey; } } ``` **Example:** ```javascript const result = await mintToken({ rpc: 'https://api.devnet.solana.com', mint: 'TokenMintAddress', urc: 'UNIQUECODE', keypairBs58: 'minter-base58-private-key' }); ``` #### `getMintData(options: GetMintDataOptions): Promise<GetMintDataResponse>` Get detailed information about a token. **Parameters:** ```typescript interface GetMintDataOptions { rpc: string; // RPC endpoint URL mint: string; // Token mint address } ``` **Returns:** ```typescript interface GetMintDataResponse { mint: PublicKey; name: string; symbol: string; uri: string; isMutable: boolean; configAccount: PublicKey; admin: PublicKey; tokenVault: PublicKey; feeRate: number; targetEras: number; initialMintSize: number; epochesPerEra: number; targetSecondsPerEpoch: number; reduceRatio: number; maxSupply: number; liquidityTokensRatio: number; currentSupply: number; liquidityTokensSupply: number; minterTokensSupply: number; } ``` **Example:** ```javascript const info = await getMintData({ rpc: 'https://api.devnet.solana.com', mint: 'TokenMintAddress' }); ``` #### `getUrcData(options: GetUrcDataOptions): Promise<GetUrcDataResponse>` Get information about a URC code. **Parameters:** ```typescript interface GetUrcDataOptions { rpc: string; // RPC endpoint URL urc: string; // Universal Referral Code } ``` **Returns:** ```typescript interface GetUrcDataResponse { urc: string; codeHash: PublicKey; mint: PublicKey; referrerMain: PublicKey; referrerAta: PublicKey; usageCount: number; activeTimestamp: number; isValid: boolean; } ``` **Example:** ```javascript const info = await getUrcData({ rpc: 'https://api.devnet.solana.com', urc: 'UNIQUECODE' }); ``` #### `getSystemConfig(options: SystemConfigAccountOptions): Promise<SystemConfigAccountData>` Get system configuration information. **Parameters:** ```typescript interface SystemConfigAccountOptions { rpc: string; // RPC endpoint URL } ``` **Returns:** ```typescript interface SystemConfigAccountData { systemConfigAccount: PublicKey; systemManagerAccount: PublicKey; admin: PublicKey; count: number; referralUsageMaxCount: number; protocolFeeAccount: PublicKey; refundFeeRate: number; referrerResetIntervalSeconds: number; updateMetadataFee: number; customizedDeployFee: number; initPoolWsolAmount: number; graduateFeeRate: number; minGraduateFee: number; raydiumCpmmCreateFee: number; } ``` **Example:** ```javascript const config = await getSystemConfig({ rpc: 'https://api.devnet.solana.com' }); ``` ### Utility Functions All utility functions and constants can also be imported from the library: ```typescript import { initProvider, initProviderNoSigner, loadKeypairFromBase58, loadKeypairFromFile, validateImageFile, CONFIGS, NetworkType } from '@flipflop-sdk/node'; ``` ## Configuration ### Network Types - `mainnet`: Production network - `devnet`: Development network - `local`: Local validator ### Token Types - `meme`: Aggressive parameters for community tokens - `standard`: Conservative parameters for utility tokens ### RPC Endpoints - **Mainnet**: `https://api.mainnet-beta.solana.com` - **Devnet**: `https://api.devnet.solana.com` - **Local**: `http://127.0.0.1:8899` ### Irys Network Integration - **Devnet**: `https://api-dev.flipflop.plus/api/irys/upload` - **Mainnet**: `https://api.flipflop.plus/api/irys/upload` - **Gateway**: `https://gateway.irys.xyz/` ## Authentication The SDK supports two methods for providing keypairs: ### 1. Base58 Encoded Private Key ```javascript const result = await launchToken({ // ... other options keypairBs58: 'your-base58-encoded-private-key' }); ``` ### 2. Keypair File Path ```javascript const result = await launchToken({ // ... other options keypairFile: './path/to/keypair.json' }); ``` ## Error Handling All functions throw descriptive errors for validation and runtime issues: ```javascript try { // Validate image first const validation = validateImageFile('./logo.png'); if (!validation.valid) { throw new Error(`Image validation failed: ${validation.error}`); } // Generate metadata const metadataResult = await generateMetadataUri({ rpc: 'https://api.devnet.solana.com', name: 'My Token', symbol: 'MTK', description: 'My awesome token', imagePath: './logo.png' }); if (!metadataResult.success) { throw new Error(`Metadata upload failed: ${metadataResult.error}`); } // Launch token const result = await launchToken({ rpc: 'https://api.devnet.solana.com', name: 'My Token', symbol: 'MTK', tokenType: 'meme', uri: metadataResult.metadataUrl, keypairBs58: 'invalid-key' }); } catch (error) { console.error('Operation failed:', error.message); } ``` ## Development ### Dependencies The SDK uses the following key dependencies: **Core Solana Libraries:** - `@coral-xyz/anchor` (0.31.1) - Anchor framework for Solana - `@solana/web3.js` (^1.98.0) - Solana Web3 JavaScript API - `@solana/spl-token` (^0.4.9) - SPL Token library - `@solana/spl-token-metadata` (^0.1.6) - Token metadata standard **Utility Libraries:** - `axios` (^1.11.0) - HTTP client for API requests - `form-data` (^4.0.4) - Multipart form data for file uploads - `bn.js` (5.2.1) - Big number arithmetic - `bs58` (^6.0.0) - Base58 encoding/decoding - `decimal.js` (^10.4.3) - Decimal arithmetic - `sleep-promise` (^9.1.0) - Promise-based sleep utility ### Building ```bash # Install dependencies npm install # Build the library npm run build # Run tests npm test # Watch mode for development npm run dev ``` ### Testing ```bash # Run all tests npm test # Run specific test file npm test launch.test.ts # Run tests with coverage npm run test:coverage # Run metadata tests (requires network connection) npm test metadata.test.ts ``` **Note**: Metadata tests make real API calls to devnet and require internet connection. ## Examples ### Complete Token Launch Flow with Metadata ```javascript const { generateMetadataUri, launchToken, setUrc, mintToken } = require('@flipflop-sdk/node'); async function completeFlowWithMetadata() { const rpc = 'https://api.devnet.solana.com'; const creatorKey = 'creator-base58-private-key'; const minterKey = 'minter-base58-private-key'; // 1. Generate metadata URI console.log('Step 1: Generating metadata...'); const metadata = await generateMetadataUri({ rpc, name: 'Demo Token', symbol: 'DEMO', description: 'A demonstration token with custom metadata', imagePath: './assets/demo-logo.png' }); if (!metadata.success) { throw new Error(`Metadata generation failed: ${metadata.error}`); } console.log('Metadata URL:', metadata.metadataUrl); console.log('Image URL:', metadata.imageUrl); // 2. Launch token with metadata console.log('Step 2: Launching token...'); const launch = await launchToken({ rpc, name: 'Demo Token', symbol: 'DEMO', tokenType: 'standard', uri: metadata.metadataUrl, keypairBs58: creatorKey }); console.log('Token launched:', launch.mintAddress.toString()); // 3. Set URC console.log('Step 3: Setting URC...'); const urc = await setUrc({ rpc, mint: launch.mintAddress.toString(), urc: 'DEMO_CODE', keypairBs58: creatorKey }); console.log('URC set:', urc.urc); // 4. Mint tokens console.log('Step 4: Minting tokens...'); const mint = await mintToken({ rpc, mint: launch.mintAddress.toString(), urc: 'DEMO_CODE', keypairBs58: minterKey }); console.log('Mint successful:', mint.success); return { metadata: metadata.metadataUrl, mint: launch.mintAddress.toString(), urc: urc.urc, transaction: mint.data?.tx }; } ``` ### Batch Operations with Metadata Validation ```javascript async function batchMintWithValidation() { const imagePaths = [ './assets/logo1.png', './assets/logo2.jpg', './assets/logo3.gif' ]; // Validate all images first const validations = imagePaths.map(path => ({ path, validation: validateImageFile(path) })); const validImages = validations.filter(v => v.validation.valid); const invalidImages = validations.filter(v => !v.validation.valid); if (invalidImages.length > 0) { console.warn('Invalid images found:'); invalidImages.forEach(img => { console.warn(`- ${img.path}: ${img.validation.error}`); }); } // Process valid images const metadataPromises = validImages.map((img, index) => generateMetadataUri({ rpc: 'https://api.devnet.solana.com', name: `Batch Token ${index + 1}`, symbol: `BT${index + 1}`, description: `Batch generated token ${index + 1}`, imagePath: img.path }) ); const metadataResults = await Promise.all(metadataPromises); console.log('Batch metadata generation results:', metadataResults); return metadataResults; } ``` ## Migration from CLI ### CLI to SDK Mapping | CLI Command | SDK Function | |-------------|-------------| | `flipflop launch` | `launchToken()` | | `flipflop set-urc` | `setUrc()` | | `flipflop mint` | `mintToken()` | | `flipflop display-mint` | `getMintData()` | | `flipflop display-urc` | `getUrcData()` | | **NEW** | `generateMetadataUri()` | | **NEW** | `validateImageFile()` | ### Migration Example **CLI usage:** ```bash flipflop launch --name "MyToken" --symbol "MTK" --keypair-file ./keypair.json --rpc https://api.devnet.solana.com ``` **SDK usage:** ```javascript const { generateMetadataUri, launchToken } = require('@flipflop-sdk/node'); // Generate metadata first (new capability) const metadata = await generateMetadataUri({ rpc: 'https://api.devnet.solana.com', name: 'MyToken', symbol: 'MTK', description: 'My awesome token', imagePath: './logo.png' }); // Launch with metadata const result = await launchToken({ name: 'MyToken', symbol: 'MTK', tokenType: 'standard', uri: metadata.metadataUrl, rpc: 'https://api.devnet.solana.com', keypairFile: './keypair.json' }); ``` ## Security - Never commit private keys to version control - Use environment variables for sensitive configuration - Validate all inputs before SDK operations - **Image Security**: Only upload trusted images, validate file types and sizes - **Metadata Security**: Review generated metadata before using in production - Consider using `Keypair.fromSeed()` for deterministic key generation - Always verify transaction results before proceeding - **Network Security**: Use HTTPS endpoints for all API calls ## TypeScript Support Full TypeScript support with comprehensive type definitions: ```typescript import { LaunchTokenOptions, LaunchTokenResponse, MintTokenOptions, MintTokenResponse, SetUrcOptions, SetUrcResponse, GetMintDataOptions, GetMintDataResponse, GetUrcDataOptions, GetUrcDataResponse, SystemConfigAccountOptions, SystemConfigAccountData, GenerateMetadataUriOptions, MetadataUploadResponse, MetadataParams, TokenMetadata, ConfigAccountData, NetworkType } from '@flipflop-sdk/node'; ``` ## Contributing 1. Fork the repository 2. Create a feature branch 3. Add tests for new functionality 4. Ensure all tests pass (including metadata tests) 5. Update documentation for new features 6. Submit a pull request ## License MIT License - see LICENSE file for details.