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_check_token_name({
tokenName: 'mytoken'
})
// Response: { available: true, message: "Token name is available" }
// Step 2: Verify token symbol is available
gala_check_token_symbol({
symbol: 'MTK'
})
// Response: { available: true, message: "Token symbol is available" }
// Step 3: Upload token image (optional, can use URL instead)
gala_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_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_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_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_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_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!
expected amount max acceptable reverse bonding curve fee
3. Trading Workflow (Sell Tokens)
Same two-step pattern:
// Step 1: Calculate sell amount
const calcResult = gala_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_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_fetch_gala_balance({
address: 'eth|your-address' // Optional, defaults to authenticated wallet
})
// Get specific token balance (optimized single-token lookup)
gala_fetch_token_balance({
tokenName: 'woohoo',
address: 'eth|your-address'
})
// Get all tokens held (with filtering)
gala_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_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_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_lock_tokens({
tokens: [{ tokenName: 'anime', amount: '1000' }]
})
// Response: { transactionId: '...', status: 'completed' }
// ============================================================================
// LOCK TOKENS - Advanced options (escrow, vesting)
// ============================================================================
// Lock with custom authority (escrow pattern)
gala_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_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_unlock_tokens({
tokens: [{ tokenName: 'anime', amount: '500' }]
})
// Response: { transactionId: '...', status: 'completed' }
// Unlock with name matching (for specific locks)
gala_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
lock authority 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_fetch_launchpad_fee()
// Response: 25 (number — fee in GALA)
// Fetch sale details for a token (cached 10 seconds)
const details = gala_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_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_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_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_get_trade_quote (instant) |
| Pre-trade validation (accurate) | gala_calculate_buy_amount (chain) |
| Token creation preview | gala_get_premint_quote |
| Token sale status check | gala_fetch_sale_details |
| Fee display | gala_fetch_launchpad_fee |
gala get trade quote calculate buy amount premint fetch sale details launchpad fee
7. Pool Analysis Workflow
Discover and analyze token pools:
// Fetch recent/trending pools
gala_fetch_pools({
type: 'trending', // 'recent', 'trending', or 'user'
pageSize: 100 // Max 100 for pool operations
})
// Get detailed pool state
gala_fetch_pool_details({
tokenName: 'woohoo'
})
// Get holder distribution
gala_fetch_token_distribution({
tokenName: 'woohoo'
})
// Get volume data for charting
gala_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_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_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_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_get_swap_result; never submit the swap again.
request trade unique key transaction id gala get swap result
Critical Gotchas
Gotcha #1: Missing reverseBondingCurveFee Parameter ⚠️🔥
Problem: AI agents forget to pass maxAcceptableReverseBondingCurveFee, causing transaction failures.
Wrong:
// Step 1: Calculate
const calc = gala_calculate_sell_amount({ tokenName: 'anime', amount: '500', type: 'exact' })
// calc = { amount: '0.7056532', reverseBondingCurveFee: '0.3528266', ... }
// Step 2: Execute - MISSING reverseBondingCurveFee!
gala_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_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_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!
reverse bonding curve fee max acceptable
Gotcha #2: expectedAmount Parameter Confusion ⚠️
Problem: AI agents use the input amount as expectedAmount, causing WebSocket timeouts.
Wrong:
gala_buy({
amount: '10',
expectedAmount: '10' // ❌ WRONG - This is your input, not the expected output!
})
Correct:
// Step 1: Calculate first
const calc = gala_calculate_buy_amount({ amount: '10', ... })
// calc.amount = '16843.7579794843252'
// Step 2: Use calc.amount as expectedAmount
gala_buy({
amount: '10',
expectedAmount: '16843.7579794843252' // ✅ CORRECT - Use result.amount
})
Fix: Always call calculate*Amount() first, then use result.amount as expectedAmount.
expected amount
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_fetch_trades({
pageSize: 100 // ❌ WRONG - Trades max is 20!
})
Correct:
gala_fetch_trades({
pageSize: 20 // ✅ CORRECT - Respects constraint
})
gala_fetch_pools({
pageSize: 100 // ✅ CORRECT - Pools allow 100
})
Fix: Use the constraint reference table below for correct limits.
page size
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_fetch_tokens_held({
tokenName: 'anime', // Exact match
pageSize: 1 // Only need 1 result
})
Use search for discovery:
gala_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.
token name
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)
invalid eth user ref prefix
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_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.
confirmation timeout submission outcome unknown chain dispatch failed may have been queued aborted malformed key mismatch gateway reported error data missing mode invalid sync request trade unique rejected signature dto rate limited signing provider token resolution execute swap get result
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_execute_swap. The rejected request's uniqueKey is consumed and the swap did not
execute, so a new request is safe.
validation failed estimated output fee tier gala execute swap
Constraint Reference
Pagination Limits by Operation Type
| Operation Type | Max pageSize | Tool |
|---|---|---|
| Trade Operations | 20 | gala_fetch_trades |
| User Operations | 20 | gala_fetch_tokens_held, gala_fetch_tokens_created |
| Pool Operations | 100 | gala_fetch_pools |
Each tool's schema publishes its own maximum (maximum of pageSize); the server rejects a larger value.
page size gala fetch trades tokens held created pools
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%) |
token name test token1 symbol slippage tolerance
Error Troubleshooting
"Limit must be a number between 1 and 20"
Cause: Using pageSize: 100 on trade or user operations.
Solution:
// Wrong
gala_fetch_trades({ pageSize: 100 })
// Correct
gala_fetch_trades({ pageSize: 20 })
page size
"WebSocket timeout on trade execution"
Cause: Using wrong expectedAmount (likely using input amount instead of calculated result).
Solution:
// Wrong
const calc = gala_calculate_buy_amount({ amount: '10', ... })
gala_buy({ amount: '10', expectedAmount: '10' })
// Correct
const calc = gala_calculate_buy_amount({ amount: '10', ... })
gala_buy({ amount: '10', expectedAmount: calc.amount })
web socket expected 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.
test token
"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_launch_token({
// ... other params
websiteUrl: 'https://mytoken.com' // At least one required
})
website url twitter telegram
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
expected amount
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
page size
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_fetch_token_balance({
tokenName: 'anime',
address: 'eth|...'
})
// 99% payload reduction vs fetching all tokens
For discovery:
gala_fetch_tokens_held({
search: 'dragon',
pageSize: 10
})
5. Verify Trades Complete
After executing trades, always verify:
gala_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_check_token_name({ tokenName: 'mytoken' })
// Step 2: Check symbol
gala_check_token_symbol({ symbol: 'MTK' })
// Step 3: Launch if both available
gala_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()
calculate buy amount sell expected 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
lock tokens unlock
Page Size Values (pageSize)
- Trades: 20 max
- User ops: 20 max
- Pools: 100 max
page size
Type Parameter
'native'= GALA amount (most common)'token'= Exact token amount
Token Filtering
tokenName= Exact match (faster)search= Fuzzy match (discovery)
token name
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