@gala-chain/launchpad-sdk
Version:
TypeScript SDK for Gala Launchpad Backend API - Production-ready DeFi token launchpad integration with wallet-based authentication, GalaChain trading, and comprehensive user operations. 100% tested (22/22 endpoints working).
1,477 lines (1,137 loc) • 60.6 kB
Markdown
# Gala Launchpad SDK
A comprehensive TypeScript SDK for the Gala Launchpad Backend API, providing type-safe authentication, trading, and real-time features for DeFi applications.
[](https://badge.fury.io/js/@gala-chain%2Flaunchpad-sdk)
[](https://opensource.org/licenses/MIT)
[](http://www.typescriptlang.org/)
## Features
**Clean Result Types with No Wrapper Overhead:**
- **Direct Result Access**: Get clean, typed results without wrapper objects
- **Semantic Type Conversion**: Dates as Date objects, numbers as numbers, strings for precision
- **Comprehensive Type Safety**: Full TypeScript support with precise result interfaces
- **Zero Wrapper Overhead**: No more `result.data.success` - direct property access
- **Options Object Pattern**: All methods with 2+ parameters use clean options objects
- **Auto-Pagination**: Automatic multi-page fetching with configurable concurrency
### Developer Experience
```typescript
import { createLaunchpadSDK, createWallet } from '@gala-chain/launchpad-sdk';
// Auto-detect wallet format and create SDK
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic' // Auto-detects format!
});
// Direct result access - no wrapper objects!
const pools = await sdk.fetchPools({ type: 'recent' });
console.log(`Found ${pools.total} pools`); // Direct property access
console.log(`Page ${pools.page} of ${pools.totalPages}`); // Clean pagination
console.log(`Has next: ${pools.hasNext}`); // Boolean convenience properties
// Clean typed results everywhere
const balance = await sdk.fetchGalaBalance();
console.log(`Balance: ${balance.balance} GALA`); // Direct balance access
console.log(`Last updated: ${balance.lastUpdated.toISOString()}`); // Date object
```
## Clean API Architecture
**Direct result access with no wrapper overhead:**
```typescript
// Get pools with direct property access
const pools = await sdk.fetchPools({ type: 'recent' });
console.log(pools.pools); // Direct access to pool array
console.log(pools.total); // Immediate pagination info
console.log(pools.hasNext); // Computed convenience properties
```
## Key Features
- **Type-Safe API Client**: Full TypeScript support with comprehensive type definitions
- **Clean Result Types**: Direct property access without wrapper objects
- **Options Object Pattern**: All multi-parameter methods use clean options objects
- **Auto-Pagination**: Automatic multi-page fetching for large result sets
- **Signature Authentication**: Ethereum wallet-based authentication with automatic signature generation
- **Helper Functions**: Auto-detecting wallet creation and SDK factory functions
- **Pool Management**: Create, fetch, and check token pools on the launchpad
- **Token Trading**: Buy and sell tokens with slippage protection via GalaChain
- **Token Transfers**: Transfer GALA and launchpad tokens between wallets with EIP-712 signatures
- **User Operations**: Portfolio management, token balances, and account management
- **Comment System**: Post and retrieve comments on token pools
- **Price History**: Fetch historical price data for DEX tokens with pagination (Node.js only, requires MySQL)
- **Comprehensive Validation**: Input validation and error handling for all operations
- **Multi-Environment Support**: Production, staging, and custom backend URLs
## Installation
### NPM
```bash
npm install @gala-chain/launchpad-sdk
```
### Yarn
```bash
yarn add @gala-chain/launchpad-sdk
```
### Peer Dependencies
This SDK requires the following peer dependencies to be installed:
```bash
npm install ethers@^6.15.0 @gala-chain/api@^2.4.3 @gala-chain/connect@^2.4.3 socket.io-client@^4.8.1 axios@^1.12.2 bignumber.js@^9.1.2 zod@^3.25.76
```
**Or with yarn:**
```bash
yarn add ethers@^6.15.0 @gala-chain/api@^2.4.3 @gala-chain/connect@^2.4.3 socket.io-client@^4.8.1 axios@^1.12.2 bignumber.js@^9.1.2 zod@^3.25.76
```
**All peer dependencies are required** - this includes `socket.io-client` which is needed for transaction verification via WebSocket.
## Module Formats
The SDK is distributed in **three module formats** to support both modern and legacy projects:
### ESM (ES Modules) - Primary Format
**For modern bundlers and Node.js 16+:**
```typescript
import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk';
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
```
**When to use:**
- ✅ React, Vue, Svelte, Angular applications
- ✅ Next.js, Nuxt, SvelteKit
- ✅ Vite, Webpack, esbuild bundlers
- ✅ Modern Node.js projects with `"type": "module"`
### CommonJS - Legacy Support
**For CommonJS projects and older Node.js environments:**
```javascript
const { createLaunchpadSDK } = require('@gala-chain/launchpad-sdk');
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
```
**When to use:**
- ✅ Legacy Node.js projects with CommonJS modules
- ✅ Older tooling that doesn't support ESM
- ✅ Express.js, Nest.js (CommonJS mode)
- ✅ Projects without build tools
### UMD (Universal Module Definition) - Browser Legacy
**For browser globals and legacy environments:**
```html
<script src="node_modules/@gala-chain/launchpad-sdk/dist/index.js"></script>
<script>
const sdk = window.GalaLaunchpadSDK.createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
</script>
```
**When to use:**
- ✅ Direct browser `<script>` tags
- ✅ Older browser environments
- ✅ CDN delivery
### Module Resolution
Node.js automatically selects the correct module format based on your project:
| Project Type | Method | Format Used | File |
|---|---|---|---|
| ESM Module | `import` | ESM | `dist/index.esm.js` |
| CommonJS | `require()` | CommonJS | `dist/index.cjs.js` |
| Legacy Tools | Direct Include | UMD | `dist/index.js` |
**No configuration needed** - Node.js and bundlers automatically select the optimal format via the package exports field!
## AI Agent Integration
### For Claude Desktop Users
Install the MCP server to enable Claude to interact with Gala Launchpad directly:
```bash
claude mcp add "galachain-launchpad" -- env PRIVATE_KEY=<YOUR_PRIVATE_KEY> ENVIRONMENT=development npx -y @gala-chain/launchpad-mcp-server@latest
```
**Environment Variables:**
- `PRIVATE_KEY` - Your wallet private key (required)
- `ENVIRONMENT` - Backend environment: `development` | `production` (default: development)
- `DEBUG` - Enable debug logging: `true` | `false` (default: false)
- `TIMEOUT` - Request timeout in milliseconds (default: 30000)
**Features**: 50 tools + 14 slash commands for complete Gala Launchpad operations
See: [MCP Server Documentation](../../mcp-server/README.md)
**Try slash commands** (MCP v1.4.0+):
```
/galachain-launchpad:analyze-token tokenName=anime
/galachain-launchpad:portfolio
/galachain-launchpad:buy-tokens tokenName=anime galaAmount=100
```
### For AI Developers
Need help with SDK integration, trading bots, or MCP server development?
Ask **[@agent-galachain-launchpad-developer](../../@agent-galachain-launchpad-developer.md)** - a specialized AI agent with expertise in:
- Complete SDK API (45 methods)
- Trading patterns and DeFi best practices
- MCP server architecture
- Error handling strategies
- Performance optimization
**Full Integration Guide**: [AI Agent Guide](./docs/AI-AGENT-GUIDE.md)
## Quick Start
### Using Helper Functions (Recommended)
```typescript
import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk';
// Auto-detecting SDK creation (easiest method)
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic' // Auto-detects format!
});
// Clean, direct result access - All methods use options objects
// Pool Management - Direct result properties
const pools = await sdk.fetchPools({ type: 'recent', limit: 10 });
console.log(`Found ${pools.total} pools across ${pools.totalPages} pages`);
console.log(`Current page: ${pools.page}, Has next: ${pools.hasNext}`);
const badges = await sdk.fetchTokenBadges('dragnrkti');
console.log(`Volume badges: ${badges.volumeBadges.length}`);
console.log(`Engagement badges: ${badges.engagementBadges.length}`);
const details = await sdk.fetchPoolDetails('dragnrkti');
console.log(`Sale status: ${details.saleStatus}`);
console.log(`Native token quantity: ${details.nativeTokenQuantity}`);
// Price Calculations - Direct amount access
const buyAmount = await sdk.calculateBuyAmount({
tokenName: 'dragnrkti',
amount: '1', // 1 GALA
type: 'native'
});
console.log(`Buy amount: ${buyAmount.amount}`);
console.log(`Transaction fee: ${buyAmount.transactionFee}`);
// Trading Operations - Required expectedAmount and slippageToleranceFactor
const buyResult = await sdk.buy({
tokenName: 'dragnrkti',
amount: '1',
type: 'native',
expectedAmount: buyAmount.amount, // Required: from calculation
slippageToleranceFactor: 0.05 // Required: decimal format (5% slippage)
});
console.log(`Transaction ID: ${buyResult.transactionId}`);
// Data & Analytics - Clean pagination
const trades = await sdk.fetchTrades({ tokenName: 'dragnrkti' });
console.log(`Found ${trades.total} trades`);
console.log(`Page ${trades.page} of ${trades.totalPages}`);
trades.trades.forEach(trade => {
console.log(`Trade: ${trade.tradeType} ${trade.tokenAmount} at ${trade.createdAt.toISOString()}`);
});
const comments = await sdk.fetchComments({ tokenName: 'dragnrkti' });
console.log(`${comments.total} comments found`);
// User Operations - Direct balance access
const galaBalance = await sdk.fetchGalaBalance();
console.log(`GALA Balance: ${galaBalance.balance}`);
console.log(`Last updated: ${galaBalance.lastUpdated.toISOString()}`);
const tokenBalance = await sdk.fetchTokenBalance({
tokenName: 'dragnrkti',
address: sdk.getAddress()
});
console.log(`Token balance: ${tokenBalance.quantity}`);
console.log(`USD value: $${tokenBalance.holdingPriceUsd}`);
// Profile - Direct user data
const profile = await sdk.fetchProfile();
console.log(`Profile name: ${profile.fullName || 'Not set'}`);
// URL Utilities - Generate frontend URLs
const tokenUrl = sdk.getUrlByTokenName('dragnrkti');
console.log(`View token: ${tokenUrl}`);
// Output: https://lpad-frontend-test1.defi.gala.com/buy-sell/dragnrkti
```
## Auto-Pagination Feature
The SDK now supports automatic pagination for pool fetching with three powerful modes:
### Three Pagination Modes
```typescript
import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk';
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
// MODE 1: Single Page (backward compatible)
// Limit <= 20: Single API call
const recent = await sdk.fetchPools({ type: 'recent', limit: 20 });
console.log(`Fetched ${recent.pools.length} pools in one request`);
// MODE 2: Multi-Page Auto-Fetch
// Limit > 20: Automatic concurrent multi-page fetching
const large = await sdk.fetchPools({ type: 'popular', limit: 100 });
console.log(`Fetched ${large.pools.length} pools across multiple pages`);
// Internally fetches 5 pages concurrently: 20+20+20+20+20 = 100 pools
// MODE 3: Infinite Fetch
// Limit = 0: Fetches ALL available pools
const all = await sdk.fetchPools({ limit: 0 });
console.log(`Fetched all ${all.pools.length} pools from the platform`);
// Convenience method for "fetch all" pattern
const allRecent = await sdk.fetchAllPools({ type: 'recent' });
console.log(`Total pools: ${allRecent.total}`);
```
### Concurrency Configuration
The SDK uses `MAX_CONCURRENT_POOL_FETCHES` to control parallel API requests:
```typescript
import { MAX_CONCURRENT_POOL_FETCHES } from '@gala-chain/launchpad-sdk';
console.log(`SDK fetches up to ${MAX_CONCURRENT_POOL_FETCHES} pages concurrently`);
// Output: "SDK fetches up to 5 pages concurrently"
```
**Default**: 5 concurrent requests
**Benefit**: Balances speed with API rate limits
### Performance Benefits
| Scenario | Pages Fetched | Network Calls | Time (Sequential) | Time (Concurrent) | Improvement |
|----------|---------------|---------------|-------------------|-------------------|-------------|
| 20 pools | 1 page | 1 call | ~200ms | ~200ms | No change |
| 100 pools | 5 pages | 5 calls | ~1000ms | ~200ms | 5x faster |
| 500 pools | 25 pages | 25 calls | ~5000ms | ~1000ms | 5x faster |
| All pools (1000+) | 50+ pages | 50+ calls | ~10,000ms | ~2000ms | 5x faster |
### When to Use Each Mode
**Single Page (limit <= 20)**
- Quick queries
- UI pagination with next/previous buttons
- When you only need recent results
**Multi-Page (limit > 20)**
- Analytics dashboards
- Bulk operations on specific token counts
- When you know how many results you need
**Infinite (limit = 0 or fetchAllPools())**
- Complete market scans
- Full portfolio analysis
- Trading bot initialization
- Data exports and backups
### Example: Market Scanner
```typescript
async function scanEntireMarket() {
// Fetch all pools at once (auto-pagination handles everything)
const allPools = await sdk.fetchAllPools({ type: 'popular' });
console.log(`Scanning ${allPools.total} pools...`);
// Filter for interesting opportunities
const highVolume = allPools.pools.filter(pool =>
parseFloat(pool.volumeGala) > 10000
);
console.log(`Found ${highVolume.length} high-volume pools`);
return highVolume;
}
```
### New Methods
**fetchAllPools(options?)**
Convenience method that automatically fetches all available pools:
```typescript
// Fetch all recent pools
const allRecent = await sdk.fetchAllPools({ type: 'recent' });
// Fetch all pools matching search
const dragons = await sdk.fetchAllPools({ search: 'dragon' });
// Fetch specific token across all results
const specific = await sdk.fetchAllPools({ tokenName: 'anime' });
// Equivalent to fetchPools({ limit: 0 })
const all = await sdk.fetchAllPools();
```
### Manual SDK Creation (Alternative)
```typescript
import { Wallet } from 'ethers';
import { LaunchpadSDK } from '@gala-chain/launchpad-sdk';
// Create wallet manually
const wallet = new Wallet(process.env.PRIVATE_KEY);
// Initialize SDK
const sdk = new LaunchpadSDK({
wallet: wallet,
baseUrl: 'https://lpad-backend-dev1.defi.gala.com',
timeout: 30000,
debug: false
});
// Same clean API available
const pools = await sdk.fetchPools({ type: 'recent' });
console.log(`${pools.total} pools found`);
```
## Complete Example: Trading Flow with Clean Results
```typescript
import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk';
// 1. Create SDK with auto-detection
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
// 2. Check available pools - direct access to results
const pools = await sdk.fetchPools({
type: 'recent',
limit: 10
});
console.log(`Found ${pools.total} pools across ${pools.totalPages} pages`);
pools.pools.forEach(pool => {
console.log(`Pool: ${pool.tokenName} created at ${pool.createdAt}`);
});
// 3. Get price quote - direct amount access
const quote = await sdk.calculateBuyAmount({
tokenName: 'tinyevil',
amount: '100',
type: 'native'
});
console.log(`Buying 100 GALA worth will get you: ${quote.amount} TINYEVIL`);
console.log(`Transaction fee: ${quote.transactionFee} GALA`);
console.log(`Reverse bonding curve fee: ${quote.reverseBondingCurveFee} GALA`);
// 4. Execute trade with slippage protection - requires expectedAmount
const buyResult = await sdk.buy({
tokenName: 'tinyevil',
amount: '100',
type: 'native',
expectedAmount: quote.amount, // Required: from calculation above
slippageToleranceFactor: 0.05 // Required: decimal format for 5% slippage
});
console.log(`Transaction submitted: ${buyResult.transactionId}`);
// 5. Check trade history - clean pagination
const trades = await sdk.fetchTrades({ tokenName: 'tinyevil' });
console.log(`Found ${trades.total} trades on page ${trades.page}`);
console.log(`Has more pages: ${trades.hasNext}`);
trades.trades.forEach(trade => {
console.log(`${trade.tradeType}: ${trade.tokenAmount} at ${trade.createdAt.toISOString()}`);
});
// 6. Post a comment about your trade
const comment = await sdk.postComment({
tokenName: 'tinyevil',
content: 'Just bought some tokens! Great project!'
});
console.log(`Comment posted with ID: ${comment.id}`);
// 7. Check your balance - direct balance access
const galaBalance = await sdk.fetchGalaBalance();
console.log(`GALA Balance: ${galaBalance.balance}`);
console.log(`Decimals: ${galaBalance.decimals}`);
console.log(`Last updated: ${galaBalance.lastUpdated.toISOString()}`);
const tokenBalance = await sdk.fetchTokenBalance({
tokenName: 'tinyevil',
address: sdk.getAddress()
});
console.log(`TINYEVIL Balance: ${tokenBalance.quantity}`);
console.log(`USD Value: $${tokenBalance.holdingPriceUsd}`);
console.log(`GALA Value: ${tokenBalance.holdingPriceGala} GALA`);
console.log(`Finalized: ${tokenBalance.isFinalized}`);
```
## Transfer Operations
Transfer GALA and launchpad tokens between wallets with EIP-712 signatures:
```typescript
import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk';
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
// Transfer GALA tokens - direct result access
const galaTransfer = await sdk.transferGala({
recipientAddress: 'eth|1234567890abcdef1234567890abcdef12345678', // or 0x format
amount: '1', // 1 GALA
uniqueKey: 'galaconnect-operation-my-transfer-123' // Optional for idempotency
});
console.log(`GALA Transfer ID: ${galaTransfer.transactionId}`);
console.log(`Status: ${galaTransfer.status}`);
// Transfer launchpad tokens - direct result access
const tokenTransfer = await sdk.transferToken({
to: '0x9876543210fedcba9876543210fedcba98765432', // or eth| format
tokenName: 'tinyevil',
amount: '1000000', // Token amount in smallest unit
uniqueKey: 'galaconnect-operation-token-transfer-456' // Optional for idempotency
});
console.log(`Token Transfer ID: ${tokenTransfer.transactionId}`);
console.log(`Status: ${tokenTransfer.status}`);
```
### Transfer Features
- **EIP-712 Signatures**: Secure blockchain transactions
- **Address Format Handling**: Supports both `0x` and `eth|` formats
- **Idempotency**: Optional unique keys prevent duplicate transfers (must use `galaswap-operation-` or `galaconnect-operation-` prefix)
- **Comprehensive Validation**: Amount limits, address formats, token names, unique key formats
- **GalaChain Integration**: Direct transfers via GalaChain gateway
- **Error Handling**: Detailed error types for different failure scenarios
## Multi-Wallet Support
The SDK supports **per-operation wallet overrides** for testing multi-wallet workflows without creating new SDK instances. This is ideal for:
- Testing trading scenarios with multiple wallets
- Building multi-user applications
- Simulating different user behaviors
- Creating automated trading bots
### Private Key Override Pattern
All signing operations accept an optional `privateKey` parameter to use a different wallet for that specific operation:
```typescript
import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk';
// Create SDK with your main wallet
const sdk = createLaunchpadSDK({
wallet: 'your-main-private-key'
});
// Different wallet's private key (must be in '0x' + 64 hex format)
const busterPrivateKey = '0x1234567890abcdef...'; // Buster's wallet
// 1. Send GALA from main wallet to Buster
await sdk.transferGala({
recipientAddress: '0xBusterAddress...',
amount: '1000'
// Uses main SDK wallet (no privateKey override)
});
// 2. Have Buster buy tokens using his own wallet
const buyResult = await sdk.buy({
tokenName: 'tinyevil',
amount: '100',
type: 'native',
expectedAmount: '500000',
slippageToleranceFactor: 0.05,
privateKey: busterPrivateKey // Override to use Buster's wallet
});
// 3. Have Buster post a comment
await sdk.postComment({
tokenName: 'tinyevil',
content: 'Great buy!',
privateKey: busterPrivateKey // Buster posts the comment
});
// 4. Main wallet continues operations normally
const mainWalletBalance = await sdk.fetchGalaBalance();
// Uses main SDK wallet address
```
### Supported Operations with Private Key Override
All signing operations support the `privateKey` parameter:
**Trading Operations:**
- `buy(options)` - Buy tokens with different wallet
- `sell(options)` - Sell tokens with different wallet
**Token Creation:**
- `launchToken(data)` - Create token from different wallet
- `uploadTokenImage(options)` - Upload image for token
**Transfer Operations:**
- `transferGala(options)` - Transfer GALA from different wallet
- `transferToken(options)` - Transfer tokens from different wallet
**Social & Profile:**
- `postComment(options)` - Post comment from different wallet
- `updateProfile(data)` - Update profile for different wallet
- `uploadProfileImage(options)` - Upload profile image for different wallet
### Complete Multi-Wallet Example
```typescript
import { createLaunchpadSDK, createWallet } from '@gala-chain/launchpad-sdk';
// Main SDK instance
const sdk = createLaunchpadSDK({
wallet: 'your-main-private-key'
});
// Create a test wallet for "Buster"
const busterWallet = createWallet(); // Random wallet
const busterPrivateKey = busterWallet.privateKey;
const busterAddress = busterWallet.address;
console.log(`Buster's address: ${busterAddress}`);
// 1. Fund Buster with GALA from main wallet
await sdk.transferGala({
recipientAddress: busterAddress,
amount: '1000'
});
// 2. Send Buster some tokens from main wallet
await sdk.transferToken({
to: busterAddress,
tokenName: 'tinyevil',
amount: '10000'
});
// 3. Have Buster send some tokens back to main wallet
await sdk.transferToken({
to: sdk.getEthereumAddress(), // Main wallet address
tokenName: 'tinyevil',
amount: '5000',
privateKey: busterPrivateKey // Buster's wallet signs
});
// 4. Have Buster buy more tokens
const buyQuote = await sdk.calculateBuyAmount({
tokenName: 'tinyevil',
amount: '100',
type: 'native'
});
await sdk.buy({
tokenName: 'tinyevil',
amount: '100',
type: 'native',
expectedAmount: buyQuote.amount,
slippageToleranceFactor: 0.05,
privateKey: busterPrivateKey // Buster buys
});
// 5. Have Buster sell some tokens
const sellQuote = await sdk.calculateSellAmount({
tokenName: 'tinyevil',
amount: '50',
type: 'native'
});
await sdk.sell({
tokenName: 'tinyevil',
amount: '50',
type: 'native',
expectedAmount: sellQuote.amount,
slippageToleranceFactor: 0.05,
privateKey: busterPrivateKey // Buster sells
});
// 6. Check final balances for both wallets
const mainBalance = await sdk.fetchGalaBalance(); // Main wallet
const busterBalance = await sdk.fetchGalaBalance(busterAddress); // Buster's wallet
console.log(`Main wallet: ${mainBalance.balance} GALA`);
console.log(`Buster wallet: ${busterBalance.balance} GALA`);
```
### Private Key Format Requirements
The `privateKey` parameter must be a string in the format:
- **Format**: `'0x' + 64 hexadecimal characters`
- **Example**: `'0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'`
- **Invalid**: Raw hex without '0x' prefix, mnemonic phrases, addresses
```typescript
// ✅ Valid private key formats
const validKey1 = '0x' + 'a'.repeat(64); // Correct format
const validKey2 = wallet.privateKey; // From ethers.js Wallet
// ❌ Invalid formats (will throw validation error)
const invalidKey1 = 'a'.repeat(64); // Missing '0x' prefix
const invalidKey2 = 'word1 word2 ... word24'; // Mnemonic not accepted
const invalidKey3 = '0x123'; // Too short
```
## Available Methods & Result Types
### **Fetch Operations**
```typescript
// Pool Management
fetchPools(options?): Promise<PoolsResult>
// Returns: { pools, page, limit, total, totalPages, hasNext, hasPrevious }
// Supports auto-pagination: limit <= 20 (single page), limit > 20 (multi-page), limit = 0 (all pools)
fetchAllPools(options?): Promise<PoolsResult>
// Returns: { pools, page, limit, total, totalPages, hasNext, hasPrevious }
// Convenience method that fetches ALL pools (equivalent to fetchPools({ limit: 0 }))
fetchTokenDistribution(tokenName): Promise<TokenDistributionResult>
// Returns: { holders, totalSupply, totalHolders, lastUpdated }
fetchTokenBadges(tokenName): Promise<TokenBadgesResult>
// Returns: { volumeBadges, engagementBadges }
fetchPoolDetails(tokenName): Promise<PoolDetailsData>
// Returns: { basePrice, maxSupply, saleStatus, nativeTokenQuantity, ... }
fetchVolumeData(options): Promise<GraphDataResult>
// Returns: { dataPoints }
// Trade & User Data
fetchTrades(options): Promise<TradesResult>
// Returns: { trades, page, limit, total, totalPages, hasNext, hasPrevious }
fetchGalaBalance(address?): Promise<GalaBalanceInfo>
// Returns: { userAddress, balance, decimals, lastUpdated }
fetchTokenBalance(options): Promise<TokenBalanceInfo>
// Returns: { quantity, holdingPriceUsd, holdingPriceGala, isFinalized, ... }
fetchComments(options): Promise<CommentsResult>
// Returns: { comments, page, limit, total, totalPages, hasNext, hasPrevious }
fetchProfile(address?): Promise<UserProfile>
// Returns: { fullName, profileImage, address, ... }
fetchLaunchTokenFee(): Promise<number>
// Returns: Current GALA fee required to launch a new token (e.g., 0.001)
```
### **Calculate Operations**
```typescript
// Price Calculations
calculateBuyAmount(options): Promise<AmountCalculationResult>
// Returns: { amount, reverseBondingCurveFee, transactionFee }
calculateSellAmount(options): Promise<AmountCalculationResult>
// Returns: { amount, reverseBondingCurveFee, transactionFee }
calculateInitialBuyAmount(options): Promise<AmountCalculationResult>
// Returns: { amount, reverseBondingCurveFee, transactionFee }
calculateBuyAmountForGraduation(tokenName): Promise<AmountCalculationResult>
// Returns: { amount, reverseBondingCurveFee, transactionFee }
// Calculates exact GALA cost to buy all remaining tokens and graduate pool
// Local Calculations (Client-Side, No Network)
calculateBuyAmountLocal(options): Promise<AmountCalculationResult>
// Options: { tokenName, amount, type: 'native' | 'exact' }
// Returns: { amount, reverseBondingCurveFee: '0', transactionFee, gasFee }
// Instant buy calculation using local bonding curve formulas
calculateSellAmountLocal(options): Promise<AmountCalculationResult>
// Options: { tokenName, amount, type: 'native' | 'exact', maxSupply, minFeePortion, maxFeePortion }
// Returns: { amount, reverseBondingCurveFee, transactionFee, gasFee }
// Instant sell calculation with reverse bonding curve fees
// External Calculations (GalaChain Network)
calculateBuyAmountExternal(options): Promise<AmountCalculationResult>
// Explicit external calculation wrapper (same as calculateBuyAmount)
calculateSellAmountExternal(options): Promise<AmountCalculationResult>
// Explicit external calculation wrapper (same as calculateSellAmount)
// Note: Pass `calculateAmountMode: 'local' | 'external'` to override SDK default mode
// Price History Operations (MySQL-based, Node.js only)
fetchPriceHistory(options): Promise<PriceHistoryResult>
// Options: { tokenId, from?, to?, sortOrder?, page?, limit? }
// Returns: { snapshots, page, limit, total, totalPages, hasNext, hasPrevious }
// Fetches paginated historical price snapshots from MySQL database
fetchAllPriceHistory(options): Promise<PriceHistoryResult>
// Options: { tokenId, from?, to?, sortOrder? } (no pagination params)
// Returns: All matching snapshots with total count
// Convenience method with automatic pagination (returns ALL snapshots)
fetchPrices(options?): Promise<PricesResult>
// Options: { page?, limit?, sortByType? }
// Returns: { snapshots, page, limit, total, totalPages, hasNext, hasPrevious }
// Fetches latest price for each unique token (paginated)
fetchAllPrices(): Promise<PricesResult>
// No parameters
// Returns: All latest prices combined in single result
// Convenience method with automatic pagination (returns ALL latest prices)
// Note: Price history methods require MySQL connection string in SDK config
// See MySQL Configuration section below for setup details
```
## Performance Optimization
### Reusing Pool Data to Avoid Redundant Network Calls
Methods that internally use `calculateBuyAmount`/`calculateSellAmount` now support optional `calculateAmountMode` and `currentSupply` parameters for performance optimization. This allows you to:
1. **Fetch pool details once** using `fetchPoolDetailsForCalculation`
2. **Reuse `currentSupply`** across multiple calculations
3. **Eliminate redundant network calls** with local mode calculations
4. **Get instant results** when real-time precision isn't required
### Supported Methods
The following methods accept optional performance parameters:
- `fetchLaunchpadTokenSpotPrice(options)` - Pass `calculateAmountMode` and/or `currentSupply`
- `calculateBuyAmountForGraduation(options)` - Pass `calculateAmountMode` and/or `currentSupply`
- `graduateToken(options)` - Pass `calculateAmountMode` and/or `currentSupply`
### Using CALCULATION_MODES Constant
```typescript
import { createLaunchpadSDK, CALCULATION_MODES } from '@gala-chain/launchpad-sdk';
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
// Use type-safe calculation mode constants
console.log(CALCULATION_MODES.LOCAL); // 'local'
console.log(CALCULATION_MODES.EXTERNAL); // 'external'
```
### Basic Optimization Pattern
```typescript
import { createLaunchpadSDK, CALCULATION_MODES } from '@gala-chain/launchpad-sdk';
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
const tokenName = 'tinyevil';
// ❌ WITHOUT OPTIMIZATION (3 network calls)
const spotPrice1 = await sdk.fetchLaunchpadTokenSpotPrice(tokenName);
// → Fetches pool details internally (call #1)
const graduation1 = await sdk.calculateBuyAmountForGraduation(tokenName);
// → Fetches pool details internally (call #2)
const graduationResult1 = await sdk.graduateToken({ tokenName });
// → Fetches pool details internally (call #3)
// ✅ WITH OPTIMIZATION (1 network call + instant local calculations)
// Step 1: Fetch pool details once
const poolDetails = await sdk.fetchPoolDetailsForCalculation(tokenName);
const currentSupply = poolDetails.currentSupply; // Pre-computed with full precision
// Step 2: Reuse currentSupply for instant local calculations
const spotPrice2 = await sdk.fetchLaunchpadTokenSpotPrice({
tokenName,
calculateAmountMode: CALCULATION_MODES.LOCAL,
currentSupply
});
// → Uses local bonding curve formulas (instant, no network call)
const graduation2 = await sdk.calculateBuyAmountForGraduation({
tokenName,
calculateAmountMode: CALCULATION_MODES.LOCAL,
currentSupply
});
// → Uses local calculation (instant, no network call)
// Step 3: Graduate with optimized calculation
const graduationResult2 = await sdk.graduateToken({
tokenName,
calculateAmountMode: CALCULATION_MODES.LOCAL,
currentSupply,
slippageToleranceFactor: 0.01
});
// → Skips redundant pool fetch, uses local calculation
```
### Performance Comparison
| Pattern | Network Calls | Speed | Use Case |
|---------|--------------|-------|----------|
| **Without Optimization** | 3 calls | ~600-900ms | One-off operations |
| **With Optimization** | 1 call | ~200ms | Batch operations, price discovery |
| **Reduction** | **66% fewer calls** | **~70% faster** | |
### Complete Optimization Example
```typescript
import { createLaunchpadSDK, CALCULATION_MODES } from '@gala-chain/launchpad-sdk';
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
async function optimizedPoolAnalysis(tokenName: string) {
console.time('Optimized Analysis');
// 1. Fetch pool details once (only network call needed)
const poolDetails = await sdk.fetchPoolDetailsForCalculation(tokenName);
const {
currentSupply,
maxSupply,
reverseBondingCurveMinFeeFactor,
reverseBondingCurveMaxFeeFactor
} = poolDetails;
// 2. Get spot price with local calculation (instant)
const spotPrice = await sdk.fetchLaunchpadTokenSpotPrice({
tokenName,
calculateAmountMode: CALCULATION_MODES.LOCAL,
currentSupply
});
console.log(`Spot price: $${spotPrice.usdPrice.toFixed(6)}`);
// 3. Calculate graduation cost with local calculation (instant)
const graduationCost = await sdk.calculateBuyAmountForGraduation({
tokenName,
calculateAmountMode: CALCULATION_MODES.LOCAL,
currentSupply
});
console.log(`Graduation cost: ${graduationCost.amount} GALA`);
// 4. Simulate multiple buy scenarios (all instant)
const buyAmounts = ['10', '100', '1000'];
for (const amount of buyAmounts) {
const buyCalc = await sdk.calculateBuyAmount({
tokenName,
amount,
type: 'native',
mode: CALCULATION_MODES.LOCAL, // Can also use 'mode' alias
currentSupply
});
console.log(`Buying ${amount} GALA gets you: ${buyCalc.amount} tokens`);
}
// 5. Simulate multiple sell scenarios (all instant)
const sellAmounts = ['10', '100', '1000'];
for (const amount of sellAmounts) {
const sellCalc = await sdk.calculateSellAmountLocal({
tokenName,
amount,
type: 'native',
maxSupply,
reverseBondingCurveMinFeeFactor,
reverseBondingCurveMaxFeeFactor
});
console.log(`Selling ${amount} GALA worth gets you: ${sellCalc.amount} GALA`);
}
console.timeEnd('Optimized Analysis');
// Output: Optimized Analysis: ~200-300ms (vs ~2-3 seconds without optimization)
}
optimizedPoolAnalysis('tinyevil');
```
### When to Use Optimization
**✅ Use optimization when:**
- Performing multiple calculations on the same token
- Building price discovery tools or analytics dashboards
- Running simulations or backtests
- Creating trading bots with frequent calculations
- Displaying real-time price feeds (use local mode for smooth updates)
**❌ Skip optimization when:**
- Performing a single calculation
- Requiring absolute precision from GalaChain network
- Token supply changes frequently between calls
### Local vs External Calculations
```typescript
// Local mode (client-side, instant, <0.01% difference from external)
const localCalc = await sdk.calculateBuyAmount({
tokenName: 'tinyevil',
amount: '100',
type: 'native',
mode: CALCULATION_MODES.LOCAL,
currentSupply: poolDetails.currentSupply
});
// External mode (GalaChain network, real-time, slower)
const externalCalc = await sdk.calculateBuyAmount({
tokenName: 'tinyevil',
amount: '100',
type: 'native',
mode: CALCULATION_MODES.EXTERNAL // or omit to use SDK default
});
// Accuracy comparison
const difference = Math.abs(
parseFloat(localCalc.amount) - parseFloat(externalCalc.amount)
);
const percentDiff = (difference / parseFloat(externalCalc.amount)) * 100;
console.log(`Difference: ${percentDiff.toFixed(4)}%`); // Typically < 0.01%
```
### SDK Configuration for Default Calculation Mode
```typescript
import { createLaunchpadSDK, CALCULATION_MODES } from '@gala-chain/launchpad-sdk';
// Configure SDK to use local calculations by default
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic',
config: {
calculateAmountMode: CALCULATION_MODES.LOCAL // Default to local mode
}
});
// All calculations will use local mode by default
const calc1 = await sdk.calculateBuyAmount({
tokenName: 'tinyevil',
amount: '100',
type: 'native'
// Uses LOCAL mode from SDK config
});
// Override per-call if needed
const calc2 = await sdk.calculateBuyAmount({
tokenName: 'tinyevil',
amount: '100',
type: 'native',
mode: CALCULATION_MODES.EXTERNAL // Override to external for this call
});
```
## Token Metadata Cache
The SDK includes an **intelligent metadata cache** that eliminates redundant API calls and enables instant local calculations. The cache stores immutable token metadata (reverse bonding curve fees, vault addresses, max supply) that never changes.
### How Cache Warming Works
**Opportunistic & Zero-Cost**: Cache warming happens automatically during normal SDK operations without any additional network requests. When you call `fetchPools()`, the SDK extracts and caches metadata from the pool data that was already fetched.
```typescript
import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk';
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
// Before fetching - cache is empty
let cacheInfo = sdk.getCacheInfo();
console.log('Cached tokens:', cacheInfo.totalTokens); // 0
// Fetch pools - automatically warms cache with RBC fees and vault addresses
await sdk.fetchPools({ type: 'recent', limit: 20 });
// After fetching - cache is warmed with 20 tokens
cacheInfo = sdk.getCacheInfo();
console.log('Cached tokens:', cacheInfo.totalTokens); // 20
console.log('Cache size:', (cacheInfo.cacheSize / 1024).toFixed(2), 'KB');
// Now local calculations are instant (no network calls required)
const calc = await sdk.calculateBuyAmountLocal({
tokenName: 'anime',
amount: '100',
type: 'native',
currentSupply: '500000'
});
console.log('Instant result:', calc.amount); // <1ms, used cached RBC fees
```
### Performance Benefits
**Dramatic Performance Improvements:**
| Operation | Without Cache | With Cache | Improvement |
|-----------|---------------|------------|-------------|
| Single calculation | ~200ms | <1ms | **200x faster** |
| 10 calculations | ~2000ms | <5ms | **400x faster** |
| Price discovery (50 tokens) | ~10,000ms | ~50ms | **200x faster** |
**Zero Network Overhead**: Cache warming extracts metadata from pool responses you're already receiving - no extra API calls required.
**Memory Efficient**:
- ~220 bytes per cached token (includes RBC fees + vault address)
- Max 10,000 tokens = ~2.5 MB total memory
- LRU eviction keeps memory bounded
### Cache Lifecycle
**Session Lifetime**:
- Cache persists for entire MCP server session (survives across conversations)
- For direct SDK usage, cache lifetime matches SDK instance lifetime
- Call `sdk.cleanup()` to clear cache and release resources
**LRU Eviction**:
- Maximum 10,000 tokens cached
- Least Recently Updated (LRU) tokens evicted when limit reached
- O(1) get/set/eviction using JavaScript Map insertion order
```typescript
// Cache automatically manages size
await sdk.fetchPools({ limit: 100 }); // Warms cache with 100 tokens
await sdk.fetchPools({ limit: 100 }); // Warms with 100 more tokens
await sdk.fetchPools({ limit: 100 }); // ... continues
// When 10,000 limit reached, oldest tokens are evicted automatically
const stats = sdk.getCacheInfo();
console.log('Total tokens:', stats.totalTokens); // Never exceeds 10,000
console.log('Oldest entry:', new Date(stats.oldestEntry).toISOString());
```
### Cache Management API
**Get Cache Statistics:**
```typescript
const stats = sdk.getCacheInfo();
console.log('Total tokens cached:', stats.totalTokens);
console.log('Memory usage:', stats.cacheSize, 'bytes');
console.log('Average per entry:', (stats.cacheSize / stats.totalTokens).toFixed(0), 'bytes');
console.log('Oldest entry:', new Date(stats.oldestEntry).toISOString());
```
**Clear Cache (Selective or Complete):**
```typescript
// Clear specific token
sdk.clearCache('anime');
console.log('Cleared anime from cache');
// Clear all tokens
sdk.clearCache();
console.log('Cleared entire cache');
// Verify cache is empty
const stats = sdk.getCacheInfo();
console.log('Tokens remaining:', stats.totalTokens); // 0
```
**Manual Cache Warming (Advanced):**
```typescript
// Manually warm cache from pool data (useful for custom caching scenarios)
sdk.warmCacheFromPoolData('mytoken', {
vaultAddress: 'service|Token$Unit$MYTOKEN$...',
reverseBondingCurveMinFeeFactor: 0.0,
reverseBondingCurveMaxFeeFactor: 0.5
});
// Cache is now warmed for local calculations
const calc = await sdk.calculateBuyAmountLocal({
tokenName: 'mytoken',
amount: '100',
type: 'native',
currentSupply: '1000000'
});
```
### Complete Cache Example
```typescript
import { createLaunchpadSDK, CALCULATION_MODES } from '@gala-chain/launchpad-sdk';
const sdk = createLaunchpadSDK({
wallet: 'your-private-key-or-mnemonic'
});
// 1. Warm cache by fetching pools
console.log('Warming cache...');
await sdk.fetchPools({ type: 'popular', limit: 50 });
// 2. Check cache statistics
const stats = sdk.getCacheInfo();
console.log(`Cache warmed with ${stats.totalTokens} tokens`);
console.log(`Memory: ${(stats.cacheSize / 1024).toFixed(2)} KB`);
// 3. Perform instant calculations using cached metadata
const tokens = ['anime', 'dragnrkti', 'rocketri'];
console.log('\nCalculating spot prices (instant, no network calls):');
console.time('Batch Calculations');
for (const token of tokens) {
// Get pool details once for this token
const poolDetails = await sdk.fetchPoolDetailsForCalculation(token);
// Multiple instant calculations using cached data
const [buy10, buy100, buy1000] = await Promise.all([
sdk.calculateBuyAmountLocal({
tokenName: token,
amount: '10',
type: 'native',
currentSupply: poolDetails.currentSupply
}),
sdk.calculateBuyAmountLocal({
tokenName: token,
amount: '100',
type: 'native',
currentSupply: poolDetails.currentSupply
}),
sdk.calculateBuyAmountLocal({
tokenName: token,
amount: '1000',
type: 'native',
currentSupply: poolDetails.currentSupply
})
]);
console.log(`${token}:`);
console.log(` 10 GALA → ${buy10.amount} tokens`);
console.log(` 100 GALA → ${buy100.amount} tokens`);
console.log(` 1000 GALA → ${buy1000.amount} tokens`);
}
console.timeEnd('Batch Calculations');
// Output: Batch Calculations: ~50-100ms (vs ~3-5 seconds without cache)
// 4. Clear cache when done (optional)
sdk.clearCache();
console.log('\nCache cleared');
```
### Cache Design Philosophy
**Immutable Data Only**: Only caches data that never changes:
- ✅ Reverse bonding curve fee factors (set at token creation)
- ✅ Vault addresses (permanent token identifiers)
- ✅ Max supply (bonding curve constant, typically 10M)
- ❌ Current supply (changes with every trade - fetched dynamically)
- ❌ Token balances (user-specific and dynamic)
**Zero-Cost Architecture**: No extra API calls required for cache warming. Metadata is extracted from responses you're already receiving during normal operations.
**Bounded Memory**: LRU eviction ensures cache never exceeds 10,000 tokens (~2.5 MB), making it safe for long-running applications.
**Smart Defaults**: Uses 10,000,000 as default max supply for tokens without explicit data (matches 99%+ of launchpad tokens).
### When to Use the Cache
**✅ Perfect for:**
- Price discovery and analytics dashboards
- Trading bots with frequent calculations
- Batch operations on multiple tokens
- Real-time price feeds and charts
- Simulation and backtesting tools
**❌ Not needed for:**
- Single one-off calculations
- Operations requiring absolute real-time precision
- Scenarios where current supply changes between calls
### Cache Warming Demo
Run the complete cache demo to see all features in action:
```bash
npm run demo-cache
```
The demo showcases:
- Opportunistic warming from `fetchPools()`
- Detailed warming from `fetchPoolDetailsForCalculation()`
- Token name normalization (case-insensitive)
- Cache hit performance (200x+ faster than network calls)
- Memory estimation accuracy
- LRU eviction behavior
- Clear cache operations
### **Trading Operations**
```typescript
// Buy/Sell Tokens
buy(options): Promise<TransactionResult>
// Options: { tokenName, amount, type, expectedAmount, slippageToleranceFactor }
// Returns: { transactionId, status, ... }
sell(options): Promise<TransactionResult>
// Options: { tokenName, amount, type, expectedAmount, slippageToleranceFactor }
// Returns: { transactionId, status, ... }
graduateToken(options): Promise<TransactionResult>
// Options: { tokenName, slippageToleranceFactor?, maxAcceptableReverseBondingCurveFeeSlippageFactor?, privateKey? }
// Returns: { transactionId, status, ... }
// One-step pool graduation: calculates cost and buys all remaining tokens
```
### **Content Operations**
```typescript
// Comments & Content
postComment(options): Promise<CommentResult>
// Returns: { id, content, createdAt, ... }
// Token Creation & Management
launchToken(data): Promise<LaunchTokenResult>
// Returns: { transactionId, status, ... }
uploadTokenImage(options): Promise<ImageUploadResult>
// Returns: { imageUrl, success, ... }
// Profile Management
updateProfile(data): Promise<ProfileUpdateResult>
// Returns: { success, data, ... }
uploadProfileImage(options): Promise<ImageUploadResult>
// Returns: { imageUrl, success, ... }
```
### **Validation & Utilities**
- `isTokenNameAvailable(tokenName: string): Promise<boolean>`
- `isTokenSymbolAvailable(symbol: string): Promise<boolean>`
- `isTokenGraduated(tokenName: string): Promise<boolean>` - Check if token completed bonding curve phase
- `getAddress(): string` - Get backend format address (eth|...)
- `getEthereumAddress(): string` - Get Ethereum format address (0x...)
- `getUrlByTokenName(tokenName: string): string` - Get frontend URL for token
- `resolveVaultAddress(tokenName: string): Promise<string>`
- `cleanup(): void` - Cleanup resources
## Configuration
### Constants
```typescript
import { MAX_CONCURRENT_POOL_FETCHES } from '@gala-chain/launchpad-sdk';
console.log(`SDK fetches up to ${MAX_CONCURRENT_POOL_FETCHES} pages concurrently`);
// Output: "SDK fetches up to 5 pages concurrently"
```
**MAX_CONCURRENT_POOL_FETCHES**
- **Type**: `number`
- **Value**: `5`
- **Purpose**: Controls concurrency for parallel page fetching in auto-pagination
- **Balances**: Speed vs API rate limits
- **Usage**: Exported constant for reference (not configurable at runtime)
### SDK Configuration
```typescript
interface LaunchpadSDKConfig {
wallet: Wallet; // ethers.js Wallet instance
baseUrl?: string; // Backend URL (default: dev environment)
galaChainBaseUrl?: string; // GalaChain gateway URL
bundleBaseUrl?: string; // Bundle service URL
webSocketUrl?: string; // WebSocket URL for monitoring
timeout?: number; // Request timeout (default: 30000ms)
debug?: boolean; // Enable debug logging
maxRetries?: number; // Retry attempts (default: 3)
retryDelay?: number; // Retry delay (default: 1000ms)
mysqlConnectionString?: string; // MySQL connection string for price history (Node.js only)
// Format: mysql://user:password@host:port/database
}
```
### MySQL Configuration (Price History)
To use the price history methods, you need to configure a MySQL connection string:
```typescript
import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk';
const sdk = createLaunchpadSDK({
wallet: 'your-private-key',
config: {
baseUrl: 'https://lpad-backend-dev1.defi.gala.com',
mysqlConnectionString: 'mysql://user:password@localhost:3306/galachain'
}
});
// 1. Fetch historical price snapshots (paginated)
const priceHistory = await sdk.fetchPriceHistory({
tokenId: 'Token|Unit|GUSDC|eth:9401b171307bE656f00F9e18DF756643FD3a91dE', // String format
from: new Date('2024-01-01'),
to: new Date('2024-01-31'),
sortOrder: 'DESC',
page: 1,
limit: 20
});
console.log(`Found ${priceHistory.snapshots.length} snapshots`);
console.log(`Total: ${priceHistory.total}, Page ${priceHistory.page} of ${priceHistory.totalPages}`);
// 2. Fetch ALL historical price snapshots (auto-paginated)
const allHistory = await sdk.fetchAllPriceHistory({
tokenId: { // Object format also supported
collection: 'Token',
category: 'Unit',
type: 'GUSDC',
additionalKey: 'eth:9401b171307bE656f00F9e18DF756643FD3a91dE'
},
from: new Date('2024-01-01'),
to: new Date('2024-01-31')
});
console.log(`Total snapshots: ${allHistory.total}`);
// 3. Fetch latest prices for all tokens (paginated)
const latestPrices = await sdk.fetchPrices({
page: 1,
limit: 20,
sortByType: 'ASC' // Optional: sort alphabetically by token type
});
console.log(`Found ${latestPrices.snapshots.length} tokens with prices`);
// 4. Fetch all latest prices (auto-paginated)
const allLatestPrices = await sdk.fetchAllPrices();
console.log(`Total tokens with prices: ${allLatestPrices.total}`);
```
**Token Identification Formats:**
```typescript
// String format (pipe-delimited) - simpler
tokenId: 'Token|Unit|GUSDC|eth:9401b171307bE656f00F9e18DF756643FD3a91dE'
// Object format (explicit) - for clarity
tokenId: {
collection: 'Token',
category: 'Unit',
type: 'GUSDC',
additionalKey: 'eth:9401b171307bE656f00F9e18DF756643FD3a91dE'
}
```
**Environment Configuration:**
```bash
# Set in .env or pass to SDK config
PRICE_SERVICE_MYSQL_CONNECTION_STRING=mysql://user:password@localhost:3306/galachain
```
**Requirements:**
- Node.js environment (browser not supported)
- MySQL server with `price_snapshots` table
- Connection pooling is automatic (default 5 concurrent connections)
### Security Considerations
⚠️ **Credential Management:**
- Store MySQL connection strings in environment variables, NOT in code
- Use restrictive file permissions on `.env` files (recommended: `0600`)
- Never log or expose connection strings in debug output
- For production, consider using credential providers (AWS Secrets Manager, Azure Key Vault, etc.)
⚠️ **Input Validation:**
- TokenClassKey fields are validated with a whitelist pattern to prevent SQL injection
- Only alphanumeric characters plus dots (.), colons (:), hyphens (-), and underscores (_) are allowed
- Fields are limited to 255 characters maximum
⚠️ **Database Security:**
- Ensure MySQL is behind a firewall and not exposed to the internet
- Use strong passwords and rotate them regularly
- Consider using SSL/TLS for MySQL connections in production
- Create a dedicated dat