AI Agent Patterns for Gala Launchpad MCP Server
This guide provides AI agents with common workflows, gotchas, and best practices when using the galachain-launchpad MCP server.
Table of Contents
Common Workflows
1. Token Launch Workflow
Complete token creation from scratch:
// Step 1: Verify token name is available
gala_launchpad_check_token_name({
tokenName: 'mytoken'
})
// Response: { available: true, message: "Token name is available" }
// Step 2: Verify token symbol is available
gala_launchpad_check_token_symbol({
symbol: 'MTK'
})
// Response: { available: true, message: "Token symbol is available" }
// Step 3: Upload token image (optional, can use URL instead)
gala_launchpad_upload_token_image({
tokenName: 'mytoken',
imagePath: '/absolute/path/to/image.png'
})
// Response: { url: 'https://launchpad.galachain.com/uploads/mytoken.png' }
// Step 4: Launch the token
gala_launchpad_launch_token({
tokenName: 'mytoken',
tokenSymbol: 'MTK',
tokenDescription: 'My awesome token for the community',
tokenImage: 'https://launchpad.galachain.com/uploads/mytoken.png',
preBuyQuantity: '100', // Optional initial buy
websiteUrl: 'https://mytoken.com',
twitterUrl: 'https://twitter.com/mytoken'
})
// Response: { tokenName: 'mytoken', transactionId: '...' }
// Step 5: Get the frontend URL
gala_launchpad_get_url_by_token_name({
tokenName: 'mytoken'
})
// Response: { url: 'https://launchpad.galachain.com/token/mytoken' }
2. Trading Workflow (Buy Tokens)
Two-step process: Calculate → Execute
// Step 1: Calculate buy amount (REQUIRED FIRST STEP)
const calcResult = gala_launchpad_calculate_buy_amount({
tokenName: 'woohoo',
amount: '10', // Spending 10 GALA
type: 'native' // 'native' = GALA amount
})
// Response: {
// amount: '16843.7579794843252', // <- THIS is expectedAmount for buy()
// reverseBondingCurveFee: '0.059280156', // <- THIS is maxAcceptableReverseBondingCurveFee
// transactionFee: '0.00141090',
// gasFee: '1'
// }
// Step 2: Execute buy with calculated expectedAmount AND reverseBondingCurveFee
gala_launchpad_buy({
tokenName: 'woohoo',
amount: '10', // Same as Step 1
type: 'native', // Same as Step 1
expectedAmount: '16843.7579794843252', // <- Use result.amount from Step 1
maxAcceptableReverseBondingCurveFee: '0.059280156', // <- Use result.reverseBondingCurveFee from Step 1
slippageToleranceFactor: 0.05 // 5% slippage protection
})
// Response: { transactionId: '...', status: 'completed' }
// Step 3: Verify trade completed
gala_launchpad_fetch_trades({
tokenName: 'woohoo',
userAddress: 'eth|your-address',
pageSize: 1
})
⚠️ CRITICAL:
expectedAmountmust beresult.amountfrom calculate function, NOT your input amount!maxAcceptableReverseBondingCurveFeemust beresult.reverseBondingCurveFeefrom calculate function!
3. Trading Workflow (Sell Tokens)
Same two-step pattern:
// Step 1: Calculate sell amount
const calcResult = gala_launchpad_calculate_sell_amount({
tokenName: 'woohoo',
amount: '1000', // Selling 1000 tokens
type: 'exact' // 'exact' = exact token amount
})
// Response: {
// amount: '5.234567', // <- THIS is expectedAmount for sell()
// reverseBondingCurveFee: '2.617284', // <- THIS is maxAcceptableReverseBondingCurveFee
// transactionFee: '0.00523457',
// gasFee: '1'
// }
// Step 2: Execute sell with calculated expectedAmount AND reverseBondingCurveFee
gala_launchpad_sell({
tokenName: 'woohoo',
amount: '1000',
type: 'exact',
expectedAmount: '5.234567', // <- Use result.amount from Step 1
maxAcceptableReverseBondingCurveFee: '2.617284', // <- Use result.reverseBondingCurveFee from Step 1
slippageToleranceFactor: 0.05
})
4. Portfolio Management Workflow
Check balances and trading activity:
// Get GALA balance
gala_launchpad_fetch_gala_balance({
address: 'eth|your-address' // Optional, defaults to authenticated wallet
})
// Get specific token balance (optimized single-token lookup)
gala_launchpad_fetch_token_balance({
tokenName: 'woohoo',
address: 'eth|your-address'
})
// Get all tokens held (with filtering)
gala_launchpad_fetch_tokens_held({
address: 'eth|your-address',
tokenName: 'woohoo', // Optional exact match filter
pageSize: 20 // Max 20 for user operations
})
// Get all tokens created by user
gala_launchpad_fetch_tokens_created({
address: 'eth|your-address',
search: 'test', // Optional backend search; tokenName is exact-matched on the returned page
pageSize: 20
})
// Get trade history
gala_launchpad_fetch_trades({
tokenName: 'woohoo',
userAddress: 'eth|your-address',
tradeType: 'BUY', // Optional: 'BUY' or 'SELL'
pageSize: 20, // Max 20 for trade operations
sortOrder: 'DESC'
})
5. Token Lock/Unlock Workflow
Lock tokens for staking, escrow, or vesting:
// ============================================================================
// LOCK TOKENS - Basic staking (batch operation: tokens is always an array)
// ============================================================================
// Lock tokens (caller becomes lock authority by default)
gala_launchpad_lock_tokens({
tokens: [{ tokenName: 'anime', amount: '1000' }]
})
// Response: { transactionId: '...', status: 'completed' }
// ============================================================================
// LOCK TOKENS - Advanced options (escrow, vesting)
// ============================================================================
// Lock with custom authority (escrow pattern)
gala_launchpad_lock_tokens({
tokens: [{
tokenName: 'anime',
amount: '500',
lockAuthority: 'eth|1234...', // Escrow agent can unlock
name: 'escrow-order-001' // Identifier for matching during unlock
}]
})
// Lock with expiration (vesting/staking period)
gala_launchpad_lock_tokens({
tokens: [{
tokenName: 'anime',
amount: '10000',
name: 'vesting-q1-2025',
expires: 1743465600000 // April 1, 2025 timestamp (auto-unlock)
}]
})
// ============================================================================
// UNLOCK TOKENS - Release locked tokens (batch operation: tokens is always an array)
// ============================================================================
// Basic unlock (must be called by lock authority)
gala_launchpad_unlock_tokens({
tokens: [{ tokenName: 'anime', amount: '500' }]
})
// Response: { transactionId: '...', status: 'completed' }
// Unlock with name matching (for specific locks)
gala_launchpad_unlock_tokens({
tokens: [{ tokenName: 'anime', amount: '1000', name: 'escrow-order-001' }] // Match the lock name
})
⚠️ CRITICAL:
lockAuthoritydefaults to caller - only the authority can unlocknameparameter helps identify specific locks when unlockingexpirestimestamp enables auto-unlock after the specified time- Only the lock authority can call
unlock_tokens
6. Backend-Proxy Trading Quotes (Fast, No Chain Call)
Get instant quotes and fee info without hitting GalaChain:
These tools use backend-proxied endpoints with local bonding curve math. No GalaChain network round-trip — results are instant. Useful for UI price previews, quoting UIs, and pre-flight checks.
// Fetch current launchpad fee (cached 1 hour)
const fee = gala_launchpad_fetch_launchpad_fee()
// Response: 25 (number — fee in GALA)
// Fetch sale details for a token (cached 10 seconds)
const details = gala_launchpad_fetch_sale_details({ tokenName: 'anime' })
// Response: {
// maxSupply: '10000000',
// sellingTokenQuantity: '8500000',
// nativeTokenQuantity: '4250.5',
// saleStatus: 'ACTIVE',
// saleStartTime: undefined
// }
// Get a buy quote (NATIVE → MEME): how many tokens for 100 GALA?
const buyQuote = gala_launchpad_get_trade_quote({
tokenName: 'anime',
amount: '100', // 100 GALA to spend
type: 'NATIVE', // Input is GALA
method: 'IN', // Spending this amount
})
// Response: {
// amount: '51234.567', // tokens you will receive
// reverseBondingCurveFee: '0', // dynamic pool fee
// transactionFee: '0.001234',
// gasFee: '1'
// }
// Get a sell quote (MEME → NATIVE): how much GALA for 1000 tokens?
const sellQuote = gala_launchpad_get_trade_quote({
tokenName: 'anime',
amount: '1000', // 1000 tokens to sell
type: 'MEME', // Input is the meme token
method: 'IN', // Selling this amount
})
// Pre-mint quote during token creation (supply = 0 assumed)
const premintQuote = gala_launchpad_get_premint_quote({
amount: '500', // 500 GALA to spend at launch
})
// Response: {
// amount: '321000.123', // tokens you will receive at launch
// ...
// }
When to use backend-proxy tools vs chain-call tools:
| Scenario | Recommended Tool |
|---|---|
| Price preview / UI display | gala_launchpad_get_trade_quote (instant) |
| Pre-trade validation (accurate) | gala_launchpad_calculate_buy_amount (chain) |
| Token creation preview | gala_launchpad_get_premint_quote |
| Token sale status check | gala_launchpad_fetch_sale_details |
| Fee display | gala_launchpad_fetch_launchpad_fee |
7. Pool Analysis Workflow
Discover and analyze token pools:
// Fetch recent/trending pools
gala_launchpad_fetch_pools({
type: 'trending', // 'recent', 'trending', or 'user'
pageSize: 100 // Max 100 for pool operations
})
// Get detailed pool state
gala_launchpad_fetch_pool_details({
tokenName: 'woohoo'
})
// Get holder distribution
gala_launchpad_fetch_token_distribution({
tokenName: 'woohoo'
})
// Get volume data for charting
gala_launchpad_fetch_volume_data({
tokenName: 'woohoo',
resolution: '1h', // '1m', '5m', '15m', '1h', '4h', '1d'
from: '2024-01-01T00:00:00Z',
to: '2024-01-31T23:59:59Z'
})
8. GSwap DEX Swap Workflow (queued RequestTrade)
Quote, submit the queued request, inspect the applied result, and verify assets:
// Step 1: Get a fresh quote
const quote = gala_launchpad_get_swap_quote_exact_input({
fromToken: 'GALA',
toToken: 'GUSDC',
amount: '100',
})
// Step 2: Execute the queued RequestTrade; the tool waits for apply
const swap = gala_launchpad_execute_swap({
fromToken: 'GALA',
toToken: 'GUSDC',
inputAmount: '100',
estimatedOutput: quote.estimatedOutput,
feeTier: quote.feeTier,
slippageTolerance: 0.01,
})
// Step 3: Read the applied trade, not the queued submission, for execution details
const applied = swap.confirmation
console.log(applied.result) // token quantities, fee, and fee breakdown
// Step 4: Verify the resulting wallet assets
gala_launchpad_get_swap_user_assets({ walletAddress: 'eth|your-address' })
The response includes a queued submission (method: 'RequestTrade', uniqueKey, request
transactionId, and mode: 'queued') plus the applied confirmation. If the outcome is
unknown, use the unique key with gala_launchpad_get_swap_result; never submit the swap again.
Critical Gotchas
Gotcha #1: Missing reverseBondingCurveFee Parameter ⚠️🔥
Problem: AI agents forget to pass maxAcceptableReverseBondingCurveFee, causing transaction failures.
Wrong:
// Step 1: Calculate
const calc = gala_launchpad_calculate_sell_amount({ tokenName: 'anime', amount: '500', type: 'exact' })
// calc = { amount: '0.7056532', reverseBondingCurveFee: '0.3528266', ... }
// Step 2: Execute - MISSING reverseBondingCurveFee!
gala_launchpad_sell({
tokenName: 'anime',
amount: '500',
type: 'exact',
expectedAmount: '0.7056532', // ✅ Got this right
// ❌ MISSING: maxAcceptableReverseBondingCurveFee
slippageToleranceFactor: 0.05
})
// Result: Transaction fails with "FAILED" status
Correct:
// Step 1: Calculate
const calc = gala_launchpad_calculate_sell_amount({ tokenName: 'anime', amount: '500', type: 'exact' })
// calc = { amount: '0.7056532', reverseBondingCurveFee: '0.3528266', ... }
// Step 2: Execute - Include BOTH parameters from calculation
gala_launchpad_sell({
tokenName: 'anime',
amount: '500',
type: 'exact',
expectedAmount: '0.7056532', // ✅ From result.amount
maxAcceptableReverseBondingCurveFee: '0.3528266', // ✅ From result.reverseBondingCurveFee
slippageToleranceFactor: 0.05
})
// Result: Transaction succeeds!
Fix: Always extract BOTH result.amount AND result.reverseBondingCurveFee from calculate functions, then pass BOTH to buy/sell.
This applies to both buy AND sell operations!
Gotcha #2: expectedAmount Parameter Confusion ⚠️
Problem: AI agents use the input amount as expectedAmount, causing WebSocket timeouts.
Wrong:
gala_launchpad_buy({
amount: '10',
expectedAmount: '10' // ❌ WRONG - This is your input, not the expected output!
})
Correct:
// Step 1: Calculate first
const calc = gala_launchpad_calculate_buy_amount({ amount: '10', ... })
// calc.amount = '16843.7579794843252'
// Step 2: Use calc.amount as expectedAmount
gala_launchpad_buy({
amount: '10',
expectedAmount: '16843.7579794843252' // ✅ CORRECT - Use result.amount
})
Fix: Always call calculate*Amount() first, then use result.amount as expectedAmount.
Gotcha #3: Limit Validation Errors
Problem: AI agents hit "Limit must be between 1 and 20" errors when using pageSize: 100.
Root Cause: Different operations have different maximum page sizes (the pageSize argument):
- Trade operations: Max 20
- User operations (tokens held/created): Max 20
- Pool operations: Max 100
- Comment operations: Max 50
Wrong:
gala_launchpad_fetch_trades({
pageSize: 100 // ❌ WRONG - Trades max is 20!
})
Correct:
gala_launchpad_fetch_trades({
pageSize: 20 // ✅ CORRECT - Respects constraint
})
gala_launchpad_fetch_pools({
pageSize: 100 // ✅ CORRECT - Pools allow 100
})
Fix: Use the constraint reference table below for correct limits.
Gotcha #4: Type Parameter Ambiguity
Problem: Confusion between type: 'native' and type: 'exact'.
When to use 'native' (GALA amount):
- "I want to spend 10 GALA" →
{ amount: '10', type: 'native' } - "I want to receive 5 GALA" →
{ amount: '5', type: 'native' }
When to use 'exact' (exact token amount):
- "I want to buy exactly 1000 tokens" →
{ amount: '1000', type: 'exact' } - "I want to sell exactly 500 tokens" →
{ amount: '500', type: 'exact' }
Most Common: Use 'native' when you know the GALA amount.
Gotcha #5: Token Filtering Confusion
Problem: Not using the right filter for the task.
Use tokenName for exact lookups:
gala_launchpad_fetch_tokens_held({
tokenName: 'anime', // Exact match
pageSize: 1 // Only need 1 result
})
Use search for discovery:
gala_launchpad_fetch_tokens_held({
search: 'dragon', // Fuzzy search
pageSize: 10 // Get multiple matches
})
For created-token results, search is applied by the backend and tokenName is exact-matched locally on the returned page. If both are provided, both filters apply.
Gotcha #6: Wallet Address Format
Problem: A wallet address in a form the SDKs do not take is refused before anything is signed or sent.
Forms a tool accepts (pass the address as you have it; never convert by hand):
- ✅
eth|<40 hex digits>- the GalaChain form of an Ethereum account (the SDK sends the EIP-55 checksummed spelling) - ✅
0x<40 hex digits>- a bare Ethereum address, converted by the SDK - ✅
client|<id>- a GalaChain alias, sent as written - ❌
eth|0x<40 hex digits>- not an address form: refused withINVALID_ETH_USER_REF_PREFIX; aneth|reference takes the 40 digits with no0x(the error'sexpectednames the right spelling) - ❌ a mixed-case address whose EIP-55 checksum is wrong is refused (
Invalid address checksum)
Gotcha #7: Swap outcome unknown — never resubmit
Problem: A timeout or dispatch response does not prove whether the queued swap applied.
CONFIRMATION_TIMEOUT and SUBMISSION_OUTCOME_UNKNOWN mean the outcome is unknown. A 409
CHAIN_DISPATCH_FAILED also means the uniqueKey was consumed and must be recovered the same way:
// Use the uniqueKey from the execute_swap response or error
gala_launchpad_get_swap_result({
uniqueKey: 'swap_abc123',
timeoutMs: 30000,
})
Never resubmit while the outcome is unknown. Resolve the persisted key first; the result is either the applied confirmation or a terminal chain rejection.
How the server picks the tip (8.0.1): DEX errors are classified by the gswap-sdk error code
(shown in the error text as [CODE]), never by English message text, which may change or be
localized. The "outcome unknown, do NOT resubmit" tip covers every code gswap-sdk's
mayHaveBeenQueued treats as unknown: SUBMISSION_OUTCOME_UNKNOWN, CONFIRMATION_TIMEOUT,
CONFIRMATION_ABORTED, CONFIRMATION_FAILED, CONFIRMATION_MALFORMED,
CONFIRMATION_KEY_MISMATCH, GATEWAY_REPORTED_ERROR, GATEWAY_DATA_MISSING,
GATEWAY_MODE_INVALID, GATEWAY_SYNC_REQUEST_TRADE, MISSING_UNIQUE_KEY, UNIQUE_KEY_MISMATCH,
and CHAIN_DISPATCH_FAILED with status 409, 5xx or none. CHAIN_REJECTED (and a 422 dispatch)
means the swap did not execute (slippage is recognised from the chain's message text);
gateway refusals (SIGNATURE_INVALID, DTO_INVALID, RATE_LIMITED, ...) mean nothing was
queued; SIGNING_FAILED / KEY_PROVIDER_FAILED / TOKEN_RESOLUTION_FAILED mean nothing was
sent. Once execute_swap / get_swap_result hold a queued swap's uniqueKey, every failure except
a chain rejection is reported as outcome unknown (never "submit a new request"). Errors without a recognised code (gswap-sdk 1.1.x, other tools) fall back to message
patterns.
Gotcha #8: DEX slippage rejection
Problem: The chain rejects the request at apply time when the output falls below the minimum:
VALIDATION_FAILED: Slippage limit: trade would return ….
Re-quote immediately and pass the fresh estimatedOutput and feeTier to
gala_launchpad_execute_swap. The rejected request's uniqueKey is consumed and the swap did not
execute, so a new request is safe.
Constraint Reference
Pagination Limits by Operation Type
| Operation Type | Max pageSize | Tool |
|---|---|---|
| Trade Operations | 20 | gala_launchpad_fetch_trades |
| User Operations | 20 | gala_launchpad_fetch_tokens_held, gala_launchpad_fetch_tokens_created |
| Pool Operations | 100 | gala_launchpad_fetch_pools |
Each tool's schema publishes its own maximum (maximum of pageSize); the server rejects a larger value.
Common Validation Rules
| Parameter | Pattern | Example |
|---|---|---|
tokenName | ^[a-zA-Z0-9]{1,25}$ | 'mytoken', 'TestToken1' |
tokenSymbol | ^[A-Z0-9]{2,10}$ | 'MTK', 'TEST123' |
address | `^(0x[a-fA-F0-9]{40}|eth\ | [a-fA-F0-9]{40})$` |
amount | ^[0-9.]+$ | '10', '100.5' |
slippageTolerance | 0-1 (decimal) | 0.05 (5%), 0.01 (1%) |
Error Troubleshooting
"Limit must be a number between 1 and 20"
Cause: Using pageSize: 100 on trade or user operations.
Solution:
// Wrong
gala_launchpad_fetch_trades({ pageSize: 100 })
// Correct
gala_launchpad_fetch_trades({ pageSize: 20 })
"WebSocket timeout on trade execution"
Cause: Using wrong expectedAmount (likely using input amount instead of calculated result).
Solution:
// Wrong
const calc = gala_launchpad_calculate_buy_amount({ amount: '10', ... })
gala_launchpad_buy({ amount: '10', expectedAmount: '10' })
// Correct
const calc = gala_launchpad_calculate_buy_amount({ amount: '10', ... })
gala_launchpad_buy({ amount: '10', expectedAmount: calc.amount })
"Token name validation failed"
Cause: Token name doesn't match pattern ^[a-zA-Z0-9]{1,25}$.
Valid: 'mytoken', 'TestToken', 'token123'
Invalid: 'my-token' (dash), 'my token' (space), a 26-character name (too long)
Solution: Use letters and digits only, 1-25 characters.
"Token symbol validation failed"
Cause: Token symbol doesn't match pattern ^[A-Z0-9]{2,10}$.
Valid: 'MTK', 'TEST123', 'ABC'
Invalid: 'mtk' (lowercase), 'A' (too short), 'MY-TOKEN' (dash)
Solution: Use uppercase alphanumeric only, 2-10 characters.
"At least one social URL required"
Cause: Launching token without websiteUrl, twitterUrl, or telegramUrl.
Solution: Provide at least one social link:
gala_launchpad_launch_token({
// ... other params
websiteUrl: 'https://mytoken.com' // At least one required
})
Best Practices
1. Always Calculate Before Trading
Never skip the calculate step - it provides:
- Accurate
expectedAmountfor slippage protection - Fee breakdown for transparency
- Price impact analysis for informed decisions
2. Use Appropriate Limits
Match your pageSize to the operation type:
- Trades/User operations: Use 20 or less
- Pools: Can use up to 100
- Comments: Can use up to 50
3. Handle Slippage Appropriately
Common slippage tolerance factors:
0.01(1%) - Low volatility, stable pools0.05(5%) - Standard for most trades0.10(10%) - High volatility, new tokens
4. Use Token Filtering Efficiently
For single token lookups:
gala_launchpad_fetch_token_balance({
tokenName: 'anime',
address: 'eth|...'
})
// 99% payload reduction vs fetching all tokens
For discovery:
gala_launchpad_fetch_tokens_held({
search: 'dragon',
pageSize: 10
})
5. Verify Trades Complete
After executing trades, always verify:
gala_launchpad_fetch_trades({
tokenName: 'woohoo',
userAddress: 'eth|...',
pageSize: 1,
sortOrder: 'DESC'
})
6. Check Availability Before Launch
Always verify token name and symbol availability before launching:
// Step 1: Check name
gala_launchpad_check_token_name({ tokenName: 'mytoken' })
// Step 2: Check symbol
gala_launchpad_check_token_symbol({ symbol: 'MTK' })
// Step 3: Launch if both available
gala_launchpad_launch_token({ ... })
Quick Reference Card
Trading Flow
calculate_buy_amount()orcalculate_sell_amount()- Extract
result.amountfrom response - Use
result.amountasexpectedAmountin buy/sell - Verify with
fetch_trades()
Lock/Unlock Flow
lock_tokens()- Lock tokens, passed as atokensarray (optional: lockAuthority, name, expires)unlock_tokens()- Release tokens, passed as atokensarray (must be lock authority)- Use
nameto match specific locks when unlocking
Page Size Values (pageSize)
- Trades: 20 max
- User ops: 20 max
- Pools: 100 max
Type Parameter
'native'= GALA amount (most common)'token'= Exact token amount
Token Filtering
tokenName= Exact match (faster)search= Fuzzy match (discovery)
Address Format
- API expects:
'eth|abc123...' - Convert from:
'0xabc123...'
For more details, see:
- MCP Server README
- SDK Documentation
- Constraints reference:
docs/CONSTRAINTS-REFERENCE.mdin the package