# Gala developer docs Documentation for the Gala SDKs and tools, assembled from each package's own docs bundle. # GalaChain core SDK 1.0.0-rc.8 (@gala-chain/gala-core-sdk) Signing, signers, gateway transport, token reads and writes, wallets, bridge and the shared error model every Gala SDK builds on. --- # Agent guide: gala-core-sdk This page is for an AI agent (or a developer working with one) that writes code against `@gala-chain/gala-core-sdk`. Every recipe compiles against the package's built types (the docs build fails otherwise), and every invariant names the test or golden that enforces it. ## Which package for which job | Job | Package | Install | | --- | --- | --- | | Sign a payload, transfer GALA or a token, read a balance, bridge, wrap, connect a wallet | `@gala-chain/gala-core-sdk` | `npm install @gala-chain/gala-core-sdk@next` | | Quote, swap and manage liquidity on the GSwap DEX | `@gala-chain/gswap-sdk` (core is its peer) | `npm install @gala-chain/gswap-sdk@next` | | Launchpad pools, bonding-curve buy and sell, token creation | `@gala-chain/launchpad-sdk` (core is its peer) | `npm install @gala-chain/launchpad-sdk@next` | | Give an MCP client (Claude, Cursor) the same abilities as tools | `@gala-chain/gala-mcp-server` | `npm install -g @gala-chain/gala-mcp-server@next` | Never install a second copy of core next to a product SDK: two copies split `instanceof`, the signer identity and the error class. The product SDKs declare core as a peer dependency so one copy is shared. ## Recipes ### Sign a payload ```ts import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; const signer = new PrivateKeySigner(process.env.GALACHAIN_PRIVATE_KEY!); // The signer signs exactly the object it is handed: pass the bare DTO of the method. const signed = await signer.signObject('TransferToken', { quantity: '1', uniqueKey: 'k-1' }); console.log(signed); ``` ### Transfer GALA ```ts import { GALA_CHAIN_ENVIRONMENTS, GatewayWrites, PrivateKeySigner, getEthereumAddressFromPrivateKey } from '@gala-chain/gala-core-sdk'; const privateKey = process.env.GALACHAIN_PRIVATE_KEY!; const writes = new GatewayWrites({ gatewayBaseUrl: GALA_CHAIN_ENVIRONMENTS.stage.gatewayBaseUrl, signer: new PrivateKeySigner(privateKey), walletAddress: getEthereumAddressFromPrivateKey(privateKey), }); // `to` may be eth|, 0x<40 hex> or a client| alias; quantity is whole GALA as a string. const receipt = await writes.transferGala({ to: 'client|5f1b0c0a1b2c3d4e5f6a7b8c', quantity: '1.5' }); console.log(receipt.transactionId, receipt.uniqueKey); ``` ### Transfer another token ```ts import { GALA_CHAIN_ENVIRONMENTS, GatewayWrites, PrivateKeySigner, getEthereumAddressFromPrivateKey } from '@gala-chain/gala-core-sdk'; const privateKey = process.env.GALACHAIN_PRIVATE_KEY!; const writes = new GatewayWrites({ gatewayBaseUrl: GALA_CHAIN_ENVIRONMENTS.stage.gatewayBaseUrl, signer: new PrivateKeySigner(privateKey), walletAddress: getEthereumAddressFromPrivateKey(privateKey), }); // A token is named by its four-part class key; a bare symbol is never a key. await writes.transferToken({ to: 'client|5f1b0c0a1b2c3d4e5f6a7b8c', tokenClassKey: 'GUSDC|Unit|none|none', quantity: '10', }); ``` ### Read a balance ```ts import { GALA_CHAIN_ENVIRONMENTS, GatewayReads } from '@gala-chain/gala-core-sdk'; const reads = new GatewayReads({ gatewayBaseUrl: GALA_CHAIN_ENVIRONMENTS.stage.gatewayBaseUrl }); const balance = await reads.fetchTokenBalance({ owner: 'client|5f1b0c0a1b2c3d4e5f6a7b8c', tokenClassKey: 'GALA|Unit|none|none', }); console.log(balance?.quantity); ``` ### Recover from an unknown write outcome A write that times out or loses its connection may have been applied. The error carries the write's `uniqueKey`: check that key before sending anything again, never re-send under a fresh key. ```ts import { GALA_CHAIN_ENVIRONMENTS, GatewayWrites, PrivateKeySigner, getEthereumAddressFromPrivateKey, isGalaError } from '@gala-chain/gala-core-sdk'; const privateKey = process.env.GALACHAIN_PRIVATE_KEY!; const writes = new GatewayWrites({ gatewayBaseUrl: GALA_CHAIN_ENVIRONMENTS.stage.gatewayBaseUrl, signer: new PrivateKeySigner(privateKey), walletAddress: getEthereumAddressFromPrivateKey(privateKey), }); try { await writes.transferGala({ to: 'client|5f1b0c0a1b2c3d4e5f6a7b8c', quantity: '1' }); } catch (error) { if (isGalaError(error, 'GATEWAY_WRITE_OUTCOME_UNKNOWN')) { console.log('check this write before retrying:', error.uniqueKey, error.params.reason); } else { throw error; } } ``` For a swap, a token launch or a buy and sell, use the product SDK: each has its own agent guide (`/gswap-sdk/agents.md`, `/launchpad-sdk/agents.md`). The bundler write path belongs to `@gala-chain/launchpad-sdk`. ## Invariants - Sign the bare DTO. The signer is handed exactly the object of the method; the personal-sign path never hashes an embedded `prefix` field into the message (the "phantom signer" bug), and the signature recovers to the signing wallet. Enforced by `packages/gala-core-sdk/tests/chain_dto_signing.test.ts` ("never hashes the embedded prefix field into the message (the phantom-signer bug)") and by `packages/gala-core-sdk/tests/signing-golden.test.ts` ("serializes and natively signs byte-for-byte"). - A write sends what the signer returned and adds nothing. Enforced by `packages/gala-core-sdk/tests/writes.test.ts` ("hands the signer the bare DTO for the write method and sends exactly what it returned"). - A user reference is `eth|` or a `client|` alias. Every Ethereum spelling is converted to the checksummed `eth|` form; a bare `0x<40 hex>` is converted, a wrong mixed-case checksum is refused. Enforced by `packages/gala-core-sdk/tests/writes.test.ts` ("sends every Ethereum account spelling as eth|, a client| alias as written"), `packages/gala-core-sdk/tests/writes.test.ts` ("accepts one-case digits and refuses a mixed case with a wrong checksum") and the golden `packages/gala-core-sdk/tests/fixtures/writes-signing-golden.json` ("vectors.transferGala 0x recipient is sent as checksummed eth|"). - `eth|0x` is not an address form. It is REFUSED with `INVALID_ETH_USER_REF_PREFIX` before anything is signed or sent, for a write recipient, the writer identity, a lock authority and a read owner. Enforced by `packages/gala-core-sdk/tests/writes.test.ts` ("refuses eth|0x for each, before anything is signed or sent") and `packages/gala-core-sdk/tests/reads.test.ts` ("refuses eth|0x owners as INVALID_ETH_USER_REF_PREFIX before anything is sent"). - Amounts are whole tokens as a decimal string, signed exactly as written. A JS number, an exponent, a sign, hex or a zero quantity is refused with `INVALID_QUANTITY`. Enforced by `packages/gala-core-sdk/tests/writes.test.ts` ("signs quantities exactly as written and refuses any other spelling"). - A token is named by a four-part class key (`collection|category|type|additionalKey`) or by `tokenName` through a resolver; a bare symbol is never a class key and none is derived from it. Enforced by `packages/gala-core-sdk/tests/writes.test.ts` ("names a token by class key (pipe with exactly four parts, $ from the right, object) or by name"). - A minted `uniqueKey` is at most 64 characters with no `|`; a key you supply is 1 to 128 characters of `A-Za-z0-9._:-` and is refused before signing otherwise. Enforced by `packages/gala-core-sdk/tests/writes.test.ts` ("mints : at most 64 characters, no \"|\", a fresh key per write") and `packages/gala-core-sdk/tests/writes.test.ts` ("keeps a caller key and refuses an invalid one before signing"). - A write whose outcome is unknown is never retried under a fresh key: the error carries the `uniqueKey` to check. Enforced by `packages/gala-core-sdk/tests/writes.test.ts` ("a timeout is GATEWAY_WRITE_OUTCOME_UNKNOWN (timeout) carrying the uniqueKey, never a retryable REQUEST_TIMEOUT"). - The signing helpers work on a private copy of the key bytes and zero it when the signing action finishes, on success and when it throws; a `PrivateKeySigner` itself holds its key for its lifetime, so keep it out of logs and tool arguments. Enforced by `packages/gala-core-sdk/tests/chain_dto_signing.test.ts` ("zeroes its private copy of the key, on success and when the action throws"). ## Error codes Branch on `error.code` (stable), never on `error.message`. `isGalaError(error, 'CODE')` narrows the error and its `params`. | Code | Meaning | Fix | | --- | --- | --- | | `INVALID_ETH_USER_REF_PREFIX` | An address was written `eth\|0x`. | Write `eth\|` or the bare `0x`; `error.params.expected` is the correct spelling. | | `INVALID_WALLET_ADDRESS` | A wallet address, recipient or owner is not an accepted form; `params.field` names it. | Use `eth\|`, a checksummed `0x` or a `client\|` alias. | | `INVALID_QUANTITY` | A write quantity is not a plain positive decimal string. | Pass whole tokens as a string such as `'1.5'`. | | `INVALID_TOKEN_REFERENCE` | A token is named badly (missing, ambiguous, a bare symbol). | Pass the four-part class key, or `tokenName` with a resolver. | | `INVALID_UNIQUE_KEY` | A `uniqueKey` outside 1 to 128 characters of `A-Za-z0-9._:-`. | Omit it to mint one, or mint with `createUniqueKey`. | | `SIGNING_FAILED` | The signer threw before anything was sent (a locked wallet, a declined prompt). | Nothing was sent; retry once the wallet is unlocked or approved. | | `INVALID_PRIVATE_KEY` | A key is empty, the wrong length, mis-encoded or off the curve; `params.reason` says which. | Supply 32 bytes as 64 hex digits. | | `GATEWAY_WRITE_OUTCOME_UNKNOWN` | The write may have been applied (timeout or lost connection). | Check `error.uniqueKey` on chain before any retry. | | `GATEWAY_WRITE_REJECTED` | GalaChain refused the write (`Status` other than 1). | Read `error.body` for the chain's reason; fix the input. | | `REQUEST_TIMEOUT` | A read exceeded its timeout. | Retry the read; reads are safe to repeat. | | `TRANSPORT_ERROR` | A read failed before any answer (offline, DNS, CORS). | Retry the read after connectivity returns. | | `CSPRNG_UNAVAILABLE` | No `crypto.getRandomValues` (React Native without the polyfill). | Import `react-native-get-random-values` first. | --- # GalaChain core SDK `@gala-chain/gala-core-sdk` is the layer every GalaChain product SDK and app shares: signing (native, personal-sign, EIP-712 and arbitrary typed data), the signers (private key, lazy private key, Gala Wallet, EIP-1193 browser wallets), the gateway transport (`fetch` requestor with timeouts, wire options, axios and ethers adapters), the gateway token reads (balances and holds, token classes, NFT collection authorizations) and writes (transfer, burn, lock, unlock), token class keys and write `uniqueKey`s, and the shared error model (`GalaSDKError`, its catalog, the failure view). It speaks to the GalaChain gateway generically; product backends (the DEX and Launchpad backends) have their own SDKs (`@gala-chain/gswap-sdk`, `@gala-chain/launchpad-sdk`) that build on it. ## Install ```bash npm install @gala-chain/gala-core-sdk@next ``` 1.0 is a release candidate, published under the `next` dist-tag: install `@next`, and pin the exact version in an app build. A product SDK takes core as a **peer dependency**: install it next to the product SDK, once. ## Quick start ```typescript import { PrivateKeySigner, serialize, signNative, normalizePrivateKey } from '@gala-chain/gala-core-sdk'; const signer = new PrivateKeySigner(process.env.GALACHAIN_PRIVATE_KEY!); const signed = await signer.signObject('TransferToken', { quantity: '1', uniqueKey: 'k-1' }); // The primitives the signer is built on, byte-identical to @gala-chain/api: const key = normalizePrivateKey(process.env.GALACHAIN_PRIVATE_KEY!); console.log(serialize({ b: 1, a: 2 }), signNative(key, { a: 1 })); key.fill(0); ``` ## What is in it | Area | Exports | | --- | --- | | Signers | `PrivateKeySigner`, `createLazyPrivateKeySigner`, `GalaWalletSigner`, `BrowserWalletSigner`, `signPreSend`, type `GalaChainSigner` | | Signing | `serialize`, `getPayloadToSign`, `signNative`, `signPersonalMessage`, `personalSignPrefixFor`, `fixpointPrefixFor`, `signChainDto*`, `signRawObject`, `generateEIP712Types`, `buildEIP712Payload`, `hashTypedData`, `signTypedDataPayload` | | Transport | `fetchRequestor`, `requestWithTimeout` (`kind: { write: false }` makes a read's timeout and transport failure say `write: false`), `buildRequestHeaders`, `buildQueryString`, `readRetryAfter`, `httpRequestorFromAxios`, `eip1193ProviderFromEthers`, `isFetchTransportFailure`, types `HttpRequestor`, `WireOptions`, `RequestKind` | | Gateway reads | `GatewayReads` (`fetchBalances`, `fetchTokenBalance`, `fetchNftBalances`, `fetchTokenClasses`, `fetchTokenClassesWithSupply`, `fetchTokenClass`, `fetchTokenDetails`, `fetchTokenClassesPage`, `fetchAllTokenClasses`, `fetchNftCollectionAuthorizationsPage`, `fetchAllNftCollectionAuthorizations`, `fetchPublicKey`), `GATEWAY_READ_METHODS`, `GATEWAY_READ_LIMITS`, types `GalaChainTokenBalance`, `GalaChainTokenBalanceSummary`, `GalaChainTokenClass`, `GalaChainTokenDetails`, `GalaChainPage`, `GalaChainPublicKey` | | Gateway writes | `GatewayWrites` (`transferGala`, `transferToken`, `burnTokens`, `lockTokens`, `unlockTokens`), `galaChainUserRef` (a user reference in the one spelling the gateway accepts), `GATEWAY_WRITE_METHODS`, `GATEWAY_WRITE_BATCH_LIMITS`, `GALA_TOKEN_CLASS_KEY`, types `GatewayWritesOptions`, `GatewayWriteReceipt`, `TokenNameResolver`, `TokenQuantityInput` | | Deployments | `GALA_CHAIN_ENVIRONMENTS` (gateway and DEX API of `prod` / `stage`) | | Keys | `compositeKeyOf`, `tryParseTokenClassKey`, `tryParseCompositeKey`, `createUniqueKey`, `assertUniqueKey`, `isValidUniqueKey` | | Wallets | `createWallet` (random, from a private key, or from a 12/24-word mnemonic at `m/44'/60'/0'/0/0`), `validateWalletInput`, `getPublicKeyFromPrivateKey`, `getEthereumAddressFromPrivateKey`, `checksumEthereumAddress`, types `GeneratedWallet`, `PublicKeyResult` | | Errors | `GalaSDKError`, `isGalaError`, `GALA_ERROR_CATALOG`, `galaErrorTemplates`, `GALA_ERROR_PHASE_BY_CODE`, `toFailureView`, `isWriteView`, `FAILURE_OUTCOMES` | | Wallet helpers (`./wallet`) | `isWalletUserRejection`, `walletDeclineCode`, `isGalaErrorLike` | | Wallet providers (`./providers`) | `PrivateKeyProvider`, `ExternalWalletProvider`, `GalaWalletProvider`, `detectWallets`, `subscribeToWalletChanges`, `getWalletByRdns`, `isWalletAvailable`, `findMetaMaskWallet`, `getMetaMaskWallet`, `findTrustWallet`, `getTrustWallet`, `hasAnyWallet`, `getInjectedEip1193Provider`, `KNOWN_WALLET_RDNS`, `createWalletProvider`, `createProviderFromEip1193`, `ensureConnected`, `getPrivateKeyIfAvailable`, `isPrivateKeyProvider`, `isExternalProvider`, `isEip1193Provider`, type `WalletProvider` | | React (`./react`) | `WalletProvider` (context component), `WalletContext`, `useWallet`, `useWalletContext`, `useWalletConnection`, `useWalletDetection`, `useWalletAddress`, `useGalaAddress`, `useWalletProvider`, `useIsWalletConnected` | | Bridge (`./bridge`) | `BridgeService` (bridge out to and in from Ethereum and Solana, fees, status, external balances), `EthereumBridgeStrategy`, `SolanaBridgeStrategy`, `BaseBridgeStrategy`, `GalaConnectClient`, `BridgeableTokenService`, `WrappableTokenService`, `WrapService` (channel wrap / unwrap), `createSolanaWallet`, `buildBridgeOutPayload` (the signed bridge-out request), the bridge constants and token tables, the bridge types, `RateLimiter`, the token amount helpers (`toBaseUnits`, `fromBaseUnits`, `formatTokenAmount`, `compareAmounts`) | ## Subpaths Each subpath is its own build: it loads the root (and `./react` the providers) through the package, never a copy, so an app has one `GalaSDKError` class, one signer set and one set of provider classes (checked on the packed tarball by `pnpm run check:pack`, and on the source by `tests/subpath_isolation.test.ts`). The root never loads a subpath. | Entry | What it is for | Loads (besides the root) | Peer it needs | | --- | --- | --- | --- | | `@gala-chain/gala-core-sdk` | Signing, signers, transport, gateway reads and writes, keys, wallets, errors | `@noble/*`, `@scure/bip32`, `@scure/bip39`, `bignumber.js` | none | | `@gala-chain/gala-core-sdk/wallet` | The dependency-free wallet helpers (an app shell) | nothing (not even the root) | none | | `@gala-chain/gala-core-sdk/providers` | One `WalletProvider` per wallet kind, EIP-6963 detection | `@noble/hashes` | none | | `@gala-chain/gala-core-sdk/react` | The wallet context and hooks | `./providers` | `react` (optional peer, 16.8 to 19; `react-dom` is not needed) | | `@gala-chain/gala-core-sdk/bridge` | Bridging GalaChain to and from Ethereum and Solana, channel wrap / unwrap, the bridgeable and wrappable token lists | `ethers`, `@solana/web3.js`, `@solana/spl-token`, `@scure/base`, `bignumber.js` | `ethers` 6, `@solana/web3.js` 1.99+, `@solana/spl-token` 0.4.15+ (optional peers: install them when you import `./bridge`) | Only `./bridge` loads `ethers` or `@solana/*`: the root and the other subpaths never do (checked on the source by `pnpm run check:rn-safety` and the isolation test, and on the built files by the packed smoke). ## Bridge ```typescript import { BridgeableTokenService, BridgeService, GalaConnectClient } from '@gala-chain/gala-core-sdk/bridge'; const walletAddress = 'eth|...'; // The DEX API's bridgeable token list (production by default; `baseUrl` for another deployment) const tokens = new BridgeableTokenService(new GalaConnectClient({ walletAddress })); const bridge = new BridgeService({ environment: 'prod', // or 'stage': GalaConnect, the gateway and the RPCs of that deployment galaChainWalletAddress: walletAddress, ethereumPrivateKey: process.env.ETH_PRIVATE_KEY!, // signs the bridge-out request and Ethereum deposits bridgeableTokenService: tokens, // resolves a token id to its bridge symbol }); // Token ids are class keys (pipe form or object): a bare symbol is refused (symbols are not unique) const GALA = 'GALA|Unit|none|none'; const fee = await bridge.estimateBridgeFee({ tokenId: GALA, destinationChain: 'Ethereum' }); const out = await bridge.bridgeOut({ tokenId: GALA, amount: '10', destinationChain: 'Ethereum', recipientAddress: '0x...' }); const status = await bridge.waitForBridgeCompletion(out.transactionHash); ``` A bridge or wrap that does not complete throws a `GalaSDKError` (never a "failed" result). Once a bridge-out request was accepted the tokens may be locked: a later failure is `BRIDGE_OUT_OUTCOME_UNKNOWN` (with the step, the bridge request id and the `uniqueKey`), and a deposit that may have been sent is `BRIDGE_DEPOSIT_OUTCOME_UNKNOWN`; neither is ever retried by the SDK. `WrapService` wraps a token from its own channel to the asset channel (MUSIC to GMUSIC) and back, signed natively by a `GalaChainSigner`. TypeScript: the `./bridge` declarations name `@solana/web3.js` types, whose own declarations import Node's `http` and `https`, so a TypeScript app that imports `./bridge` has `@types/node` (with TypeScript 6, `"types": ["node"]`) or `skipLibCheck`. The other entries need no Node types. ## Wallet providers ```typescript import { detectWallets, ExternalWalletProvider, PrivateKeyProvider } from '@gala-chain/gala-core-sdk/providers'; const { wallets } = await detectWallets(); // EIP-6963 announcements, then window.ethereum / window.gala const first = wallets[0]; if (first === undefined) throw new Error('No wallet announced itself'); const provider = new ExternalWalletProvider(first.provider); await provider.connect(); await provider.signMessage('Hello'); // personal_sign const signer = provider.getSigner(); // a GalaChainSigner for GatewayWrites, gswap-sdk, ... const server = new PrivateKeyProvider(process.env.GALACHAIN_PRIVATE_KEY!); // Node, CLI, bots ``` A provider listens to its wallet only while connected, follows `accountsChanged` (an empty or malformed account list disconnects it), and reads its connection once per operation, so one operation never names two accounts. `getSigner()` is bound to the account connected when it is called: after an account change, get a new signer. `GalaWalletProvider` selects its account in the extension before each signature, serialized with every other signer of the same extension. Every failure is a `GalaSDKError`: `WALLET_CONNECTION_FAILED` (`user_rejected`, `no_accounts`, `failed`), `WALLET_NOT_CONNECTED`, `SIGNING_FAILED` (`user_rejected` when the person declined), `INVALID_SIGNATURE`, `PRIVATE_KEY_NOT_ACCESSIBLE`, `INVALID_WALLET_PROVIDER_CONFIG`. Detection works without a window (Node, SSR, React Native): it finds nothing and throws nothing. ## React ```tsx import { WalletProvider, useWalletConnection, useWalletDetection, useWallet } from '@gala-chain/gala-core-sdk/react'; ; const { wallets } = useWalletDetection(); const { connectDetected } = useWalletConnection(); // a GalaWalletProvider for Gala Wallet, an ExternalWalletProvider otherwise const { address, galaAddress, isConnected } = useWallet(); ``` The address follows the wallet (account switches, a wallet-side disconnect); the latest connect wins over a slower earlier one; a provider the context created is released when it is replaced, when its connect fails and on unmount; `initialProvider` is connected once. A hook outside `` is `WALLET_CONTEXT_MISSING`. It renders on the server (no window, nothing detected). `./react` does not re-export the providers: import them from `./providers`. Every error core throws is a `GalaSDKError` with a stable `code`, flat `params` for an app's own localization and a `phase` (`pre_send`: nothing was transmitted). The codes are listed in [docs/error-catalog.md](/gala-core-sdk/next/error-catalog.md). A product SDK's error class extends `GalaSDKError` and adds its own codes; `isGalaError(error)` recognises an error from any of them. ## Gateway writes ```typescript import { GatewayWrites, PrivateKeySigner } from '@gala-chain/gala-core-sdk'; const writes = new GatewayWrites({ gatewayBaseUrl: 'https://gateway-mainnet.galachain.com', signer: new PrivateKeySigner(process.env.GALACHAIN_PRIVATE_KEY!), walletAddress: 'eth|70997970C51812dc3A010C7d01b50e0d17dc79C8', // or a client| alias }); const { transactionId, blockNumber } = await writes.transferGala({ to: 'client|abc', quantity: '1.5' }); await writes.lockTokens({ tokens: [{ tokenClassKey: 'GALA|Unit|none|none', quantity: '10' }], expires: 0 }); ``` - Quantities are WHOLE tokens, as the decimal string the chain receives; they are signed exactly as written (`"1.50"` stays `"1.50"`) and never scaled. - Tokens: `tokenClassKey` (`collection|category|type|additionalKey` with exactly four parts, the `$` composite key, or the object) plus `instance` (default `"0"`), or `tokenName` through an optional `tokenNameResolver`. A bare symbol is never a class key. - Identities (`to`, `walletAddress`, `lockAuthority`): an Ethereum account (`eth|<40 hex>`, `0x<40 hex>`, bare hex; any casing but a wrong EIP-55 checksum) is always sent as `eth|`, the only spelling the gateway accepts; `client|` is sent as written. `eth|0x` is **not** an address form: it is refused before anything is signed or sent with `INVALID_ETH_USER_REF_PREFIX` (an `eth|` reference takes the 40 digits with no `0x`; the error's `expected` is the right spelling). A bare `0x<40 hex>` is an ordinary Ethereum address and is converted. - The signer is handed the bare DTO; the body sent is exactly the DTO plus the signature (a signer that adds or changes a field is refused). A `uniqueKey` is minted per write unless you pass one. - GalaChain's `Status` is checked before anything else is trusted; a timeout or broken connection is `GATEWAY_WRITE_OUTCOME_UNKNOWN`: the write may have been applied, so check its `uniqueKey` and never resend it under a fresh key. ## Gateway reads ```typescript import { GALA_CHAIN_ENVIRONMENTS, GatewayReads } from '@gala-chain/gala-core-sdk'; const reads = new GatewayReads({ gatewayBaseUrl: GALA_CHAIN_ENVIRONMENTS.prod.gatewayBaseUrl }); const gala = await reads.fetchTokenBalance({ owner: 'client|abc', tokenClassKey: 'GALA|Unit|none|none' }); console.log(gala?.quantity, gala?.lockedQuantity, gala?.availableQuantity); // whole-token strings const { symbol, decimals } = await reads.fetchTokenDetails('GUSDC|Unit|none|none'); const classes = await reads.fetchAllTokenClasses({ collection: 'BONKTactics' }, { maxPages: 10 }); ``` - Reads are unsigned and apply nothing: every failure after the request left says so (`error.write === false`), and a retry is always safe. - Owners are spelled as the writes spell them (an Ethereum account in any form as `eth|`, `client|` as written); class keys are accepted in the same forms. `$MUSIC` balances are read on the gateway's `music` channel. - Every answer is checked (GalaChain's `Status`, then each row) before it is returned; a balance of another owner than the one asked for is refused. Quantities stay the chain's whole-token decimal strings; hold totals are exact and never in exponent form. - A token class that does not exist is `TOKEN_CLASS_NOT_FOUND`; a `fetchAll...` read that would need more than `maxPages` pages is `PAGINATION_LIMIT_EXCEEDED` (never a truncated list). - `fetchPublicKey(user)` reads the key GalaChain has registered for a user (`{ publicKey, signing? }`, `undefined` when none is saved). The public gateways do not route the public-key-contract; read it through a connect-api proxy: `new GatewayReads({ gatewayBaseUrl: 'https://api-galaswap.gala.com/galachain' })`. ## Signing parity The signing code is pinned byte-for-byte to `@gala-chain/api` and to the Gala Wallet's and the gSwap web app's signing code by the golden vectors in `tests/fixtures/wallet-signing-golden.json` and `tests/fixtures/frontend-signing-golden.json` (`tests/signing-golden.test.ts`). They are never regenerated to make a test pass. ## React Native The shipped source uses no Node builtin, no `Buffer`, no `process`, and never loads `ethers`, `axios` or `@gala-chain/api` (`pnpm run check:rn-safety`, also run by the test suite). The only polyfill React Native/Hermes needs is `crypto.getRandomValues`, for minting `uniqueKey`s and new random wallets (`createWallet()`): ```typescript import 'react-native-get-random-values'; // once, before the SDK mints a key ``` Without it, minting a key or a wallet throws `CSPRNG_UNAVAILABLE` (never a weaker fallback). `./bridge` is the exception: it loads `ethers`, `@solana/web3.js` and `@solana/spl-token`, and an app that imports it on React Native also installs what those libraries ask for there (`crypto.getRandomValues` above, which `createSolanaWallet` needs too; `@solana/web3.js`'s React Native guidance adds a global `Buffer` from the `buffer` package). Core's own `./bridge` code uses no `Buffer` or `process` global (Solana instruction data are `Uint8Array`s) and touches none at module load: the guard allows `./bridge` exactly those three packages and nothing else (base58 is `@scure/base`, pure JS like the rest of core). ## Bundle size `sideEffects: false`, and the browser build is one file per source module, so an app (or a product SDK's light module) that imports one helper loads that module only. `@gala-chain/gala-core-sdk/wallet` holds only the dependency-free wallet helpers (about 1.2 kB minified, capped at 2 kB). `tests/tree_shaking.test.ts` budgets every shell-safe helper. The browser builds of `./providers` (about 17 kB minified, 7.6 kB gzipped, most of it the known wallets' icons), `./react` (about 4 kB, 1.7 kB gzipped) and `./bridge` (about 60 kB minified, 16 kB gzipped, before `ethers` and `@solana/*`) are loaded only by an app that imports them. ## Status 1.0.0-rc.8 (rc.7: `eth|0x` is refused as `INVALID_ETH_USER_REF_PREFIX`, not an address form; rc.6: `fetchPublicKey`, MetaMask and Trust Wallet detection, silent `restore()`; rc.5: every Ethereum account a read, write or GalaConnect client sends is `eth|`, the only spelling the gateway accepts, and `galaChainUserRef` is exported; rc.4: `bridgeableTokenService` is required). In: signing, signers, transport and the error model (rc.0, from gswap-sdk); the gateway token writes (rc.1, from launchpad-sdk's transfer and lock services, which now delegate here); the gateway token reads (rc.2: balances, token classes, NFT collection authorizations, from launchpad-sdk's balance and token services, which now delegate here) and the deployment endpoints; the wallet providers (`./providers`), React hooks (`./react`), wallet helpers (`createWallet` and the key derivations) and the bridge (`./bridge`: bridging, the token lists, wrap / unwrap, `createSolanaWallet`) (rc.3, from launchpad-sdk's `/wallet`, `/react`, `helpers/wallet`, `bridge/` and its bridgeable / wrappable token and wrap services, which are gone). ## Migrating from gswap-sdk 1.x See [MIGRATING-FROM-GSWAP.md](/gala-core-sdk/next/migrating-from-gswap.md): every moved export, old path to new path, and the renamed error and brand identifiers. ## License Apache License 2.0. --- # Error catalog (`@gala-chain/gala-core-sdk`) Every error the core SDK throws is a `GalaSDKError` with a stable `code`, flat `params` an app localizes, and a `phase` (`pre_send`: nothing was transmitted; `in_flight`: the request may have left; `post_send`: an answer was read). Branch on `code`, never on `message` (English, for logs). A product SDK's error class extends `GalaSDKError` and adds its own catalog: gswap-sdk's DEX codes are documented in its `docs/other/error-handling.md`. A `GSwapSDKError` can carry any code of both catalogs; `isGalaError(error)` recognises an error from any of them, and `isGalaErrorLike` / `isWalletUserRejection` (`@gala-chain/gala-core-sdk/wallet`) do so without `instanceof`, across copies of the SDK, through the registered brand `Symbol.for('@gala-chain/gala-core-sdk/error')`. How a failure is classified for Retry and "maybe queued" (`classifyFailure`) is a product SDK's decision (gswap-sdk's `failure_classification.ts`): the descriptions below say what gswap-sdk's classifier answers. {/* error-catalog:start (generated by pnpm run docs:error-catalog) */} | code | phase | params | English template (seed only) | when thrown | | --- | --- | --- | --- | --- | | `REQUEST_TIMEOUT` | `in_flight` | `url`:string, `timeoutMs`:number | Request to \{url\} timed out after \{timeoutMs\} ms. | A read or write request exceeded its timeout. A write that times out becomes `SUBMISSION_OUTCOME_UNKNOWN` (gswap-sdk) or `GATEWAY_WRITE_OUTCOME_UNKNOWN` (core `GatewayWrites`). | | `TRANSPORT_ERROR` | `in_flight` | `url`:string | The request to \{url\} failed before the server answered. | A READ failed before any answer: the default `fetch` requestor (offline, DNS, CORS), or `httpRequestorFromAxios` (an answer that is not a response, any rejection with `rejectOnHttpError: false`, an axios error without a `response` with `true`). The original error is `cause`. A requestor the app supplies is NOT wrapped (its rejection reaches you as it is), and neither is a caller abort. On a write POST the same failure is `SUBMISSION_OUTCOME_UNKNOWN` (gswap-sdk) or `GATEWAY_WRITE_OUTCOME_UNKNOWN` (core `GatewayWrites`). | | `INVALID_TIMEOUT` | `pre_send` | `field`:string, `value`:number | \{field\} must be a positive number of milliseconds, or Infinity for no timeout (got \{value\}). | A timeout option is not a positive number or Infinity. | | `GALA_WALLET_NOT_AVAILABLE` | `pre_send` | - | Gala wallet is not available. Please ensure the Gala wallet is connected. | `window.gala` is absent when `GalaWalletSigner` signs. | | `WALLET_UNAVAILABLE` | `pre_send` | - | No wallet is connected. | The ethers EIP-1193 shim has no provider (nothing connected). | | `MALFORMED_WALLET_REQUEST` | `pre_send` | `method`:string | Wallet \{method\} request is malformed. | The shim got an unreadable `eth_signTypedData_v4` / `personal_sign` request. | | `UNSUPPORTED_WALLET_METHOD` | `pre_send` | `method`:string | Unsupported wallet method \{method\}. | The shim got a method other than chainId / typed data / personal_sign. | | `INVALID_SIGNATURE` | `pre_send` | `scheme`:string | Wallet returned an invalid \{scheme\} signature. | A wallet answered with a signature that is not 130 hex digits; `params.scheme` is `native` or `personal-sign`. | | `INVALID_CHAIN_ID` | `pre_send` | `chainId`:string | Wallet returned an invalid chain id (\{chainId\}). | `eth_chainId` answered something that is not a positive integer. | | `SIGNER_ADDRESS_MISMATCH` | `pre_send` | - | The signing key does not belong to the expected account. | A lazy private-key signer whose key is not the expected account. | | `INVALID_PRIVATE_KEY` | `pre_send` | `reason`:wrong_length\|bad_encoding\|not_on_curve\|no_key_provided | Invalid private key: \{reason\}. | A key that is empty, the wrong length, mis-encoded or off the curve; `params.reason`: `no_key_provided` (the provider returned nothing, for example a locked wallet: `not_sent`, Retry is safe), `wrong_length`, `bad_encoding`, `not_on_curve` (`invalid_input`). Never carries key material. | | `SIGNING_FAILED` | `pre_send` | `method`:string, `reason`:user_rejected\|failed | Signing the \{method\} request failed (\{reason\}); nothing was sent. | The signer threw something that is not an SDK error before anything was sent: a locked wallet, an unreachable extension, a wallet that declined (`params.reason` `user_rejected`, from the wallet's own code `4001` / `ACTION_REJECTED`, or `failed`), or a signer that returned no object. `params.method` is the contract method; the original error is `cause`, and the wallet's own `code` (`4001`, `-32603`, `'ACTION_REJECTED'`) is the typed field `error.walletCode` when it set one. `not_sent`: Retry is safe. An SDK error the signer throws itself keeps its own code. | | `KEY_PROVIDER_FAILED` | `pre_send` | - | The signing key could not be fetched; nothing was sent. | The `createLazyPrivateKeySigner` key provider threw or rejected (the wallet's session slot is locked or unreadable). The original error is `cause`. `not_sent`: Retry is safe once the wallet is unlocked. | | `INVALID_SIGNING_HASH_LENGTH` | `pre_send` | `length`:number | secp256k1 can only sign a 32-byte hash (got \{length\}). | `signHash` got other than 32 bytes. | | `INVALID_WALLET_ADDRESS` | `pre_send` | `field`:string, `value`:string | Invalid \{field\}: "\{value\}" is not an accepted wallet address form. | A wallet address / `selectAddress`, a write identity or a read `owner` not in an accepted form; `params.field` names it. | | `INVALID_ETH_USER_REF_PREFIX` | `pre_send` | `field`:string, `value`:string, `expected`:string | Invalid \{field\}: "\{value\}" is not a GalaChain user reference. An eth\| reference takes the 40 hex digits of the account with no 0x prefix; write it as "\{expected\}". | An address was written `eth|0x<40 hex>`: that is not a GalaChain user reference (an `eth|` reference takes the 40 hex digits with no `0x`). `params.field` names it and `params.expected` is the correct spelling (`eth|`, or `eth|<40 hex digits>` when the digits are not a usable address). A bare `0x<40 hex>` is a normal Ethereum address and is still accepted. | | `INVALID_DECIMAL` | `pre_send` | `value`:string | Invalid decimal quantity: \{value\} | `canonicalDecimalString` got a non-finite quantity. | | `PERSONAL_SIGN_NOT_JSON` | `pre_send` | - | Personal-sign DTO is not valid JSON | `gala_signChainDto` personal-sign data is not valid JSON. | | `PERSONAL_SIGN_NOT_OBJECT` | `pre_send` | - | Personal-sign DTO must be a JSON object | The personal-sign data is JSON but not an object. | | `PERSONAL_SIGN_BAD_PREFIX` | `pre_send` | - | Personal-sign DTO prefix is not an EIP-191 "Ethereum Signed Message" header | The personal-sign `prefix` is not an EIP-191 "Ethereum Signed Message" header. | | `PERSONAL_SIGN_ENVELOPE_FIELDS` | `pre_send` | `fields`:string | Personal-sign DTO carries signing-envelope field(s): \{fields\} | The personal-sign data carries signing-envelope fields; `params.fields` lists them. | | `PERSONAL_SIGN_NOT_CANONICAL` | `pre_send` | - | Personal-sign DTO is not in canonical serialized form | The personal-sign data is not in canonical serialized form. | | `EIP712_NAME_COLLISION` | `pre_send` | `name`:string | Name collisions are not supported when deriving EIP-712 types (\{name\}). | Deriving EIP-712 types met two nested structs with one name. | | `EIP712_UNSUPPORTED_VALUE` | `pre_send` | `valueType`:string | Unsupported EIP-712 value of type \{valueType\}. | Deriving EIP-712 types met a value that has no EIP-712 type. | | `TYPED_DATA_NOT_STRING` | `pre_send` | `what`:string | Invalid typed data: \{what\} must be a string | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_UNPAIRED_SURROGATE` | `pre_send` | `what`:string | Invalid typed data: \{what\} has an unpaired surrogate | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_NOT_HEX_BYTES` | `pre_send` | `what`:string | Invalid typed data: \{what\} must be an even-length 0x hex string | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_NOT_SAFE_INTEGER` | `pre_send` | `what`:string | Invalid typed data: \{what\} must be a safe integer | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_NOT_INTEGER` | `pre_send` | `what`:string | Invalid typed data: \{what\} must be an integer | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_NOT_BOOLEAN` | `pre_send` | - | Invalid typed data: bool must be a boolean | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_BAD_ADDRESS` | `pre_send` | - | Invalid typed data: address must be 0x followed by 40 hex digits | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_BAD_CHECKSUM` | `pre_send` | - | Invalid typed data: address has a bad checksum | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_BYTES_LENGTH` | `pre_send` | `type`:string, `width`:number | Invalid typed data: \{type\} must be exactly \{width\} bytes | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_OUT_OF_BOUNDS` | `pre_send` | `type`:string | Invalid typed data: value out of bounds for \{type\} | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_UNSUPPORTED_TYPE` | `pre_send` | `type`:string | Invalid typed data: unsupported type "\{type\}" | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_FIELDS_NOT_LIST` | `pre_send` | `typeName`:string | Invalid typed data: type \{typeName\} must be a list of fields | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_FIELD_MALFORMED` | `pre_send` | `typeName`:string | Invalid typed data: type \{typeName\} has a field without a string name and type | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_INVALID_FIELD_NAME` | `pre_send` | `name`:string | Invalid typed data: invalid field name "\{name\}" | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_DUPLICATE_FIELD` | `pre_send` | `name`:string, `typeName`:string | Invalid typed data: duplicate field "\{name\}" in \{typeName\} | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_INVALID_TYPE_NAME` | `pre_send` | `name`:string | Invalid typed data: invalid type name "\{name\}" | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_CIRCULAR_TYPE` | `pre_send` | `typeName`:string | Invalid typed data: circular type reference in \{typeName\} | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_UNKNOWN_FIELD_TYPE` | `pre_send` | `type`:string, `typeName`:string | Invalid typed data: unknown type "\{type\}" in \{typeName\} | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_NO_PRIMARY_TYPE` | `pre_send` | - | Invalid typed data: missing primary type | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_AMBIGUOUS_PRIMARY_TYPE` | `pre_send` | `roots`:string | Invalid typed data: ambiguous primary types or unused types (\{roots\}) | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_ARRAY_EXPECTED` | `pre_send` | `type`:string | Invalid typed data: \{type\} array value must be an array | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_ARRAY_LENGTH_MISMATCH` | `pre_send` | - | Invalid typed data: array length mismatch | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_STRUCT_NOT_OBJECT` | `pre_send` | `typeName`:string | Invalid typed data: \{typeName\} value must be an object | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_MISSING_FIELD` | `pre_send` | `typeName`:string, `field`:string | Invalid typed data: \{typeName\} value is missing field "\{field\}" | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_DOMAIN_NOT_OBJECT` | `pre_send` | - | Invalid typed data: domain must be an object | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `TYPED_DATA_INVALID_DOMAIN_KEY` | `pre_send` | `key`:string | Invalid typed data: invalid typed-data domain key \{key\} | A dApp `eth_signTypedData_v4` payload the encoder refuses (it fails closed rather than coerce). | | `INVALID_UNIQUE_KEY` | `pre_send` | `uniqueKey`:string | The uniqueKey "\{uniqueKey\}" must be 1-128 characters of A-Z, a-z, 0-9, ".", "_", ":" or "-". | A uniqueKey outside 1-128 chars of `A-Za-z0-9._:-` (also when confirming). | | `INVALID_UNIQUE_KEY_PREFIX` | `pre_send` | `uniqueKeyPrefix`:string, `maxLength`:number | uniqueKeyPrefix "\{uniqueKeyPrefix\}" must be at most \{maxLength\} characters of A-Z, a-z, 0-9, ".", "_", ":" or "-". | A uniqueKeyPrefix that would make the key invalid. | | `CSPRNG_UNAVAILABLE` | `pre_send` | - | No cryptographically secure random source (globalThis.crypto.getRandomValues) is available to mint a uniqueKey or a new wallet; install a getRandomValues polyfill (react-native-get-random-values on Hermes). | A uniqueKey, or a new random wallet (`createWallet()`), was to be minted on a platform with no `crypto.getRandomValues` (React Native/Hermes without `react-native-get-random-values`). Nothing was sent; install the polyfill. The SDK never falls back to `Math.random` or `crypto.randomUUID` (Hermes has none). | | `INVALID_WRITES_OPTION` | `pre_send` | `option`:signer\|gatewayBaseUrl\|httpRequestor\|tokenNameResolver | GatewayWrites option \{option\} is missing or is not of the expected type. | `new GatewayWrites(...)` without a signer (an object with `signObject`) or a string `gatewayBaseUrl`, or with a requestor that is not a function or a resolver without `resolveTokenClassKey`; `params.option` names it. | | `INVALID_QUANTITY` | `pre_send` | `field`:string, `value`:string | \{field\} must be a positive decimal number of whole tokens, written as a string (got "\{value\}"). | A write quantity that is not a plain decimal string greater than zero (no sign, exponent, hex or spaces; a JS number is refused). Quantities are whole tokens, signed as written. | | `INVALID_TOKEN_REFERENCE` | `pre_send` | `field`:string, `reason`:missing\|ambiguous\|bad_class_key\|bad_instance | Invalid token reference \{field\}: \{reason\}. | A write or read names its token badly; `params.reason`: `missing`, `ambiguous` (class key and name, or a name with an instance), `bad_class_key` (a pipe key needs exactly four parts; a bare symbol is never a key; a read filter part must be a non-empty string), `bad_instance`. `params.field` is `token`, `tokens[i].token`, `tokenClassKey`, `tokenClassKeys[i]` or the filter part. | | `INVALID_TOKEN_BATCH` | `pre_send` | `method`:string, `count`:number, `max`:number | \{method\} takes 1 to \{max\} tokens (got \{count\}). | A burn (1-50), lock or unlock (1-100), or a token-class read (1-1000 keys), with no tokens or too many. | | `INVALID_LOCK_EXPIRES` | `pre_send` | `value`:string | expires must be a non-negative whole number of epoch milliseconds, 0 for none (got \{value\}). | A lock `expires` that is not a non-negative whole number of epoch milliseconds (`0` means it never expires and is kept). | | `INVALID_LOCK_NAME` | `pre_send` | `valueType`:string | The lock name must be a string (got a \{valueType\}). | A lock / unlock `name` that is not a string. | | `NO_TOKEN_NAME_RESOLVER` | `pre_send` | `tokenName`:string | The token name "\{tokenName\}" cannot be resolved: no tokenNameResolver is configured. Pass its tokenClassKey instead. | A write names a token by `tokenName` but `GatewayWrites` has no `tokenNameResolver`. | | `TOKEN_NAME_RESOLUTION_FAILED` | `pre_send` | `tokenName`:string | The token name "\{tokenName\}" could not be resolved to a token class key; nothing was sent. | The app's `tokenNameResolver` rejected (the original error is `cause`; an SDK error it throws passes through instead) or answered something that is not a key. Nothing was sent. | | `GATEWAY_WRITE_OUTCOME_UNKNOWN` | `in_flight` | `method`:string, `reason`:timeout\|transport | The outcome of \{method\} is unknown (\{reason\}): the request may have reached the gateway. Check the write by its uniqueKey before sending it again. | A gateway write's POST timed out (`params.reason` `timeout`) or failed before an answer was read, including a body that broke off (`transport`). The original error is `cause`. The write MAY have been applied: keep `error.uniqueKey` and check it; never send it again under a fresh key. | | `GATEWAY_HTTP_ERROR` | `post_send` | `method`:string, `status`:number, `serverMessage`:string (not in `message`) | The gateway answered \{method\} with HTTP \{status\}. | The gateway answered with a non-2xx status that carries no numeric top-level `Status` (a proxy page, a 5xx, the gateway's nested `{ error: { ErrorKey, Message } }` refusal). `params.serverMessage` is the chain's `Message` / the answer's `message` when it had one; a non-JSON body is `error.bodyText`. After a write it may or may not have been applied: check `error.uniqueKey`. After a read (`error.write === false`) nothing changed. | | `GATEWAY_WRITE_REJECTED` | `post_send` | `method`:string, `chainStatus`:number, `errorKey`:string, `serverMessage`:string (not in `message`) | GalaChain rejected \{method\} (Status \{chainStatus\}, error key "\{errorKey\}"). | GalaChain refused a write: its answer had a numeric `Status` other than 1, in any HTTP status (checked before an `x-transaction-id` header is trusted). `params.errorKey` / `params.serverMessage` are its `ErrorKey` / `Message`. | | `GATEWAY_RESPONSE_INVALID` | `post_send` | `method`:string | The gateway answered \{method\} with something that is not a GalaChain result; the write may have been applied. | A 2xx answer to a write that proves nothing: not a JSON object, a non-numeric `Status`, or no `Status` and no transaction id. The write may have been applied: check `error.uniqueKey`. | | `INVALID_READS_OPTION` | `pre_send` | `option`:gatewayBaseUrl\|httpRequestor | GatewayReads option \{option\} is missing or is not of the expected type. | `new GatewayReads(...)` without a string `gatewayBaseUrl`, or with a requestor that is not a function; `params.option` names it. | | `INVALID_PAGE_REQUEST` | `pre_send` | `field`:limit\|pageSize\|maxPages\|bookmark, `value`:string | \{field\} is not valid for a paginated read (got \{value\}): a page size or page count is a whole number from 1 to 10000, a bookmark a string. | A paginated read with a `limit` / `pageSize` / `maxPages` that is not a whole number from 1 to 10 000, or a `bookmark` that is not a string; `params.field` names it. Nothing was sent. | | `GATEWAY_READ_REJECTED` | `post_send` | `method`:string, `chainStatus`:number, `errorKey`:string, `serverMessage`:string (not in `message`) | GalaChain refused \{method\} (Status \{chainStatus\}, error key "\{errorKey\}"). | GalaChain refused a read: its answer had a numeric `Status` other than 1. `params.errorKey` / `params.serverMessage` are its `ErrorKey` / `Message`. A read (`error.write === false`): nothing changed, a retry is safe. | | `GATEWAY_READ_RESPONSE_INVALID` | `post_send` | `method`:string | The gateway answered \{method\} with something that is not a usable GalaChain result. | A read's answer is not a usable GalaChain result: not `{ Status: 1, Data }`, a row that is not GalaChain's (a numeric quantity, a hold without its expiry, a class without its symbol), a balance of another owner than the one asked for, or a page whose bookmark does not move on. The answer is `error.body`. | | `TOKEN_CLASS_NOT_FOUND` | `post_send` | `tokenClassKey`:string | GalaChain has no token class \{tokenClassKey\}. | GalaChain has no class for a key a token-class read asked for (its 404 `TOKEN_CLASS_NOT_FOUND`, or an answer without that key's row); `params.tokenClassKey` is the `$` composite key the chain named (`''` when it named none). | | `PAGINATION_LIMIT_EXCEEDED` | `post_send` | `method`:string, `maxPages`:number | Reading every page of \{method\} takes more than \{maxPages\} pages; narrow the filter or raise maxPages. | A `fetchAll...` read would need more than `maxPages` pages. Nothing is returned (never a truncated list): narrow the filter or raise `maxPages`. | | `WALLET_NOT_CONNECTED` | `pre_send` | `reason`:not_connected\|disconnected\|unauthorized, `operation`:string | The wallet is not connected (\{reason\}): connect it before \{operation\}. | A `./providers` wallet provider has no account: `connect()` was never called or `disconnect()` was (`not_connected`), the wallet reported a disconnection (`disconnected`: EIP-1193 4900/4901, a `disconnect` event, an `accountsChanged` with no account), or it refused the account (`unauthorized`: 4100). `params.operation` names what was attempted; a `disconnect()` while `connect()` waited for the wallet makes that `connect` fail with it too. | | `WALLET_CONNECTION_FAILED` | `pre_send` | `reason`:no_accounts\|user_rejected\|failed | Connecting to the wallet failed (\{reason\}). | `connect()` failed: the wallet answered with no account (`no_accounts`), the person declined (`user_rejected`), or anything else (`failed`, also a reported account that is not an Ethereum address). The wallet's error is `cause`. | | `INVALID_WALLET_PROVIDER_CONFIG` | `pre_send` | `missing`:eip1193_provider\|private_key_or_eip1193_provider | A wallet provider cannot be built without \{missing\}. | A wallet provider was built without what it needs: an `ExternalWalletProvider` / `GalaWalletProvider` without a provider object, `createWalletProvider` with neither a key nor a provider. | | `PRIVATE_KEY_NOT_ACCESSIBLE` | `pre_send` | - | This wallet provider signs in the wallet and cannot give out a private key; only a PrivateKeyProvider holds one. | `getPrivateKey()` on a wallet-backed provider: the key never leaves the wallet. | | `INVALID_WALLET_INPUT` | `pre_send` | `reason`:empty\|unrecognized_format\|unknown_mnemonic_word\|mnemonic_checksum | The wallet input was refused (\{reason\}): give a private key (64 hex digits) or a 12- or 24-word mnemonic. | `createWallet(input)` with an input that is empty, neither a key nor 12 / 24 words, or a mnemonic with an unknown word or a wrong checksum; `params.reason` says which, nothing of the input is shown. | | `INVALID_BRIDGE_AMOUNT` | `pre_send` | `value`:string, `reason`:not_a_number\|not_positive\|too_many_decimals | The bridge amount "\{value\}" was refused (\{reason\}). | A bridge amount that is not a finite number, not above zero, or has more decimals than the token (`toBaseUnits` never rounds). Nothing was sent. | | `UNSUPPORTED_BRIDGE_TOKEN` | `pre_send` | `network`:string, `symbol`:string | \{symbol\} cannot be bridged with \{network\}. | A token symbol the bridge has no configuration for on that network. | | `BRIDGE_NOT_CONFIGURED` | `pre_send` | `network`:Ethereum\|Solana | \{network\} bridging is not configured: give the bridge a \{network\} private key (ethereumPrivateKey / solanaPrivateKey). | An Ethereum or Solana bridge operation on a bridge built without that network's private key. | | `INVALID_TRANSACTION_HASH` | `pre_send` | `network`:Ethereum\|Solana, `value`:string | "\{value\}" is not a \{network\} transaction hash. | A transaction hash that is not in the network's format (Ethereum: `0x` plus 64 hex digits). | | `INVALID_BRIDGE_OPTION` | `pre_send` | `option`:string | The bridge option \{option\} is missing or out of range. | A bridge option missing or out of range (`params.option`), refused when the client, service or strategy is built (never as a library error at the first request): a rate limit that is not above zero, a URL that is not http(s), a bridge contract or wallet address that is not an Ethereum address, a program id or mint that is not a Solana public key, a missing signer or lookup. | | `BRIDGE_RESPONSE_INVALID` | `post_send` | `method`:string, `missing`:string | GalaConnect answered \{method\} without a usable \{missing\}; the request may have been accepted. | GalaConnect answered a bridge write without what the next step needs (`params.missing`: the bridge request id, the transaction hash, or a JSON answer at all). The request may have been accepted: check before sending it again. | | `BRIDGE_READ_RESPONSE_INVALID` | `post_send` | `method`:string | GalaConnect answered \{method\} with something that is not a usable result. | GalaConnect answered a bridge READ (configurations, fee, status, balances) with something that is not the JSON the call needs. Nothing changed (`error.write === false`). | | `BRIDGE_WRITE_OUTCOME_UNKNOWN` | `in_flight` | `method`:string | The outcome of \{method\} is unknown: the request failed in transit and may have reached GalaConnect. Check it before sending it again. | A GalaConnect bridge write (`requestBridgeOut`, `bridgeTokenOut`, `registerBridgeTransaction`) failed in transit, after any retries: the request may have reached GalaConnect. A read that fails this way is `TRANSPORT_ERROR` (`write: false`). | | `GALACONNECT_HTTP_ERROR` | `post_send` | `method`:string, `status`:number, `serverMessage`:string (not in `message`) | GalaConnect answered \{method\} with HTTP \{status\}. | GalaConnect answered a bridge call with an HTTP status other than 2xx (`params.status`; the body as `error.body`, its first 500 characters as `params.serverMessage`). `error.write` says whether the call was a write. | | `BRIDGE_TOKEN_NOT_FOUND` | `post_send` | `symbol`:string | GalaConnect has no verified bridge configuration for \{symbol\}. | GalaConnect's bridge configurations have no VERIFIED entry for the token symbol (a well-known token such as GALA or GUSDC is resolved without asking). Nothing was sent. | | `TOKEN_NOT_WRAPPABLE` | `post_send` | `tokenId`:string, `reason`:not_listed\|no_counterpart\|unknown_channel | \{tokenId\} cannot be wrapped or unwrapped (\{reason\}). | A wrap or unwrap of a token the wrappable token list does not have (`not_listed`), whose counterpart it does not have (`no_counterpart`, `params.tokenId` the counterpart), or whose channel is not one a wrap moves between (`unknown_channel`). Nothing was sent. | | `INVALID_WRAP_DIRECTION` | `pre_send` | `symbol`:string, `direction`:wrap\|unwrap | Cannot \{direction\} \{symbol\}: it is on the wrong channel for it (use the other direction). | A wrap of a token already on the asset channel, or an unwrap of one that is not on it: the other direction is the one that moves it. Nothing was sent. | | `BRIDGE_REQUEST_REJECTED` | `post_send` | `method`:string, `chainStatus`:number, `errorKey`:string, `serverMessage`:string (not in `message`) | GalaChain refused \{method\} (Status \{chainStatus\}, error key "\{errorKey\}"). | GalaChain refused a bridge write that GalaConnect relayed (an answer with `Status` other than 1: `params.chainStatus`, its `ErrorKey`, its `Message` as `params.serverMessage`). A refused `RequestTokenBridgeOut` locked nothing; a refused `BridgeTokenOut` reaches the caller inside `BRIDGE_OUT_OUTCOME_UNKNOWN` (the request before it was accepted). `error.status` is the chain's own `ErrorCode` when the answer has one: a 409 is a uniqueKey already consumed (an earlier attempt may be applied), no code cannot be judged. | | `BRIDGE_OUT_OUTCOME_UNKNOWN` | `in_flight` | `step`:request_id\|bridge_token_out\|transaction_hash, `bridgeRequestId`:string (not in `message`) | GalaConnect accepted the bridge-out request, which may have locked the tokens, then the bridge-out failed at \{step\}. Check it before bridging again. | A bridge-out failed AFTER GalaConnect accepted its `RequestTokenBridgeOut`, so the tokens may be locked: the answer had no bridge request id, `BridgeTokenOut` failed, or its answer had no transaction hash (`params.step`; the failure as `cause`). Whatever that failure was, a new bridge-out would lock the tokens again: keep `error.uniqueKey` and `params.bridgeRequestId` (empty when the id never came) and finish this one (`BridgeTokenOut` with the id) or check it. | | `BRIDGE_DEPOSIT_OUTCOME_UNKNOWN` | `in_flight` | `network`:Ethereum\|Solana, `step`:send\|confirmation\|registration, `transactionHash`:string (not in `message`) | The \{network\} bridge deposit may have been sent, then its \{step\} failed. Check the deposit before sending another. | A bridge-in deposit (Ethereum or Solana) failed once it was being sent: sending it, confirming it, or registering it with GalaConnect (`params.step`; the failure as `cause`). The funds may have left the wallet: check the deposit (`params.transactionHash`, empty when the send failed before a hash was known) and register it, never send another. Every refusal BEFORE the send is its own pre-send code. | | `BRIDGE_CHAIN_READ_FAILED` | `post_send` | `network`:Ethereum\|Solana, `call`:string | The \{network\} read \{call\} failed or answered something unusable; nothing was sent. | A read of the external chain (`params.call`: a token balance, allowance, name or permit nonce, a token account, the bridge program's mint lookup) failed or answered something unusable (the failure, if any, as `cause`). Nothing was sent. | | `INSUFFICIENT_BRIDGE_BALANCE` | `pre_send` | `network`:Ethereum\|Solana, `symbol`:string, `needed`:string, `available`:string | The \{network\} balance of \{symbol\} is \{available\}; the bridge needs \{needed\}. | The wallet's balance of the token on the external chain is below the bridge-in amount (`params.needed`, `params.available`, as decimals). Nothing was sent. | | `BRIDGE_STATUS_TIMEOUT` | `in_flight` | `transactionHash`:string (not in `message`), `timeoutMs`:number, `lastStatus`:number | The bridge transaction did not reach a final status within \{timeoutMs\} ms (last status \{lastStatus\}); it may still complete. | `waitForCompletion` reached its timeout before the bridge transaction reached a final status (`params.lastStatus`, a `BridgeStatusCode`). The transaction may still complete: wait again or read its status. | | `WALLET_CONTEXT_MISSING` | `pre_send` | - | The wallet hooks and the wallet context need a WalletProvider above them. | A `./react` wallet hook (or the context value outside any provider) was used with no `WalletProvider` above it. | {/* error-catalog:end */} --- # Migrating from `@gala-chain/gswap-sdk` 1.x to `@gala-chain/gala-core-sdk` `@gala-chain/gswap-sdk` 2.0.0 no longer ships the signing, transport, wallet-helper and base-error layer. It moved, unchanged in behaviour, into `@gala-chain/gala-core-sdk` (1.0.0-rc.0), which gswap-sdk 2.0 takes as a **peer dependency** (the range is in gswap-sdk's `peerDependencies`). There are no re-exports: an app imports each moved symbol from core. This page is the mechanical migration table for any app that imported those symbols from gswap-sdk 1.x. ```bash npm install @gala-chain/gswap-sdk@next @gala-chain/gala-core-sdk@next ``` Both are release candidates under the `next` dist-tag (`^2` matches no prerelease); an app build pins the exact versions. Install exactly one copy of core (a peer, never a nested dependency): `npm ls @gala-chain/gala-core-sdk` must show one version. Two copies would split `instanceof GalaSDKError` and the signer classes. ## 1. Imports that change path only (same name, same behaviour) Every row: `import { X } from '@gala-chain/gswap-sdk'` becomes `import { X } from '@gala-chain/gala-core-sdk'`. | Area | Moved exports (values) | Moved exports (types) | | --- | --- | --- | | Signers | `PrivateKeySigner`, `GalaWalletSigner`, `BrowserWalletSigner`, `createLazyPrivateKeySigner`, `ethereumAddressOfAccount` | `GalaChainSigner`, `SignedDto`, `BrowserWalletProvider`, `GalaWalletScheme`, `PrivateKeyProvider`, `LazyPrivateKeySignerOptions` | | Signing primitives | `serialize`, `getPayloadToSign`, `signNative`, `signSerializedNative`, `signPersonalMessage`, `calculatePersonalSignPrefix`, `personalSignPrefixFor`, `fixpointPrefixFor`, `normalizePrivateKey`, `ethAddressOfPrivateKey` | | | Wallet signing (string keys) | `signChainDtoNative`, `signChainDtoHash`, `signChainDtoPersonalSign`, `resolvePersonalSignChainDtoPayload`, `signRawObject`, `withPrivateKey`, `stripEip712DomainType`, `tokenClassDollarKey`, `canonicalDecimalString` | `PersonalSignChainDtoPayload`, `PrivateKeyInput` | | EIP-712 and typed data | `generateEIP712Types`, `buildEIP712Payload`, `eip712DomainFor`, `EIP712_CAPABLE_METHODS`, `hashTypedData`, `signTypedDataPayload` | `EIP712Types`, `EIP712DomainValue`, `TypedDataPayload` | | Transport adapters | `httpRequestorFromAxios`, `eip1193ProviderFromEthers`, `isFetchTransportFailure` | `AxiosLikeInstance`, `AxiosLikeConfig`, `AxiosLikeResponse`, `AxiosRequestorOptions`, `EthersLikeSigner`, `EthersLikeProvider`, `EthersEip1193Options`, `WireOptions` | | Token class keys | `compositeKeyOf`, `tryParseCompositeKey`, `tryParseTokenClassKey` | `GalaChainTokenClassKey` | | uniqueKeys | `createUniqueKey`, `assertUniqueKey`, `resolveUniqueKeyPrefix`, `isValidUniqueKey`, `DEFAULT_UNIQUE_KEY_PREFIX` | `UniqueKeyOptions` | | Failure views | `toFailureView`, `isWriteView`, `FAILURE_OUTCOMES` | `FailureView`, `FailureOutcome` | | Error reasons (closed sets) | `INVALID_PRIVATE_KEY_REASONS`, `SIGNING_FAILURE_REASONS` | `InvalidPrivateKeyReason`, `SigningFailureReason` | | Wallet helpers | `isWalletUserRejection`, `walletDeclineCode` | | | Error helpers | `parseJson` | | Everything else stays in `@gala-chain/gswap-sdk`: `GSwap` and its services, `ChainGateway`, `GSwapSDKError`, `isGSwapError`, `isPreSendError`, `classifyFailure`, `mayHaveBeenQueued`, the guards (`isRelayableRefusal`, `isNoMarket`, `chainErrorKeyOf`, ...), `pendingSwapFateFor`, the builders, tick math, `getObjectProperty`, `getStringProperty`, `UPDATE_REQUIRED_STATUS`. ## 2. Renamed while moving | gswap-sdk 1.x | gala-core-sdk | | --- | --- | | `isGSwapErrorLike` | `isGalaErrorLike` | | `type GSwapErrorShape` | `type GalaErrorShape` | | `GSWAP_ERROR_PHASES` | `GALA_ERROR_PHASES` | | `type GSwapErrorPhase` | `type GalaErrorPhase` | | `type GSwapErrorContext` | `type GalaErrorContext` | | `renderGSwapErrorTemplate` | `renderGalaErrorTemplate` | | brand `Symbol.for('@gala-chain/gswap-sdk/error')` | brand `Symbol.for('@gala-chain/gala-core-sdk/error')` | | subpath `@gala-chain/gswap-sdk/wallet` (`isGSwapErrorLike`, `isWalletUserRejection`, `walletDeclineCode`) | subpath `@gala-chain/gala-core-sdk/wallet` (`isGalaErrorLike`, `isWalletUserRejection`, `walletDeclineCode`) | The brand change matters only across versions: a gswap-sdk **1.x** error object (old brand) is still recognised by `isGalaErrorLike` / `isWalletUserRejection` through its shape (a string `code` and object `params`), but `hasGalaErrorBrand` is `false` for it. Upgrade every bundle that throws or reads SDK errors together. ## 3. Behaviour an app may rely on, and what changed - **The error class.** Core's `GalaSDKError` is the base class; `GSwapSDKError extends GalaSDKError` and carries the same fields (`code`, `params`, `phase`, `status`, `body`, `bodyText`, `url`, `uniqueKey`, `write`, `shadow`, `walletCode`, `retryAfterMs`, ...). Errors that core throws itself (a signer, `normalizePrivateKey`, the fetch requestor's `TRANSPORT_ERROR`, `requestWithTimeout`'s `REQUEST_TIMEOUT`, `validateTimeoutMs`, `resolveUniqueKeyPrefix`) are plain `GalaSDKError`s and **not** `instanceof GSwapSDKError`. Replace `error instanceof GSwapSDKError` with `isGSwapError(error)` (gswap-sdk; recognises both) or `isGalaError(error)` (core). `isGSwapError(error, 'INVALID_PRIVATE_KEY')` keeps working for a core code thrown by core. - **The catalogs are split, one code per catalog.** `GALA_ERROR_CATALOG` (core) holds the 52 signing / transport / wallet / typed-data / uniqueKey codes; gswap-sdk's `GSWAP_ERROR_CATALOG`, `gswapErrorTemplates` and `GSWAP_ERROR_PHASE_BY_CODE` hold only the DEX codes. An app that seeds its translations from the templates merges `galaErrorTemplates` (core) and `gswapErrorTemplates`. A `GSwapSDKError` can carry a code of either catalog (`GSwapErrorCode` is the union), and `classifyFailure` / `isPreSendError` / the guards answer for both exactly as in 1.x. - **No code changed meaning.** Every one of the 135 codes of gswap-sdk 1.2 keeps its template, params, phase and classification. One code is new: `CSPRNG_UNAVAILABLE` (below). - **uniqueKeys are minted with `crypto.getRandomValues`, never `crypto.randomUUID`** (React Native/Hermes has no `randomUUID`). The format is unchanged (``, lowercase 8-4-4-4-12). With no `getRandomValues` the mint throws `CSPRNG_UNAVAILABLE` (`pre_send`): install `react-native-get-random-values` on React Native. A test that pinned the key by stubbing `crypto.randomUUID` now stubs `crypto.getRandomValues` (the 16 bytes of the wanted UUID). - **User-Agent.** The default request header is still `GalaChain-SDK/`, and the version is now core's package version (`GALA_CORE_SDK_VERSION`), not gswap-sdk's. Set `wire.userAgent` to pin your own. - **No Node globals.** Core's shipped source uses no Node builtin, no `Buffer`, no `process`, and never loads `ethers`, `axios` or `@gala-chain/api` (a CI guard, `pnpm run check:rn-safety`, enforces it). The only polyfill React Native needs is `getRandomValues`. ## 4. New in core (no 1.x equivalent) `GalaSDKError`, `isGalaError`, `AnyGalaError`, `GALA_ERROR_CATALOG`, `galaErrorTemplates`, `GALA_ERROR_PHASE_BY_CODE`, `isGalaCatalogCode`, `hasGalaErrorBrand`, `templatePlaceholders`, `signPreSend` (the "nothing was sent" wrapper around an app signer), the transport pieces gswap-sdk used internally (`fetchRequestor`, `requestWithTimeout`, `buildRequestHeaders`, `buildQueryString`, `readHeader`, `readRetryAfter`, `readBlockNumberHeader`, `readResponseBody`, `armTimeout`, `validateTimeoutMs`, types `HttpRequestor`, `HTTPResponse`, `RequestHeaderParts`), the failure-view readers `stringParamOf` / `numberParamOf`, `splitClassKey`, and `GALA_CORE_SDK_VERSION`. ## 5. Mechanical migration, per app 1. Add `@gala-chain/gala-core-sdk` to dependencies next to `@gala-chain/gswap-sdk@^2`. 2. For every import of a symbol in section 1, change the module to `@gala-chain/gala-core-sdk`. 3. Apply the renames of section 2 (including `@gala-chain/gswap-sdk/wallet` → `@gala-chain/gala-core-sdk/wallet`). 4. Replace `instanceof GSwapSDKError` with `isGSwapError(...)` (section 3). 5. Seed translations from `galaErrorTemplates` and `gswapErrorTemplates` together. 6. On React Native, import `react-native-get-random-values` once at startup. # gSwap SDK 2.0.0-rc.4 (@gala-chain/gswap-sdk) The TypeScript SDK for the GalaChain DEX contract: quoting, queued swaps, liquidity positions, market data and the realtime stream. --- # Agent guide: gswap-sdk This page is for an AI agent (or a developer working with one) that writes code against `@gala-chain/gswap-sdk`, the client of the GSwap DEX. Every recipe compiles against the package's built types (the docs build fails otherwise), and every invariant names the test or golden that enforces it. ## Which package for which job | Job | Package | | --- | --- | | Quote, swap, manage liquidity, read pools, positions and market data on GSwap | `@gala-chain/gswap-sdk` (this package) | | Signers, wallet providers, plain token transfers and balance reads | `@gala-chain/gala-core-sdk` (the peer dependency of this package) | | Buy and sell a bonding-curve token before it graduates, launch a token | `@gala-chain/launchpad-sdk` | | The same abilities as MCP tools | `@gala-chain/gala-mcp-server` | Install with `npm install @gala-chain/gswap-sdk@next` and the core peer next to it (range `>=1.0.0-rc.7 <2`). ## Recipes ### Create the client ```ts import { GSwap } from '@gala-chain/gswap-sdk'; import { PrivateKeySigner, getEthereumAddressFromPrivateKey } from '@gala-chain/gala-core-sdk'; const privateKey = process.env.GALACHAIN_PRIVATE_KEY!; const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(privateKey), walletAddress: getEthereumAddressFromPrivateKey(privateKey), }); console.log(gSwap.pools !== undefined); ``` ### Quote a swap A quote is a read: it signs nothing and spends nothing. ```ts import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); const quote = await gSwap.quoting.quoteExactInput('GALA|Unit|none|none', 'GUSDC|Unit|none|none', '100'); console.log(quote.feeTier, quote.amountOut); ``` ### Swap and confirm A swap is queued. The acknowledgement means the chain accepted the request, not that it executed: `confirm()` reads the applied trade or throws the chain's rejection. ```ts import { GSwap } from '@gala-chain/gswap-sdk'; import { PrivateKeySigner, getEthereumAddressFromPrivateKey } from '@gala-chain/gala-core-sdk'; const privateKey = process.env.GALACHAIN_PRIVATE_KEY!; const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(privateKey), walletAddress: getEthereumAddressFromPrivateKey(privateKey), }); const quote = await gSwap.quoting.quoteExactInput('GALA|Unit|none|none', 'GUSDC|Unit|none|none', '100'); const submitted = await gSwap.swaps.swap('GALA|Unit|none|none', 'GUSDC|Unit|none|none', quote.feeTier, { exactIn: '100', amountOutMinimum: quote.amountOut, }); console.log(submitted.mode, submitted.uniqueKey); const applied = await submitted.confirm(); console.log(applied.transactionId, applied.result); ``` ### Add liquidity at a tick range ```ts import { GSwap } from '@gala-chain/gswap-sdk'; import { PrivateKeySigner, getEthereumAddressFromPrivateKey } from '@gala-chain/gala-core-sdk'; const privateKey = process.env.GALACHAIN_PRIVATE_KEY!; const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(privateKey), walletAddress: getEthereumAddressFromPrivateKey(privateKey), }); const added = await gSwap.positions.addLiquidityByTicks({ token0: 'GALA', token1: 'GUSDC', fee: 3000, tickLower: -6000, tickUpper: 6000, amount: '100', amountIsToken0: true, }); await added.confirm(); ``` ### Recover from an unknown submission ```ts import { GSwap } from '@gala-chain/gswap-sdk'; import { PrivateKeySigner, getEthereumAddressFromPrivateKey, isGalaError } from '@gala-chain/gala-core-sdk'; const privateKey = process.env.GALACHAIN_PRIVATE_KEY!; const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(privateKey), walletAddress: getEthereumAddressFromPrivateKey(privateKey), }); try { await gSwap.swaps.swap('GALA|Unit|none|none', 'GUSDC|Unit|none|none', 3000, { exactIn: '100', amountOutMinimum: '1' }); } catch (error) { if (isGalaError(error) && error.code === 'SUBMISSION_OUTCOME_UNKNOWN') { // The write may have been queued: confirm by its uniqueKey, never submit a second swap blindly. console.log('check before retrying:', error.uniqueKey); } else { throw error; } } ``` ## Invariants - The SDK signs through core's signers, and its DTO builders produce exactly the DTOs (key order included) of the pinned golden builder cases. Enforced by `packages/gswap-sdk/tests/builder-parity.test.ts` ("DTO builder parity with the golden builders") and the golden `packages/gala-core-sdk/tests/fixtures/frontend-signing-golden.json` ("builders.0"). - A swap is queued: the acknowledgement is not execution. `confirm()` reads the applied trade by its `uniqueKey` without resubmitting, and surfaces a chain rejection. Enforced by `packages/gswap-sdk/tests/swaps.test.ts` ("confirms a swap by uniqueKey from apply-results without resubmitting") and `packages/gswap-sdk/tests/swaps.test.ts` ("surfaces the chain rejection when confirming a rejected swap by uniqueKey"). - Slippage bounds travel as the decimal strings you gave (non-negative), and a swap with a non-positive quantity is refused. Enforced by `packages/gswap-sdk/tests/swaps.test.ts` ("preserves non-negative slippage bounds as decimal strings and appends the signer result") and `packages/gswap-sdk/tests/swaps.test.ts` ("builds exact-output slippage and rejects non-positive quantities"). - Amounts are decimal strings: a JavaScript number is refused, naming the field. Enforced by `packages/gswap-sdk/tests/validation.test.ts` ("should reject a JavaScript number, naming the field"). - A user reference is `eth|` or a `client|` alias: every Ethereum spelling is converted, a wrong mixed-case checksum is refused. Enforced by `packages/gswap-sdk/tests/validation.test.ts` ("sends every spelling of an Ethereum account as eth|") and `packages/gswap-sdk/tests/validation.test.ts` ("refuses a wrong-checksum mixed-case account and anything else, naming the field"). - `eth|0x` is not an address form and is REFUSED with core's `INVALID_ETH_USER_REF_PREFIX`, naming the right spelling. Enforced by `packages/gswap-sdk/tests/validation.test.ts` ("refuses eth|0x as core's INVALID_ETH_USER_REF_PREFIX (not an address form), naming the right one"). - A class key carries no symbol: it is parsed from the right and a symbol is looked up in the registry, never derived from a key. Enforced by `packages/gswap-sdk/tests/symbol-key-independence.test.ts` ("class keys carry no symbol"). - A write POST that gets no answer (a timeout, or a connection that failed) is `SUBMISSION_OUTCOME_UNKNOWN` with its reason and the `uniqueKey`; a failed read keeps `TRANSPORT_ERROR`. Enforced by `packages/gswap-sdk/tests/submission_outcome_unknown.test.ts` ("a write POST that gets no answer is SUBMISSION_OUTCOME_UNKNOWN, with the reason") and `packages/gswap-sdk/tests/submission_outcome_unknown.test.ts` ("reads keep TRANSPORT_ERROR: only a state-changing submit is an unknown outcome"). - Every attempt mints a fresh `uniqueKey`; a custom prefix that would make the key unreadable by apply-results is refused. Enforced by `packages/gswap-sdk/tests/builder-parity.test.ts` ("mints a fresh uniqueKey per attempt, with the default prefix") and `packages/gswap-sdk/tests/builder-parity.test.ts` ("rejects a uniqueKeyPrefix that would make the key unreadable by apply-results"). ## Error codes Branch on `error.code`; a `GSwapSDKError` also carries core's codes. The full lists are at `/errors.json` (every SDK) and in the error handling page of this package. | Code | Meaning | Fix | | --- | --- | --- | | `SUBMISSION_OUTCOME_UNKNOWN` | The write POST got no answer (timeout or lost connection). | Confirm by `error.uniqueKey` before any retry. | | `CONFIRMATION_TIMEOUT` | `confirm()` did not see the apply result in time. | Call `confirm()` again with the same `uniqueKey`; do not resubmit. | | `CHAIN_REJECTED` | The chain applied the request and rejected it. | Read `error.body`; fix the input and submit a new swap. | | `INSUFFICIENT_LIQUIDITY` | The pool cannot fill the amount. | Quote a smaller amount or another fee tier. | | `NO_POOL_AVAILABLE` | No pool exists for the pair. | Check the pair and fee tier with `gSwap.pools`. | | `NO_SIGNER` | A write was attempted on a client built without a signer. | Pass `signer` and `walletAddress` to the constructor. | | `AMOUNT_IS_JS_NUMBER` | A JavaScript number was given as an amount. | Pass the amount as a decimal string. | | `TICKS_NOT_ALIGNED` | A tick is not divisible by the fee tier's spacing. | Align the ticks, or use `addLiquidityByPrice`. | | `RATE_LIMITED` | The backend asked the client to slow down. | Wait `error.retryAfterMs` and retry the read. | | `UPDATE_REQUIRED` | The backend refuses this client version (HTTP 426). | Upgrade the SDK. | | `INVALID_ETH_USER_REF_PREFIX` | An address was written `eth\|0x`. | Write `eth\|` or the bare `0x`. | --- # gSwap SDK `@gala-chain/gswap-sdk` is the TypeScript SDK for the current GalaChain DEX contract. It uses trading symbols for pool operations, signs writes with the signer supplied by the application, and submits them through the Chain Gateway. Swap requests are queued for later application. Pools are identified by trading symbols: the SDK resolves class keys through the symbol registry and orders `token0` and `token1` with plain string ordering. The public surface is grouped by responsibility: - `gSwap.quoting` runs read-only exact-input and exact-output simulations. - `gSwap.swaps` submits queued `RequestTrade` DTOs. - `gSwap.pools` reads pools, slot0, and composite pool snapshots. - `gSwap.positions` reads positions and submits liquidity operations. - `gSwap.assets` reads user balances; `gSwap.symbols` resolves symbols. All reads and writes go through the configured swap backend. The SDK signs the DTO, posts writes to the method-specific chain-gateway backend route, and returns a `SubmittedTransaction`. Swap acknowledgements are queued; call `confirm()` to read the applied trade or chain rejection. There is no bundler or socket waiter, and EIP-712 is only an opt-in scheme of `BrowserWalletSigner`. ## Install ```bash npm install @gala-chain/gswap-sdk@next @gala-chain/gala-core-sdk@next ``` `@gala-chain/gala-core-sdk` is a peer dependency (range >=1.0.0-rc.7 <2): install it next to the SDK. 2.0 is a release candidate under the `next` dist-tag; `latest` is still 1.2.0, so an install without `@next` gets 1.x. Pin exact versions for a wallet or app build. ## 2.0: signing moved to @gala-chain/gala-core-sdk Since 2.0.0 the signing, transport, wallet-helper and base-error layer lives in `@gala-chain/gala-core-sdk`. This package no longer exports or re-exports it: signers (`PrivateKeySigner`, `GalaWalletSigner`, `BrowserWalletSigner`), the signing and EIP-712 primitives, the transport adapters, the failure views, the unique-key helpers and the wallet helpers are imported from the core package. `GSwap`, the DEX API and the DEX error catalog stay here. The old `@gala-chain/gswap-sdk/wallet` subpath is now `@gala-chain/gala-core-sdk/wallet`, and some identifiers were renamed (`isGSwapErrorLike` is `isGalaErrorLike`). The full old-path to new-path table is in [`../gala-core-sdk/MIGRATING-FROM-GSWAP.md`](/gala-core-sdk/next/migrating-from-gswap.md); see also [Migration from 0.x](/gswap-sdk/next/other/migration-from-0x.md). ## Quick start ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; const signer = new PrivateKeySigner(process.env.GALACHAIN_PRIVATE_KEY!); const gSwap = new GSwap({ signer, walletAddress: process.env.GALACHAIN_ADDRESS, env: 'stage' }); const quote = await gSwap.quoting.quoteExactInput('GALA', 'GUSDC', '100'); const tx = await gSwap.swaps.swap('GALA', 'GUSDC', quote.feeTier, { exactIn: '100', amountOutMinimum: quote.amountOut, }); console.log({ mode: tx.mode, uniqueKey: tx.uniqueKey, transactionId: tx.transactionId }); const applied = await tx.confirm(); console.log(applied.result); ``` The `env: 'stage'` preset targets the staging swap backend, and `prod` targets the production swap backend. All SDK traffic uses the swap backend. Use class keys such as `GALA|Unit|none|none` when a symbol is not available; the SDK resolves registered symbols and orders pool tokens for you. Every write returns a `SubmittedTransaction`. A swap acknowledgement has `mode === 'queued'`, `result === undefined`, and a durable `uniqueKey`; call `confirm()` to read its applied outcome, or `swaps.confirmSwap(uniqueKey)` to resolve it later from the persisted key alone. Liquidity writes continue to confirm by re-reading position state. A request `transactionId` may be `null` when the gateway does not provide one. ## Market data and leaderboard Public reads, no signer needed: USD prices (`market.getPrices`, 1-500 tokens, split into requests the backend accepts, each read under the exact id it was asked for), price series (`market.getPriceSeries`, windows `1D` `1W` `1M` `1Y` `ALL`), platform volume (`market.getVolumeSummary`) and the trading-competition seasons and rankings (`leaderboard.getSeasons`, `getCurrentSeason`, `getLeaderboard`, `getCurrentLeaderboard`). See [Market Data and Leaderboard](/gswap-sdk/next/tutorial/market-data.md). ```typescript const gala = await gSwap.market.getPrice('GALA$Unit$none$none'); // undefined: no entry const series = await gSwap.market.getPriceSeries('GALA$Unit$none$none', '1W'); const season = await gSwap.leaderboard.getCurrentSeason(); // null between seasons ``` ## Onramper widget URL `gSwap.onramper.generateWidgetUrl(request)` asks the swap backend for a signed Onramper (fiat on-ramp) widget URL. The route is public: the request carries no `Authorization` header. An app that needs only this builds the small service without a whole client: ```typescript import { createOnramper } from '@gala-chain/gswap-sdk'; const onramper = createOnramper({ dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com' }); const url = await onramper.generateWidgetUrl({ walletAddress: '0x…', defaultCrypto: 'gala', mode: 'buy' }); ``` ## Hosts and environment presets The SDK has one network boundary: the swap backend. It does not call public GalaChain gateway hosts directly. | Preset | Targets | | ------- | --------------------------------------------------------------- | | `stage` | The staging swap backend (the preset sets `dexBackendBaseUrl`) | | `prod` | `https://dex-backend-prod1.defi.gala.com` | Use `dexBackendBaseUrl` for a test or private deployment override. ## Realtime stream `gSwap.stream` is a client for the realtime stream (`wss://…/ws`, JSON-RPC 2.0): live swaps, liquidity adds/removes/collects, pool and balance changes, new pools and blocks, with automatic reconnect. ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); await gSwap.stream.connect(); await gSwap.stream.subscribeLiquidity((e) => console.log(e.action, e.owner, e.amount0, e.amount1)); ``` See the [realtime stream guide](/gswap-sdk/next/tutorial/realtime-stream.md). ## Signers and identity | Signer | Scheme | Identity resolved by the chain | | --------------------- | ------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------- | | `PrivateKeySigner` | GalaChain native signature | Recovered from the private key | | `GalaWalletSigner` | Native `gala_signChainDto`; opt-in `personal-sign` needs a Gala Wallet build that signs the bare DTO (see Signing and Identity) | Selected account (`0x...`, `eth\|...`, `client\|...`) | | `BrowserWalletSigner` | EIP-1193 `personal_sign`; opt-in `{ scheme: 'eip712' }` (`eth_signTypedData_v4`) | Selected Ethereum account (`eip712` also resolves a `client\|` alias) | The signers are exported by `@gala-chain/gala-core-sdk`, not by this package. Native signing is the default for server keys and current Gala Wallets. Browser wallet personal-sign signs the bare serialized DTO (the wallet applies the EIP-191 header) and sends that header as the DTO's `prefix`, which is what the chain prepends when it recovers the signer. EIP-712 is opt-in on `BrowserWalletSigner` for `RequestTrade`, `AddLiquidity`, `RemoveLiquidity` and `CollectPositionFees` (`CreatePool` still uses personal-sign); it is not the default and not part of the Gala Wallet path. See [Signing and Identity](/gswap-sdk/next/other/signing-and-identity.md). ## Wallet and app integration The SDK core is platform neutral (only `fetch`, `globalThis.crypto` and timers) and ships the building blocks a wallet or app needs, each behind an adapter: `confirmAppliedTrade` (apply-results polling with `AbortSignal`, `AppliedTradeError`), `PendingSwapStore` (async `StorageAdapter`; `storageAdapterFromChromeStorage(chrome.storage.local)` for an extension, `webStorageAdapter(localStorage)` for a web app), `DexFees` (DryRun fee quotes), `swaps.swapShadow` (dark swaps through `X-Shadow`), a configurable `uniqueKeyPrefix`, and the realtime stream with an injected `WebSocket` (and an `apiKey` for server-side clients). See [App and Wallet Integration](/gswap-sdk/next/other/app-integration.md). Errors carry a stable `code` and flat `params` that an app localizes; `classifyFailure`, `pendingSwapFateFor`, `isNoMarket` and the other deciders answer retry and outcome questions from the code, never from message text ([Error Handling](/gswap-sdk/next/other/error-handling.md)). App-shell code that must not load the SDK imports its wallet helpers from `@gala-chain/gala-core-sdk/wallet` ([Bundle size](/gswap-sdk/next/other/bundle-size.md)). Tick and price math, including the contract's in-range rule, is in [Tick and Price Math](/gswap-sdk/next/other/tick-and-price-math.md). ## Documentation Start with [Getting started](/gswap-sdk/next/getting-started.md), then follow the tutorials for [quoting](/gswap-sdk/next/tutorial/quoting.md), [trading](/gswap-sdk/next/tutorial/trading.md) and [liquidity management](/gswap-sdk/next/tutorial/liquidity-management.md). For apps and wallets: [Error handling](/gswap-sdk/next/other/error-handling.md) (the error catalog, `classifyFailure`, localization), [App and wallet integration](/gswap-sdk/next/other/app-integration.md) (pending-swap storage, wire options, signing primitives, dark swaps), [Signing and identity](/gswap-sdk/next/other/signing-and-identity.md), [Bundle size](/gswap-sdk/next/other/bundle-size.md) (the `@gala-chain/gala-core-sdk/wallet` subpath and shell-safe helpers) and [Tick and price math](/gswap-sdk/next/other/tick-and-price-math.md). The API reference is generated from the package's TSDoc. The site at galachain.github.io/gswap-sdk describes the 1.x API only. Working examples are in `examples/cli`, `examples/full_dex` and `examples/demos` of the package (runnable scripts for swaps, quotes, pools, liquidity positions, fees, market data, leaderboards and pool watching). ## License This SDK is provided under the Apache License 2.0. Gala™, GalaChain™, and related marks are trademarks of Blockchain Game Partners Inc. This software is provided “AS IS” without warranties of any kind. --- # Getting Started ## Install ```bash npm install @gala-chain/gswap-sdk@next @gala-chain/gala-core-sdk@next ``` These docs describe 2.0, a release candidate under the `next` dist-tag (`latest` is still 1.2.0). Pin an exact version in an app build. `@gala-chain/gala-core-sdk` is a peer dependency (range `>=1.0.0-rc.7 <2`) that provides the signers and the signing, transport and wallet helpers. The SDK supports Node.js and browser bundlers. For a server application, use `PrivateKeySigner`; for Gala Wallet use `GalaWalletSigner`; for an EIP-1193 provider such as MetaMask use `BrowserWalletSigner`. All three are imported from `@gala-chain/gala-core-sdk`. ## Configure an environment `env: 'stage'` selects the staging swap backend and `env: 'prod'` selects the production swap backend. The SDK sends every read and write through that backend. `dexBackendBaseUrl` overrides the preset, which is useful for tests and private deployments. | Preset | Backend | | ------- | -------------------------------------------------------------- | | `stage` | The staging swap backend (the preset sets `dexBackendBaseUrl`) | | `prod` | `https://dex-backend-prod1.defi.gala.com` | The swap backend is the only host used by the SDK; it does not call public GalaChain gateway hosts directly. ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(process.env.GALACHAIN_PRIVATE_KEY!), walletAddress: process.env.GALACHAIN_ADDRESS, }); ``` Keep private keys in environment variables or a secret manager. Never commit a key or use a production key in a test. ## Read, quote, and write Tokens may be a registered trading symbol (`GALA`) or a full class key (`GALA|Unit|none|none`). The SDK resolves symbols and canonicalizes token ordering for the caller. Quotes are read-only and run against the backend's offline v2 engine: ```typescript const quote = await gSwap.quoting.quoteExactInput('GALA', 'GUSDC', '100'); console.log(quote.feeTier, quote.amountOut); const tx = await gSwap.swaps.swap('GALA', 'GUSDC', quote.feeTier, { exactIn: '100', amountOutMinimum: quote.amountOut, }); console.log(tx.mode, tx.uniqueKey, tx.transactionId, tx.result); const applied = await tx.confirm(); console.log(applied.result); ``` Swap writes are queued: `tx.mode` is `'queued'`, `tx.result` is `undefined`, and the acknowledgement means the chain accepted the request, not that it has executed. `await tx.confirm()` reads the applied trade or chain rejection from the durable `uniqueKey`; liquidity operations continue to re-read the affected position. See [Transaction Status](/gswap-sdk/next/tutorial/transaction-status.md). ## Browser setup ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; import { BrowserWalletSigner } from '@gala-chain/gala-core-sdk'; // `window.ethereum` is the EIP-1193 provider your wallet injects (typed by your wallet typings). const provider = window.ethereum; const [address] = (await provider.request({ method: 'eth_requestAccounts' })) as [string]; const gSwap = new GSwap({ env: 'stage', signer: new BrowserWalletSigner(provider, address), walletAddress: address, }); ``` `BrowserWalletSigner` uses `personal_sign`. Gala Wallet integrations should use `GalaWalletSigner`, which uses native `gala_signChainDto`. There is no automatic personal-sign fallback. See [Signing and Identity](/gswap-sdk/next/other/signing-and-identity.md). ## Next steps - [Quoting](/gswap-sdk/next/tutorial/quoting.md) - [Trading](/gswap-sdk/next/tutorial/trading.md) - [Liquidity Management](/gswap-sdk/next/tutorial/liquidity-management.md) - [Migration from 0.x](/gswap-sdk/next/other/migration-from-0x.md) --- # gSwap for Uniswap Users gSwap uses familiar concentrated-liquidity ideas, but its contract and transaction model are different from Uniswap V3. | Concept | Uniswap V3 | gSwap SDK | | --- | --- | --- | | Pool identity | Token addresses plus fee | Registered trading symbols plus fee | | Token input | ERC-20 address | Symbol or GalaChain class key | | Amounts | Raw integer units | Human-readable decimal strings | | Quote | Quoter contract call | Backend offline quote engine | | Write path | Router transaction | Signed DTO through Chain Gateway | | Confirmation | Transaction receipt | Queued swap acknowledgement, then `SubmittedTransaction.confirm()` | | Position identity | NFT `tokenId` | Pool, owner, and tick range; no `positionId` | | Fee tiers | Deployment-specific | `0`, `500`, `3000`, `10000` | ## Quotes Uniswap's `quoteExactInputSingle` is replaced by a read-only SDK method. An omitted fee compares every available v2 tier: ```typescript const quote = await gSwap.quoting.quoteExactInput('GWETH', 'GUSDC', '0.1'); console.log(quote.feeTier, quote.amountOut, quote.totalFees); const exactOutput = await gSwap.quoting.quoteExactOutput('GWETH', 'GUSDC', '3000', 3000); ``` ## Swaps The v2 SDK accepts the same exact-input/exact-output intent, but the slippage fields are explicit and the signer is configured on the client: ```typescript const tx = await gSwap.swaps.swap('GWETH', 'GUSDC', quote.feeTier, { exactIn: '0.1', amountOutMinimum: quote.amountOut, }); console.log(tx.mode, tx.uniqueKey, tx.transactionId); const applied = await tx.confirm(); console.log(applied.result); ``` The Chain Gateway receives the signed DTO at `/v1/chain/asset/dex-contract/RequestTrade`. The acknowledgement is queued, so `confirm()` reads the applied outcome from apply-results. There is no router ABI, bundler, or socket event subscription. Persist `tx.uniqueKey` so an uncertain submit or confirmation can be checked again without resubmitting. ## Liquidity Uniswap's NFT mint is a gSwap AddLiquidity write. The position is merged by pool, owner, and tick range, and an add operation supplies exactly one deposit side: ```typescript const tx = await gSwap.positions.addLiquidityByTicks({ token0: 'GUSDC', token1: 'GWETH', fee: 3000, tickLower: -6000, tickUpper: 6000, amount: '3000', amountIsToken0: true, }); await tx.confirm(); ``` Use `addLiquidityByPrice` when a UI collects token1-per-token0 prices. The SDK converts prices to spacing-aligned ticks. Spacing is `200` for fee `0`, `10` for `500`, `60` for `3000`, and `200` for `10000`. `removeLiquidity` takes an optional token withdrawal quantity. Omitting both quantities closes the position and sweeps fees. `collectPositionFees` always sweeps the complete accrued balance; there is no partial collect amount. ## Identity and signing Uniswap users often think in terms of an EVM address. GalaChain has two alias families: native keys resolve registered `client|<24-hex>` identities, while personal-sign browser wallets resolve bare `eth|<40-hex>` identities. The signers come from `@gala-chain/gala-core-sdk`. `PrivateKeySigner` is native, `GalaWalletSigner` is native (personal-sign is opt-in and needs a wallet build with the phantom-signer fix), and `BrowserWalletSigner` uses EIP-1193 personal-sign by default (an opt-in `{ scheme: 'eip712' }` signs typed data, which also resolves a registered `client|` alias). Nothing else in v2 uses EIP-712. See [Signing and Identity](/gswap-sdk/next/other/signing-and-identity.md) and [Migration from 0.x](/gswap-sdk/next/other/migration-from-0x.md) for the complete mapping. --- # Quoting Quotes are read-only simulations from the v2 backend. They accept symbols or class keys, and an omitted fee compares all available pools (`0`, `500`, `3000`, and `10000`). ```typescript const quote = await gSwap.quoting.quoteExactInput('GALA', 'GUSDC', '100'); console.log(`Tier: ${quote.feeTier}`); console.log(`Input: ${quote.amountIn}`); console.log(`Output: ${quote.amountOut}`); console.log(`Trading fees: ${quote.tradingFees}`); ``` Use exact output when the received amount is fixed: ```typescript const quote = await gSwap.quoting.quoteExactOutput('GALA', 'GUSDC', '50', 3000); console.log(`Spend at most ${quote.amountIn} GALA for 50 GUSDC`); ``` The quote includes the selected `fee`, canonical `token0Symbol` and `token1Symbol`, current and post-trade square-root prices, and the protocol, trading, and total fee amounts. It also reports `tokenInIsToken0`, which is useful when building a lower-level RequestTrade DTO. Prices can change between a quote and a write, so always set a slippage bound on the write and refresh large or delayed quotes. ```typescript const quote = await gSwap.quoting.quoteExactInput('GALA', 'GUSDC', '100'); const tx = await gSwap.swaps.swap('GALA', 'GUSDC', quote.feeTier, { exactIn: '100', amountOutMinimum: quote.amountOut, }); ``` An exact-input trade uses `amountOutMinimum`; an exact-output trade uses `amountInMaximum`. Both values are optional, but omitting them removes slippage protection. A missing pool or insufficient liquidity is reported as an SDK error. --- # Trading Trading uses a queued `RequestTrade` DTO through the swap backend's chain-gateway route. The SDK resolves the input tokens, chooses the canonical symbols, creates a `uniqueKey`, signs the DTO, and submits the request. The HTTP 201 acknowledgement means the chain accepted the request; it does not mean the swap has executed. ## Exact input Sell exactly `100` GALA and protect the minimum output with `amountOutMinimum`: ```typescript const quote = await gSwap.quoting.quoteExactInput('GALA', 'GUSDC', '100'); const tx = await gSwap.swaps.swap('GALA', 'GUSDC', quote.feeTier, { exactIn: '100', amountOutMinimum: quote.amountOut, }); console.log(tx.mode, tx.uniqueKey, tx.transactionId, tx.result); const applied = await tx.confirm(); console.log(applied.result); ``` ## Exact output Buy exactly `50` GUSDC and cap the amount of GALA spent: ```typescript const quote = await gSwap.quoting.quoteExactOutput('GALA', 'GUSDC', '50'); const tx = await gSwap.swaps.swap('GALA', 'GUSDC', quote.feeTier, { exactOut: '50', amountInMaximum: quote.amountIn, }); const applied = await tx.confirm(); console.log(applied.result); ``` `exactIn` and `exactOut` are mutually exclusive. Their corresponding slippage fields are also directional: `amountOutMinimum` protects an exact-input trade, while `amountInMaximum` protects an exact-output trade. The SDK rejects a trade that supplies both sides. An optional positive `priceLimit` (a sqrt-price limit) can be added to either form and is sent to the chain as the DTO's `priceLimit`. ## Unique keys Every write carries a fresh `uniqueKey` of the form ``. The default prefix is `galaswap-operation-`, what the Gala Wallet and the gSwap web app send. Set `uniqueKeyPrefix` on `new GSwap({ uniqueKeyPrefix })` to change it; it must be at most 92 characters of `A-Z a-z 0-9 . _ : -` so the key remains readable by the apply-results endpoint. ## What happens after submit The returned `SubmittedTransaction` has `mode === 'queued'`, `result === undefined`, and a stable `uniqueKey`. Its `transactionId` is the request transaction when the gateway provides one. `await tx.confirm()` resolves an `AppliedTrade` with `uniqueKey`, the apply `transactionId` and `blockNumber`, the `requestTransactionId`, and a `result` containing `token0`, `token1`, `fee`, and applicable decimal-string quantities and fee fields. For example, the applied fixture contains `token0: 'GALA'`, `token1: 'GUSDC'`, `fee: 3000`, `sell0Qty: '0.99999996'`, and `buy1Qty: '0.1202'`. A `Status: 0` apply result throws `CHAIN_REJECTED`, with the chain's `ErrorKey` as `params.errorKey` and its text as `params.serverMessage`; the rejected fixture has `errorKey` `VALIDATION_FAILED` and `serverMessage` `Slippage limit: trade would return 0.120199 GUSDC, below the required minimum 999999999.` Map `params.errorKey` to your own text; the server's English is data to relay or ignore. `classifyFailure(error)` tells you whether Retry is safe (see [Error Handling](/gswap-sdk/next/other/error-handling.md)). There is no synchronous swap and no fallback to one. See [Transaction Status](/gswap-sdk/next/tutorial/transaction-status.md). The current backend route is method-specific and the body is the signed DTO itself. --- # Asset Balances `getUserAssets` reads the backend's user-assets endpoint. It is public and does not require a signer. ```typescript const assets = await gSwap.assets.getUserAssets('client|635f048ab243d7eb7f5ba044'); for (const asset of assets.tokens) { console.log(`${asset.symbol}: ${asset.quantity} (${asset.decimals} decimals)`); } console.log(`Token count: ${assets.count}`); ``` The `owner` may be a native `client|...` alias or a bare `eth|...` alias. The method retains pagination options when a wallet has many assets: ```typescript const firstPage = await gSwap.assets.getUserAssets(owner, 1, 20); const nextPage = await gSwap.assets.getUserAssets(owner, 2, 20); ``` `getUserAssets` reads `GET /user/assets`, which returns only the tokens with a positive balance. The SDK never reads the backend's `/user/token-list`, so the `balancesAvailable` flag that endpoint may carry does not apply to `getUserAssets`; an app that reads `/user/token-list` itself must ignore its `quantity` fields while that flag is `false`. Balances are useful for choosing a deposit side before calling `positions.estimateAddLiquidity`. They do not reserve funds; a subsequent write still has to pass the chain's balance checks. --- # Market Data and Leaderboard `gSwap.market` reads USD prices, price series and the platform volume totals, and `gSwap.leaderboard` reads the trading-competition seasons and rankings. They are public reads of the swap backend: no signer, no wallet. ## Prices ```typescript const [gala, bene] = await gSwap.market.getPrices([ 'GALA$Unit$none$none', { collection: 'Token', category: 'Unit', type: 'BENE', additionalKey: 'client:5c806869e7fd0e2384461ce9' }, ]); console.log(gala?.price, gala?.change24h, gala?.listed); const single = await gSwap.market.getPrice('GALA|Unit|none|none'); ``` `getPrices` takes 1 to 500 tokens and sends them in as many `GET /market/price` requests as their length needs, one after another: the backend refuses a request line over 16 KB (HTTP 431; 300 launchpad keys are 17.7 KB), so each request carries at most `MARKET_PRICE_QUERY_BYTES` (8 000) of ids, about 135 launchpad keys. A failed request fails the call. Name a token by a symbol (`GALA`) or a class key: the `$` form, the `|` form or the object (sent in its `$` form). The answer is in the order you asked: - an entry is `{ token, price, change24h, listed }`: `token` is the id that was asked for, `price` is USD (`null` when the backend knows the token but has no price), `change24h` is in percent; - `undefined` means the backend has no entry for that token. The backend keys each answer by the exact id it was asked for (and also by the symbol, which two keys can share), and the SDK reads only that id, so a token is never given another token's price. A malformed entry is `undefined` too, and is reported to `onInvalidEntry`. A token string the backend would refuse (outside `A-Z a-z 0-9 . _ $ + / : | -`, or over 120 characters) is `INVALID_MARKET_TOKEN` before anything is sent; more than 500 tokens is `INVALID_TOKEN_BATCH`. ## Price series ```typescript const series = await gSwap.market.getPriceSeries('GALA$Unit$none$none', '1W'); for (const point of series.prices) console.log(new Date(point.time * 1000), point.price); console.log(series.currentPrice, series.change24h); ``` The windows are `1D`, `1W`, `1M`, `1Y` and `ALL` (`PRICE_SERIES_TIMEFRAMES`); any other is `INVALID_TIMEFRAME` before anything is sent. The whole series comes in one answer, oldest first, with `time` in unix seconds. A token the backend has no prices for is an empty series with `currentPrice: null`. ## Volume ```typescript const volume = await gSwap.market.getVolumeSummary(); console.log(volume.tvl, volume.volume1d, volume.trades1d, volume.volume1dDelta); ``` TVL, 1-, 7- and 30-day volume (USD) and the 24-hour trade count across every current-contract pool. A delta is a fraction of the previous period: `-0.11` is 11 % less, and it is `0` when the previous period had no volume. ## New pools ```typescript const stop = gSwap.pools.watchNewPools((pool) => console.log('new pool', pool.poolRef), { intervalMs: 60_000, minTvl: 1000, tokens: ['GALA'], onError: (error) => console.warn('poll failed', error), }); // later stop(); ``` `watchNewPools` polls `gSwap.pools.getPools()` (the alternative to the realtime stream's `gSwap.stream.subscribePoolCreated` for a client that cannot hold a WebSocket open). The first answer is the baseline: a pool that existed then is never reported. Each later pool is judged once, when it first appears, against `minTvl` and `tokens`. A poll never overlaps the previous one, a failed poll or a throwing callback goes to `onError` (polling goes on), and nothing is reported after `stop()`. An `intervalMs` that is not a finite number of at least 1 is `INVALID_POLL_INTERVAL`. ## Leaderboard ```typescript const seasons = await gSwap.leaderboard.getSeasons(); const season = await gSwap.leaderboard.getCurrentSeason(); // null between seasons const { entries } = await gSwap.leaderboard.getLeaderboard(seasons[0]!.id); const current = await gSwap.leaderboard.getCurrentLeaderboard(); // null between seasons ``` A season is `{ id, name, start, end, rulesId }` with `Date` bounds; `getCurrentSeason` picks the season running at `options.now` (default: now), and `start` and `end` both count as inside. An entry is `{ wallet, rank, totalXp, distributionPercent, liquidityXp, tradingXp, masteryTitles }` with XP as decimal strings; `totalXp` is `null` for a ranked wallet the backend has no XP breakdown for yet. `seasonId` must be an integer of at least 1 (`INVALID_SEASON_ID`). ## Failures Every failure of these reads is a read's (`error.write === false`), so `classifyFailure` judges a 5xx, a timeout or an unusable answer (`INVALID_CHAIN_RESPONSE`) as `transient`: Retry is safe. --- # Liquidity Management V2 positions are identified by `(token0, token1, fee, owner, tickLower, tickUpper)`. There is no `positionId`. Tokens may be symbols or class keys; the SDK resolves and orders them. ## Ticks and price ranges `addLiquidityByTicks` is the precise API. Ticks must be aligned to the pool's fee-tier spacing: ```typescript const tx = await gSwap.positions.addLiquidityByTicks({ token0: 'GALA', token1: 'GUSDC', fee: 3000, tickLower: -6000, tickUpper: 6000, amount: '100', amountIsToken0: true, }); await tx.confirm(); ``` The spacing is `0 → 200`, `500 → 10`, `3000 → 60`, and `10000 → 200`. The lower tick must be below the upper tick, both ticks must be within the contract bounds, and each must be divisible by the pool spacing. Use `addLiquidityByPrice` when the UI works in token1-per-token0 prices. The SDK converts the range to ticks and aligns it to the pool spacing. Prices are branded (`PriceIn`, see [Branded Types](/gswap-sdk/next/other/branded-types.md)): a plain string does not compile, so declare what it is with `as PriceIn`: ```typescript import type { PriceIn } from '@gala-chain/gswap-sdk'; const tx = await gSwap.positions.addLiquidityByPrice({ token0: 'GALA', token1: 'GUSDC', fee: 3000, minPrice: '0.02' as PriceIn, maxPrice: '0.04' as PriceIn, amount: '100', amountIsToken0: true, }); ``` Both add APIs require exactly one deposit side. Use `estimateAddLiquidity` first to calculate the other side for the selected range and current pool price. ## Remove and collect `removeLiquidity` accepts an optional withdrawal quantity. Supplying neither quantity closes the position completely and sweeps its accrued fees: ```typescript const tx = await gSwap.positions.removeLiquidity({ token0: 'GALA', token1: 'GUSDC', fee: 3000, tickLower: -6000, tickUpper: 6000, }); await tx.confirm(); ``` When withdrawing partially, provide at most one of the SDK's `amount0` or `amount1` options. The SDK maps it to the contract's `withdrawalQuantityToken0` or `withdrawalQuantityToken1`. The contract's `CollectPositionFees` operation always sweeps the complete accrued fee balance; there are no partial collect amount fields: ```typescript const tx = await gSwap.positions.collectPositionFees({ token0: 'GALA', token1: 'GUSDC', fee: 3000, tickLower: -6000, tickUpper: 6000, }); await tx.confirm(); ``` ## Creating a pool `CreatePool` is the first place a token's trading symbol may be claimed. Both symbols must be ASCII alphanumeric, globally available, and equal to the token class's own `symbol`. A class key carries no symbol (collection and symbol differ for many tokens, every launchpad token shares the collection `Token`, and some collections contain `$`), so the SDK never derives one from it. Tokens already in the trading-symbol registry resolve automatically; for a token being registered for the first time you must pass `token0Symbol` / `token1Symbol` (read from the token list or `FetchTokenClasses`), otherwise `createPool` throws `TOKEN_SYMBOL_NOT_REGISTERED`. The canonical pair is ordered so the lower symbol is `token0` using plain string comparison. Supply exactly one positive `startingPrice` or `startingSqrtPrice`: ```typescript const tx = await gSwap.positions.createPool({ token0: 'GALA|Unit|none|none', token1: 'GUSDC|Unit|none|none', fee: 3000, startingPrice: '0.03', }); console.log(tx.transactionId ?? tx.uniqueKey); ``` An optional `name` (omitted when undefined or empty) is sent as the DTO's `name`. CreatePool is not organization-gated. Treat symbols as a global namespace and choose them carefully; the first successful pool can register them permanently. CreatePool has no affected position to re-read, so its `confirm()` result is `null`; use the executed result and transaction metadata above. A duplicate pool is rejected by the gateway or chain. --- # Realtime Stream The SDK includes a client for the gSwap realtime stream (gdex WebSocket Protocol v1): public, read-only queries and live events over strict JSON-RPC 2.0 on one raw WebSocket. It is not a Socket.IO endpoint. ## Connect `GSwap` creates the client for its environment the first time you use `gSwap.stream`. Nothing connects until you call `connect()`: ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); await gSwap.stream.connect(); console.log(await gSwap.stream.serverInfo()); const blocks = await gSwap.stream.subscribeBlocks((event) => console.log(event.blockNumber), { snapshot: true }); await blocks.unsubscribe(); gSwap.stream.disconnect(); ``` You can also create it directly when you only need the stream: ```typescript import { GdexStreamService } from '@gala-chain/gswap-sdk'; const stream = new GdexStreamService({ url: 'wss://dex-backend-prod1.defi.gala.com/ws' }); await stream.connect(); ``` | Environment | URL | | ----------- | ------------------------------------------ | | `prod` | `wss://dex-backend-prod1.defi.gala.com/ws` | | `stage` | The staging swap backend's `/ws` (set by the `env: 'stage'` preset) | With a custom `dexBackendBaseUrl`, the stream URL is derived from it (`https` becomes `wss`, plus `/ws`) unless you pass `dexBackendWsUrl`. All on-chain numbers and epoch-millisecond timestamps stay decimal strings: do not round-trip them through JavaScript numbers. Call `disconnect()` at shutdown. It closes on purpose and turns automatic reconnect off. ## Channels Each subscription method returns a handle with `subscriptionId` and `unsubscribe()`, and your callback receives each event's payload. | Channel | Method | Sends | | ------------- | --------------------------------------- | ----------------------------------------------------------- | | `swap` | `subscribeSwaps(cb, opts?)` | one event per committed swap (omit the pool for all pools) | | `liquidity` | `subscribeLiquidity(cb, opts?)` | one event per committed add, remove or collect | | `pool` | `subscribePool(selector, cb, opts?)` | state changes of one pool (snapshot has the full tick map) | | `balance` | `subscribeBalances(owner, cb, opts?)` | balance changes of one wallet | | `poolCreated` | `subscribePoolCreated(cb, opts?)` | each newly created pool | | `blocks` | `subscribeBlocks(cb, opts?)` | each block-height advance | ### Which channel tells me who did something? | I want to know… | Use | Field that answers it | | -------------------------------------------------- | ------------- | -------------------------------------- | | who added or removed liquidity, or collected fees | `liquidity` | `event.owner` | | who made a swap | `swap` | `event.sender` | | the pool's price, tick, reserves or liquidity now | `pool` | `sqrtPrice`, `tick`, `token0Reserve` | | how one wallet's balance changed | `balance` | `quantity` | | that a pool was created, and by whom | `poolCreated` | `creator` | **`pool` events never name the wallet that caused them.** A `pool` event is the pool's state after something touched it, and one event can cover several transactions in the same block. On v2 its `creator` is the wallet that **created the pool**, which never changes; it is not whoever just traded or added liquidity. A bot that announces "wallet X added liquidity to pool Y" should subscribe to `liquidity` for the wallet and amounts, and use `pool` only for the resulting numbers. Match the two on `transactionId`. Swaps sent in shadow mode (`X-Shadow: true`) still appear on `swap` and move the pool, with the wallet withheld: `sender` is the marker `` (the same one the chain's public query-api uses; it is not an address, so code that validates `sender` must allow it), and `transactionId`, `applyTransactionId`, `requestTransactionId` and `uniqueKey` are opaque ids. They are stable per swap, so you can still deduplicate, but they do not resolve on a block explorer. The swapper gets no `balance` event. A `sender` of `` means "wallet withheld", not a real user, so leave it out of per-wallet statistics. Pass `snapshot: true` to receive current state right after the subscribe response, and `fields` to trim each event (identity and envelope fields always stay). Events carry `version: 'v1'` (the exit-only legacy contract) or `'v2'` (the live contract); an unfiltered subscription receives both. ### Liquidity: add, remove, collect `liquidity` reports every committed AddLiquidity, RemoveLiquidity and CollectPositionFees, on both contract versions. They never appear on `swap`. Every filter is optional; with none you receive every liquidity event. ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap(); await gSwap.stream.connect(); // Every liquidity change by one LP wallet: await gSwap.stream.subscribeLiquidity( (event) => console.log(event.action, event.poolHash, event.amount0, event.amount1), { owner: 'client|618ae395c1c653111d3315be' }, ); // Every liquidity change in one pool: await gSwap.stream.subscribeLiquidity((event) => console.log(event), { poolHash: 'v2:GALA$GUSDC$10000' }); ``` Filters: `pool` or `poolHash`, `owner` (the position's owner), `transactionId`, `version` (`'v1' | 'v2' | 'all'`). There is no snapshot, because an event reports a committed operation, not current state; read positions with `getPositions()`. | Field | Meaning | | -------------------------- | ---------------------------------------------------------------------------------------------------- | | `action` | `add`, `remove` or `collect` | | `owner` | the position's owner (the LP wallet) | | `version`, `pool`, `poolHash`, `transactionId`, `blockNumber`, `timestamp` | identity and envelope, always present | | `amount0`, `amount1` | principal moved: deposited by an add, withdrawn by a remove, `"0"` for a collect | | `fees0`, `fees1` | fees paid out. v2: always present (`"0"` for an add). v1: present on a collect only | | `positionId` | v1: the position id. v2: the chain's position key `\|\|\|` | | `tickLower`, `tickUpper` | the position's range | | `liquidityAfter` | v2 only: the position's liquidity after the operation; `"0"` means it is closed | | `token0Symbol`, `token1Symbol` | v2 only | A v2 add: ```json { "version": "v2", "pool": { "token0ClassKey": "MCA-imzqovym|Unit|testfaxcjykgnoki|none", "token1ClassKey": "MCB-imzqovym|Unit|testckehdbwxnkmv|none", "fee": 3000 }, "poolHash": "v2:MCAIMZQOVYM$MCBIMZQOVYM$3000", "transactionId": "5f1c…", "action": "add", "owner": "client|lp1-mnqszsfwcj", "positionId": "MCAIMZQOVYM$MCBIMZQOVYM$3000|0884392|0888232|client|lp1-mnqszsfwcj", "tickLower": -2880, "tickUpper": 960, "liquidityAfter": "50505.195635588461491346", "amount0": "3025.72277487", "amount1": "6122.68379996", "fees0": "0", "fees1": "0", "token0Symbol": "MCAIMZQOVYM", "token1Symbol": "MCBIMZQOVYM", "blockNumber": 2459000, "timestamp": "1787928959212" } ``` The same operation still updates the `pool` channel (new liquidity, reserves, price and tick, with no wallet and no amounts) and, for a subscribed owner, the `balance` channel. Use `liquidity` to learn what happened and `pool` and `balance` to track the resulting state. A malformed `liquidity` frame is dropped, never passed to your callback. **Deduplicate by `transactionId` plus `positionId`**: a v1 BatchSubmit can hold several operations under one transaction id. ## Queries The client also answers the read-only protocol queries. `request()` is the escape hatch for anything else, such as `gdex_listSubscriptions`. ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const stream = new GSwap({ env: 'stage' }).stream; await stream.connect(); const pool = { token0ClassKey: 'GALA|Unit|none|none', token1ClassKey: 'GUSDC|Unit|none|none', fee: 10000 }; const info = await stream.serverInfo(); const state = await stream.getPool({ pool }); const balance = await stream.getBalance('client|618ae395…', 'GUSDC|Unit|none|none'); const positions = await stream.getPositions({ owner: 'client|618ae395…', pool, limit: 100 }); const height = await stream.getBlockHeight(); const quote = await stream.quote({ tokenIn: 'GALA|Unit|none|none', tokenOut: 'GUSDC|Unit|none|none', amountIn: '100' }); ``` `quote` takes exactly one of `amountIn` or `amountOut`; omit `fee` to compare every tier. Each request times out after 15 seconds by default. A JSON-RPC error rejects with `GdexStreamError`, which keeps `code`, `message` and `data`. ## Reconnect and ordering An unexpected close reconnects with exponential backoff (five attempts, starting at two seconds, by default). Every active handle is resubscribed with `snapshot: true`, its `subscriptionId` updates, and the same callback and `unsubscribe()` keep working. Rate-limit responses are retried using `data.retryAfterMs`. There is no server cursor, so treat the reconnect snapshot as truth. Delivery is at least once: roughly 40 blocks can replay after a server restart. Dedupe swaps by `transactionId`; for state channels keep the value with the later `blockNumber`, which is non-decreasing within one subscription. Expect about two seconds from block commit to event. ## Limits and errors 16 connections per IP, 256 subscriptions per connection, 20 requests per rolling 10 seconds (subscribe and unsubscribe count), 1 MiB frames, 20-call batches, and a 4 MiB buffer before a slow consumer is disconnected. `-32003` means rate limited (see `data.retryAfterMs`), `-32005` unknown pool, `-32006` unknown token, `-32001` invalid channel params, `-32002` subscription limit. ## Node.js before version 22 Browsers and Node.js 22 or newer use `globalThis.WebSocket`. On older Node.js, pass a WebSocket constructor yourself, for example from the `ws` package; the SDK does not bundle one. `gSwap.stream` only needs it when you first use it. ```typescript import WebSocket from 'ws'; import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage', webSocketImpl: WebSocket }); await gSwap.stream.connect(); ``` ## Authentication Public channels need none. A privileged connection (shadow swaps with the wallet unredacted) is selected by an `x-api-key` header on the WebSocket upgrade request, which the server reads from no other place. Browser and React Native `WebSocket`s are therefore split: a browser cannot set the header and always sees the public view; Node.js (`ws`) and React Native accept `{ headers }` as the constructor's third argument, which is what `apiKey` uses. It requires `webSocketImpl`, is meant for trusted server-side code, and is described in [App and Wallet Integration](/gswap-sdk/next/other/app-integration.md). ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; import { WebSocket } from 'ws'; const gSwap = new GSwap({ webSocketImpl: WebSocket, streamApiKey: process.env.GDEX_API_KEY }); ``` --- # Transaction Status V2 writes return a `SubmittedTransaction`. A queued swap acknowledgement has `mode === 'queued'`, `result === undefined`, its request `transactionId` when provided, and a durable `uniqueKey`. It proves acceptance into the queue, not execution. Liquidity writes remain executed gateway writes whose confirmation re-reads the affected position. There is no `PendingTransaction`, bundle ID, or `.wait()` API. To watch committed swaps and liquidity changes as they happen, use the [realtime stream](/gswap-sdk/next/tutorial/realtime-stream.md). ```typescript const tx = await gSwap.swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '10' }); console.log('Correlation key:', tx.uniqueKey); console.log('Request mode:', tx.mode); console.log('Request transaction ID:', tx.transactionId ?? '(not reported)'); const applied = await tx.confirm(); console.log('Applied trade:', applied); ``` For a queued swap, `confirm()` polls: ```text GET {dexBackend}/v1/chain/apply-results/{uniqueKey}?channel=asset&contract=dex-contract ``` The confirmation policy treats these responses as follows: | Response | Meaning and client action | | --- | --- | | `200`, `Status: 1` | Terminal success; return the `AppliedTrade` from `Data`. | | `200`, `Status: 0` | Terminal chain rejection; throw `CHAIN_REJECTED` with `params.errorKey` = `ErrorKey` and `params.serverMessage` = `Message`. | | `404` | Outcome unresolved (or the result expired after 7 days); keep polling until the deadline. | | `429` | Outcome unresolved; honor `retry-after` and keep polling. | | `5xx` | Upstream trouble; keep polling until the deadline. | | `400` (any other 4xx except `404` and `429`) | Terminal: throw `CONFIRMATION_FAILED` with `params.status`. The outcome is unknown (the write may still apply); do not treat it as a rejection. | | `200` with a body that is not an apply result, or one for another key | `CONFIRMATION_MALFORMED` / `CONFIRMATION_KEY_MISMATCH`: unknown outcome. | `ConfirmOptions` has `timeoutMs` default `60_000`, `pollIntervalMs` default `2_000` with a minimum of `500`, and `initialDelayMs` default `3_000` for a queued swap (`0` for liquidity writes). Poll backoff is jittered and capped at 8 seconds. `CONFIRMATION_TIMEOUT` means the outcome is unknown: the trade may still apply, so confirm the same `uniqueKey` again later; results are retained for 7 days. Do not resubmit. Pass `signal` (an `AbortSignal`) to cancel a wait or an in-flight read; the confirmation then throws `CONFIRMATION_ABORTED`, which also leaves the outcome unknown. A queued swap's errors are `AppliedTradeError`s (a `GSwapSDKError` subclass); see [App and Wallet Integration](/gswap-sdk/next/other/app-integration.md) for the standalone `confirmAppliedTrade`. Persist the `uniqueKey`. Any time you no longer hold the `SubmittedTransaction` (a timeout you gave up on, a process restart, a `409` replay conflict), resolve the outcome from the key alone: ```typescript const applied = await gSwap.swaps.confirmSwap(uniqueKey, { timeoutMs: 30_000 }); ``` `confirmSwap()` reads the same apply-results record, starts immediately, and resolves the `AppliedTrade` or throws the chain's rejection. Liquidity writes use the same `SubmittedTransaction` abstraction, but confirm by re-reading the affected position because position writes may not have an apply-result row. Use the canonical position identity: `token0`, `token1`, `fee`, `owner`, `tickLower`, and `tickUpper`. A re-read that fails is the write's failure, never the read's (the write may be applied): a terminal HTTP status is `CONFIRMATION_FAILED`, an unusable position answer `CONFIRMATION_MALFORMED`, and anything else (no answer, a 5xx, 404, 408, 429) is read again until the deadline, then `CONFIRMATION_TIMEOUT` with the last read error as `cause`. Each carries the write's `uniqueKey`: confirm again, never resubmit. The submit request can time out with `SUBMISSION_OUTCOME_UNKNOWN`; confirm the original `uniqueKey` before taking any action. A `409` replay conflict with `CHAIN_DISPATCH_FAILED` means that key was already consumed; confirm the original key and do not retry with a new one. --- # Slippage Slippage occurs when the actual execution price of a trade differs from the expected price at the time you submit the transaction. This is a fundamental concept in automated market makers (AMMs) like gSwap. ## What Causes Slippage? ### Price Impact When you trade against an AMM pool, your trade size affects the token ratio in the pool, which changes the price: - **Large trades** relative to pool size cause more price impact - **Small trades** in deep pools have minimal price impact ### Market Movement Between the time you get a quote and your transaction executes, other traders may have submitted transactions that change the pool's state: - Other swaps can move the price before your transaction processes - Network congestion can delay your transaction - Market volatility can cause rapid price changes ### Pool Depth Pools with more liquidity (total value locked) provide better prices and less slippage: - **Deep pools**: More resistance to price impact from individual trades - **Shallow pools**: Higher sensitivity to trade size ## Types of Slippage ### Positive Slippage When you receive a better price than expected: ```text Expected: Sell 100 $GALA for 50 USDC Actual: Sell 100 $GALA for 52 USDC Positive slippage: +2 USDC ``` This can happen when prices move in your favor between quote and execution. ### Negative Slippage When you receive a worse price than expected: ```text Expected: Sell 100 $GALA for 50 USDC Actual: Sell 100 $GALA for 48 USDC Negative slippage: -2 USDC ``` This is a negative outcome and is why slippage protection is important. ## Slippage Protection ### Exact Input Swaps When selling a specific amount, set `amountOutMinimum` to protect against excessive slippage: ```typescript const tx = await gSwap.swaps.swap( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', 10000, { exactIn: '100', // Sell exactly 100 $GALA amountOutMinimum: '47.5', // We'll accept as little as 47.5 USDC (5% slippage tolerance from our expected 50 USDC) }, ); ``` If the actual output would be less than 47.5 USDC, the transaction fails rather than executing at a bad price. The chaincode will guarantee that you will not receive less than the specified minimum. :::info Gas Fees Unlike most DEXs, there is no gas fee on gSwap for failed swaps, including those that fail due to slippage protection. ::: ### Exact Output Swaps When buying a specific amount, set `amountInMaximum` to limit how much you're willing to pay: ```typescript const tx = await gSwap.swaps.swap( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', 10000, { exactOut: '50', // Buy exactly 50 USDC amountInMaximum: '105', // Pay maximum 105 $GALA (5% slippage tolerance compared to our expected 100 $GALA) }, ); ``` If more than 105 $GALA would be required, the transaction fails. ## Setting Slippage Tolerance ### Conservative (0.1% - 0.5%) - Best for stable token pairs (stablecoins) - Low volatility environments - Risk: Higher chance of transaction failure ### Moderate (0.5% - 1.5%) - Good for most token pairs - Balanced approach between execution and protection - Recommended for most users ### Aggressive (2% - 5%) - Volatile token pairs - Fast-moving markets - Large trades in shallow pools - Risk: Potential for significant value loss ## Best Practices ### Get Fresh Quotes Always get a recent quote before executing large trades: ```typescript import BigNumber from 'bignumber.js'; // Get fresh quote for exact inpu const quote = await gSwap.quoting.quoteExactInput( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', '100', ); // Calculate slippage protection based on quote const slippageTolerance = 0.01; // 1% const amountOutMinimum = new BigNumber(quote.amountOut) .multipliedBy(1 - slippageTolerance) .toFixed(); // Execute with slippage protection const tx = await gSwap.swaps.swap( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', quote.feeTier, { exactIn: '100', amountOutMinimum, }, ); ``` ### Consider Trade Size - **Small trades**: Use tighter slippage (0.1-0.5%) - **Large trades**: May need higher tolerance (1-3%) - **Very large trades**: Consider splitting into smaller trades across the different fee tiers ### Monitor Pool Conditions - Check pool liquidity before large trades - Consider multiple fee tiers for better execution - Be aware of market volatility ## Related Concepts - **[Price Impact](/gswap-sdk/next/pool-concepts/price-impact.md)** - How trade size affects execution price - **[Liquidity](/gswap-sdk/next/pool-concepts/liquidity-concentration.md)** - Understanding pool depth and concentration - **[Fee Tiers](/gswap-sdk/next/pool-concepts/fees.md)** - How different fee levels affect trading costs Understanding slippage is crucial for successful trading on any AMM. Always use appropriate slippage protection and consider market conditions when setting tolerance levels. --- # Price Impact Price impact is the change in token price caused by your trade, and is a closely related concept to slippage. ## How Price Impact Works ### Constant Product Formula AMMs like gSwap use the constant product formula: `x * y = k` - `x` = amount of token A in the pool - `y` = amount of token B in the pool - `k` = constant that must be maintained When you trade, you're changing the ratio of tokens in the pool, which changes the price. ### Example: Price Impact Calculation Starting pool state: - 1,000 $GALA tokens - 500 USDC tokens - 1,000 \* 500 = 500,000 (constant k) - Current price: 0.5 USDC per $GALA If you sell 100 $GALA you will receive ~45.5 USDC: - Pool becomes: 1,100 $GALA, ~454.5 USDC - 1,100 \* ~454.5 = 500,000 (still same constant k) - New price: ~0.413 USDC per $GALA - Price impact: ~17.4% ## Factors Affecting Price Impact ### Trade Size vs Pool Size The ratio of your trade to the pool's total liquidity determines impact: ```text Price Impact ≈ (Trade Size / Pool Liquidity) * scaling_factor ``` **Examples:** - Trading $100 in a $1M pool: ~0.01% impact - Trading $100 in a $10K pool: ~1% impact - Trading $100 in a $1K pool: ~10%+ impact ### Pool Liquidity Distribution In concentrated liquidity pools (like Uniswap V3/gSwap), liquidity isn't evenly distributed: - **Active Range**: Liquidity concentrated around current price - **Out of Range**: Less liquidity available at extreme prices - **Tick Density**: How much liquidity exists at each price level ### Fee Tier Selection Different fee tiers often have different liquidity depths: - **0.05% pools**: Usually for very stable pairs, less liquidity - **0.3% pools**: Most common, good liquidity for many pairs - **1.0% pools**: Volatile pairs, may have concentrated liquidity ## Minimizing Price Impact ### When Trade Splitting Helps **Note**: In a simple AMM with no other activity, splitting trades doesn't reduce total price impact - the cumulative effect is the same. However, splitting can help in these scenarios: #### Allow Arbitrage Between Trades By waiting between smaller trades, arbitrageurs can restore the pool price closer to external market prices: ```typescript // Split trades with delays to allow arbitrage const tradeSize = '100'; const numTrades = 10; for (let i = 0; i < numTrades; i++) { const tx = await gSwap.swaps.swap( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', 10000, { exactIn: tradeSize, amountOutMinimum: calculateMinimum(tradeSize), }, ); await tx.confirm(); // Wait for potential arbitrage to restore price await new Promise((resolve) => setTimeout(resolve, 5000)); } ``` #### Benefit from Concentrated Liquidity Ranges In concentrated liquidity pools, different price ranges have different liquidity depths. Smaller trades may stay within high-liquidity ranges: - **Large trade**: May exhaust concentrated liquidity and move into sparse ranges - **Small trades**: Each trade may complete within the concentrated range ## Estimating Price Impact ### Before Trading Always get a recent quote to understand the expected price impact: ```typescript // For exact input (selling a specific amount) - automatically finds best pool const quote = await gSwap.quoting.quoteExactInput( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', '100', ); console.log(`Best fee tier: ${quote.feeTier}`); console.log(`Current price: ${quote.currentPrice.toString()}`); console.log(`New price: ${quote.newPrice.toString()}`); console.log(`Price impact: ${quote.priceImpact.multipliedBy(100).toFixed(2)}%`); console.log(`Expected output: ${quote.amountOut} USDC`); ``` ## Price Impact vs Slippage ### Key Differences | Aspect | Price Impact | Slippage | | ------------------ | -------------------------------------------------- | -------------------------------- | | **Cause** | Your trade size | Market movement + your trade | | **Predictability** | Calculable from pool state | Unpredictable | | **Control** | Reduce by smaller trades or splitting across pools | Mitigate with tolerance settings | ## Best Practices ### Pre-Trade Analysis 1. **Check pool liquidity** across different fee tiers 2. **Calculate expected price impact** using quotes 3. **Consider trade splitting** for large amounts 4. **Monitor market conditions** and volatility ### During Execution 1. **Use appropriate slippage protection** accounting for price impact 2. **Monitor transaction status** for unexpected failures 3. **Be prepared to adjust** strategy if conditions change ### Post-Trade Review 1. **Compare actual vs expected** execution 2. **Analyze price impact accuracy** from quotes 3. **Learn from results** to improve future trading ## Related Concepts - **[Slippage](/gswap-sdk/next/pool-concepts/slippage.md)** - How market movement affects execution price - **[Liquidity Concentration](/gswap-sdk/next/pool-concepts/liquidity-concentration.md)** - Understanding pool depth and concentration - **[Fees](/gswap-sdk/next/pool-concepts/fees.md)** - How fees interact with liquidity provision Price impact is a fundamental cost of trading on AMMs. Understanding and minimizing it through proper trade sizing and timing is crucial for efficient trading. --- # Liquidity Concentration Liquidity concentration is a key feature of modern AMMs like gSwap (based on Uniswap V3) where liquidity providers can focus their capital within specific price ranges rather than across the entire price curve. ## How Liquidity Concentration Works ### Traditional AMMs vs Concentrated Liquidity **Traditional AMMs (Uniswap V2 style):** - Liquidity spread evenly across all possible prices (0 to ∞) - Most liquidity sits far from current market price - Capital inefficient but simple **Concentrated Liquidity (Uniswap V3/gSwap style):** - Liquidity providers choose specific price ranges - Capital concentrated where trading actually happens - Much more capital efficient ### Price Ranges and Ticks Liquidity is provided within discrete price ranges defined by "ticks" (numbers for example purposes only): ```text Tick -2000: Price 0.45 USDC/GALA Tick -1000: Price 0.47 USDC/GALA Tick 0: Price 0.50 USDC/GALA ← Current Price Tick 1000: Price 0.53 USDC/GALA Tick 2000: Price 0.55 USDC/GALA ``` Each liquidity position covers a range between two ticks, e.g., from tick -1000 to tick +1000. ## Effects on Trading ### Active vs Inactive Ranges **Within Active Ranges:** - High liquidity concentration provides better prices - Lower price impact for trades - More efficient execution **Outside Active Ranges:** - Little to no liquidity available - High price impact or impossible execution - Trades may fail or get very poor prices ### Real-World Example Consider a GALA/USDC pool where: - Current price: 0.50 USDC per $GALA - 100,000 $GALA of liquidity is in the range between 0.45-0.55 USDC - Sparse liquidity outside this range ```typescript // Trading within the concentrated range const quote1 = await gSwap.quoting.quoteExactInput( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', '100', // Small trade 10000, ); // Result: Low price impact, good execution // Large trade that might exit the range const quote2 = await gSwap.quoting.quoteExactInput( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', '1000000', // Large trade 10000, ); // Result: Higher price impact as it moves through different liquidity zones ``` ## Impact on Price Movement ### Liquidity Walls Dense liquidity concentration creates "walls" that resist price movement: - **Support Levels**: Heavy liquidity below current price - **Resistance Levels**: Heavy liquidity above current price - **Price Gaps**: Areas with little liquidity where price can move rapidly ### Breaking Through Ranges When trades exhaust liquidity in a range: 1. **Price Impact Increases**: Less liquidity means worse prices 2. **Slippage Risk**: Rapid price movement through sparse areas 3. **Range Transitions**: Moving from high to low liquidity zones ```typescript // Check multiple quote sizes to see how their price impacts differ const tradeSizes = ['100', '1000', '10000', '100000']; for (const size of tradeSizes) { const quote = await gSwap.quoting.quoteExactInput( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', size, 10000, ); const impactPercent = quote.priceImpact.multipliedBy(100).toNumber(); console.log(`${size} $GALA trade: ${impactPercent.toFixed(2)}% price impact`); } ``` ## Advanced Concepts ### Impermanent Loss in Concentrated Liquidity Impermanent loss means your liquidity position becomes worth less than if you had simply held the original tokens separately. This happens because the AMM automatically rebalances your position as prices change, potentially selling the appreciating token and buying more of the depreciating token. In concentrated liquidity, this works differently than traditional AMMs: **Within Your Range:** - You earn LP fees as trades happen through your position - You experience impermanent loss as the AMM automatically adjusts your token balance to maintain the correct ratio for the current price - Narrower ranges = higher fee earnings but greater exposure to impermanent loss **Outside Your Range:** - Your position stops earning fees - You're fully converted to the token that's worth relatively less - No trading happens in your position until price returns to your range **Example:** ```text Position: 100 $GALA + 50 USDC in range $0.48-$0.52 If $GALA price rises above $0.52: - Your position converts entirely to USDC (the "cheaper" token) - You stop earning LP fees until price returns below $0.52 - You have impermanent loss vs just holding the original tokens ``` **Risk Management:** - Wider ranges reduce impermanent loss but earn fewer LP fees - When price moves near your range boundaries, you can: - Remove liquidity (realizing any impermanent loss) and add it back at a new range around the current price - Add additional liquidity at a new range while keeping your original position - Wait for the price to return to your original range - LP fees can offset impermanent loss over time, especially in high-volume pairs ### Range Orders Concentrated liquidity can simulate limit orders: - **Buy Order**: Provide liquidity below current price - **Sell Order**: Provide liquidity above current price - **Automatic Execution**: Trade happens when price hits your range ### Full Range Liquidity Providing liquidity between price $0 and $Infinity is known as providing liquidity across the full range. This spreads your liquidity across all possible prices, essentially replicating traditional AMM behavior. **Advantages of Full Range:** - **Never goes out of range** - Always earning LP fees regardless of price movement - **Less active management** - Set it and forget it approach - **Lower impermanent loss** - Spread across all prices reduces sensitivity to price changes **Disadvantages of Full Range:** - **Capital inefficiency** - Most of your liquidity sits far from current price where no trading happens - **Lower fee earnings** - Your capital is diluted across the entire price curve - **Opportunity cost** - Missing out on higher returns from concentrated positions **When Full Range Makes Sense:** - You want passive rewards without active management - You're unsure about future price direction - You're providing liquidity to a very volatile or unpredictable token pair - You have a large amount of capital and want steady, predictable returns **When Concentrated Ranges Are Better:** - You have a strong view on likely price ranges - You want to maximize fee earnings from your capital - You're willing to actively manage your positions - You're providing liquidity to a stable or predictable token pair ## Related Concepts - **[Price Impact](/gswap-sdk/next/pool-concepts/price-impact.md)** - How trade size affects execution price - **[Slippage](/gswap-sdk/next/pool-concepts/slippage.md)** - How market movement affects execution price - **[Fees](/gswap-sdk/next/pool-concepts/fees.md)** - How different fee levels attract different liquidity Understanding liquidity concentration is crucial for efficient trading on modern AMMs. It explains why some trades execute with minimal impact while others face significant price movement, and helps inform better trading strategies. --- # Fees The pool fee tier is expressed in hundredths of a basis point in the SDK. The current contract supports four tiers: | Fee tier | Trading fee | Tick spacing | Protocol fee | | ---: | ---: | ---: | ---: | | `0` | 0% | 200 | 0.1 of the trading fee | | `500` | 0.05% | 10 | 0.1 of the trading fee | | `3000` | 0.30% | 60 | 0.1 of the trading fee | | `10000` | 1.00% | 200 | 0.1 of the trading fee | Tier `0` is the no-trading-fee tier. It still has a tick spacing of 200 and is not interchangeable with a missing fee value. Omitting `fee` from a quote asks the backend to compare all available tiers, including `0`. ```typescript const quote = await gSwap.quoting.quoteExactInput('GALA', 'GUSDC', '100'); console.log(`Best tier: ${quote.feeTier}`); const zeroFeeQuote = await gSwap.quoting.quoteExactInput('GALA', 'GUSDC', '100', 0); ``` Trading fees are included in quote amounts. The protocol fee is currently fixed at 10% of the trading fee. The v2 contract does not add a separate gSwap gas charge; network fee policy is outside the quote. Tick ranges must use the spacing shown above. For example, a `3000` pool must use lower and upper ticks divisible by 60. See [Liquidity Concentration](/gswap-sdk/next/pool-concepts/liquidity-concentration.md). --- # Error Handling Every error the SDK throws is a `GSwapSDKError` with a stable `code` and a flat object of named `params`. The SDK owns no user-facing text: an app maps `code` + `params` to its own localized string. `GSwapSDKError` extends `GalaSDKError`, the base class in `@gala-chain/gala-core-sdk`. Errors the core layer throws itself (a signer, the fetch requestor's `TRANSPORT_ERROR` / `REQUEST_TIMEOUT`, the uniqueKey checks) are plain `GalaSDKError`s, not `instanceof GSwapSDKError`. Do not test `instanceof GSwapSDKError`: use `isGSwapError(error, code?)` from this package or `isGalaError(error, code?)` from core. Both recognise every error of either catalog. | Field | What it is | Stable? | | --- | --- | --- | | `code` | The catalog code (`NON_CANONICAL_PAIR`, `RATE_LIMITED`, ...). The only thing to branch on. | yes | | `params` | Named placeholders of that code: only `string`, `number` and `boolean`, never an object, never a secret. A param may be a closed set of string tokens (`INVALID_PRIVATE_KEY.reason`, `SUBMISSION_OUTCOME_UNKNOWN.reason`): the matching const array (`INVALID_PRIVATE_KEY_REASONS`, ...) lists every member so you can map each one. Feed them to your i18n library. | yes, per code | | `message` | English, generated from the catalog template and `params`, for logs and developers. | **no: never show it, never match on it** | | `status`, `url`, `uniqueKey`, `requestTransactionId`, `applyTransactionId`, `blockNumber`, `retryAfterMs` | Facts about the failure that are not placeholders. | yes | | `body`, `bodyText` | The failing response: parsed JSON in `body`, raw text of a non-JSON answer in `bodyText`. Diagnostics only. | server-defined | | `cause` | The error that caused this one (a transport failure, a wallet rejection). | - | | `notFound` | `true` for HTTP 404, `NO_POOL_AVAILABLE` and `UNKNOWN_TOKEN`. | yes | | `phase` | `'pre_send'`, `'in_flight'` or `'post_send'`: how far the operation got (see "Where the failure happened"). `isPreSendError(error)` reads it. | yes, per code | | `shadow` | `true` when the error came from the dark (shadow) path (see "Dark swaps"). | yes | The server's own English (a gateway or chain message) reaches you in two places only: the raw `body`, and the `serverMessage` param of every code that relays it (`HTTP_ERROR`, `GATEWAY_REPORTED_ERROR`, the gateway bounces, `CHAIN_REJECTED`, `CONFIRMATION_FAILED`, ...). `serverMessage` is read from the failing body in one fixed order (`message`, `Message`, `error.message`, `error.Message`; the first non-empty string). It is DATA from the server, not SDK text: it is English, it can change, and it is the empty string when the server sent no text or a non-JSON page (the SDK never writes English in its place). An app may relay it next to its own string or ignore it; do not match on it. The codes that do not carry `serverMessage` have no server text to carry: a 2xx acknowledgement that is missing something (`GATEWAY_DATA_MISSING`, `GATEWAY_MODE_INVALID`, `GATEWAY_SYNC_REQUEST_TRADE`, `MISSING_UNIQUE_KEY`, `UNIQUE_KEY_MISMATCH`, `SHADOW_NOT_QUEUED`, `CONFIRMATION_MALFORMED`, `CONFIRMATION_KEY_MISMATCH`) is judged by its shape, and the quote classifications (`NO_POOL_AVAILABLE`, `INSUFFICIENT_LIQUIDITY`, `UNKNOWN_TOKEN`) are made from the server's text but state their facts as structured params. ## Deciding: `classifyFailure` `classifyFailure(error)` answers "may I offer Retry?" and "could the write have been applied?" from the code, so an app does not re-derive it per code. It returns `{ outcome, retryable }`: | `outcome` | Meaning | `retryable` | | --- | --- | --- | | `rejected` | The chain refused (`CHAIN_REJECTED`, a 422 `CHAIN_DISPATCH_FAILED`): a new request is safe. | yes | | `unknown` | The request may have been applied (`SUBMISSION_OUTCOME_UNKNOWN`, any `CONFIRMATION_*`, a 2xx that proves nothing, a 409 or 5xx dispatch failure, a write's 5xx). Keep `error.uniqueKey` and confirm it; never submit under a fresh key. | never | | `not_queued` | The gateway refused the write before queueing it (the bounces, `RATE_LIMITED`, a write's 4xx, `UPDATE_REQUIRED`). | yes, except `SHADOW_NOT_QUEUED`, `UPDATE_REQUIRED` and a write's non-429 4xx | | `not_sent` | The request never left, for a reason outside the call itself: the signer or wallet failed (locked, unreachable, the person declined), the key provider or a token resolver failed, or no key was available yet. `SIGNING_FAILED`, `KEY_PROVIDER_FAILED`, `TOKEN_RESOLUTION_FAILED`, `INVALID_PRIVATE_KEY` with `reason: 'no_key_provided'`. | yes | | `invalid_input` | The call cannot work as written (validation, missing signer or wallet, unknown token or pool, `INVALID_UNIQUE_KEY`, a READ's `UPDATE_REQUIRED`). | never | | `transient` | A read or connection failed with no state change. | yes | Anything that is not a `GSwapSDKError` or a `GalaSDKError` is `unknown` and not retryable. That is only what escapes AFTER the request left (an app requestor that rejects with its own error, a callback of yours that throws once bytes were sent), or an error your own code raised before it called the SDK: handle those first. `retryable` is the SDK's floor (a repeat cannot double-apply); an app may still withhold it. The per-code decision is in `src/utils/failure_classification.ts` and pinned by `tests/failure_classification.test.ts`; the table above lists the codes per outcome. ### Asking about a wrapper, not just an SDK error: failure views Apps wrap SDK errors in their own classes. `classifyFailure` and every guard in this section accept a `GSwapSDKError` or a plain-object **failure view** and decide from the same fields, so you do not have to keep the original error beside the wrapper to ask: ```typescript import type { FailureOutcome } from '@gala-chain/gala-core-sdk'; interface FailureView { code: string; // required: a catalog code params?: Record; // e.g. { status } of an HTTP_ERROR, { reason } of a SIGNING_FAILED status?: number; // the HTTP status of the answer phase?: 'pre_send' | 'in_flight' | 'post_send'; // absent: the catalog's phase for `code` uniqueKey?: string; // present: it is a WRITE's failure write?: boolean; // false: it is a READ's failure (see below); absent or true: a write outcome?: FailureOutcome; // an APP error's declared meaning; read only for a code the catalog does not define retryable?: false; // withhold-only: takes Retry away from the declared outcome, never grants it shadow?: boolean; notFound?: boolean; } ``` A class like `class V2Failure extends Error { code; params; status; uniqueKey; write }` is already one; `toFailureView(value)` (from `@gala-chain/gala-core-sdk`, as are the `FailureView` type, `isWriteView` and `FAILURE_OUTCOMES`) shows what the SDK reads (a field of the wrong type reads as absent). The guards that take a view: `classifyFailure`, `isRelayableRefusal`, `isUnprovenAcknowledgement`, `isUninterpretedAnswer`, `isPreSendError`, `isShadowError`, `isWalletUserRejection`, `isNoMarket`, `mayHaveBeenQueued`, `pendingSwapFateFor`. A value with no string `code`, a `code` the catalog does not define (an ethers `'ACTION_REJECTED'`, an app-only code) or an `HTTP_ERROR` view with no status is `unknown` and not retryable. `isRelayableRefusal` narrows to `GSwapSDKError<...>` only when called with an SDK error; with a view it answers `boolean`. **A view is a WRITE unless it says it is a read (fail closed).** A view with no `uniqueKey` and no `write: false` is judged a write: its 5xx stays `unknown` and not retryable. Dropping the `uniqueKey` can therefore never turn a write's 5xx into a retryable `transient` (a retry would submit a second trade). Only `write: false` without a `uniqueKey` is a read; `GSwapSDKError.write` is `false` for every failure of an SDK read and `true` otherwise. Copy `code`, `params`, `status`, `uniqueKey` and `write` from the SDK error when you wrap it. **An error your app raises declares what it means.** A code the catalog does not define is `unknown` (the SDK cannot say what happened, and `mayHaveBeenQueued` is `true`: a wrong "failed" invites a duplicate). An error raised BEFORE anything was signed or sent says so with `outcome`: `{ code: 'POSITION_STALE', outcome: 'not_sent' }` classifies as `not_sent` (retryable) and `mayHaveBeenQueued` is `false`. `retryable: false` withholds Retry from the declared outcome (`{ code: 'DID_NOT_QUEUE', outcome: 'not_queued', retryable: false }` is `NOT_QUEUED_FINAL`); `true` is never read, so a view cannot grant Retry. The declared `outcome` is read only for a code the catalog does not define: for a catalog code the SDK's own table decides. ### After the write is queued: `afterQueued` `classifyFailure(error, { afterQueued: true })` is for the step AFTER the gateway acknowledged the write (confirming it, reading its apply result): a new request would be a second trade, so `retryable` is `false` for every code, and `outcome` is unchanged. The one exception is `rejected` (the chain evaluated the queued write and refused it: `CHAIN_REJECTED`, a 422 dispatch): that proves it was not applied, so a new request under a fresh key cannot double it and `retryable` keeps its answer (`true`). Where a confirmation stopped: `confirmationStateOf(error)` is `'aborted'` (your `AbortSignal` ended the wait), `'timeout'` or `'failed'` (or `undefined` when it is not a failed confirmation), and `isConfirmationAborted` / `isConfirmationTimeout` are the two guards; a screen never matches `CONFIRMATION_*` codes itself. All of them are `unknown` outcomes: confirm the same key. ### Two questions every app asks: `isNoMarket` and `mayHaveBeenQueued` `isNoMarket(error)` is true for `NO_POOL_AVAILABLE`, `INSUFFICIENT_LIQUIDITY`, `UNKNOWN_TOKEN` and a READ answered 404 (`error.notFound`): show "no market for this pair", not an error. A write that got a 404 is a missing route, not a missing market. `mayHaveBeenQueued(error)` is `classifyFailure(error).outcome === 'unknown'`: keep `error.uniqueKey` and confirm it, never submit again under a fresh key (a value the SDK cannot judge is `true` too). ### An HTTP status you read yourself: `GSwapSDKError.fromStatus` For a resolved HTTP answer the SDK did not read (a v1 endpoint, an interceptor's rejection), `GSwapSDKError.fromStatus(status, { url?, uniqueKey?, write?, serverMessage?, body?, retryAfterMs? })` builds the error the SDK would have thrown: `UPDATE_REQUIRED` for 426, `HTTP_ERROR` otherwise, phase `post_send`. A `uniqueKey` makes it a write (`classifyFailure`: a 5xx is `unknown`, a 426 `not_queued`); without one it is a read (`write: false` on the error: a 5xx is `transient`, a 426 `invalid_input`). `write: true` with no key throws `INVALID_UNIQUE_KEY`. ### Classifying a step of your own: `classification` and `notSentClassification` An app step that runs before it calls the SDK (a quote refresh before signing) is not an SDK call, so `classifyFailure` cannot classify it. Build its classification with the SDK's type and values, not a literal: ```typescript import { classification, notSentClassification, type FailureClassification } from '@gala-chain/gswap-sdk'; const refreshFailed: FailureClassification = notSentClassification(); // { outcome: 'not_sent', retryable: true } const bad: FailureClassification = classification('invalid_input'); // { outcome: 'invalid_input', retryable: false } ``` `classification(outcome)` sets `retryable` to the SDK's default for that outcome: `false` for `unknown` and `invalid_input`, `true` for the others. `FailureClassification` is exported by this package; `FailureOutcome` and `FAILURE_OUTCOMES` are exported by `@gala-chain/gala-core-sdk`, so an app can type a `Record` and have a new outcome fail to compile until it decides it. An app may take Retry away from an outcome, never grant it: `classification('not_queued', { retryable: false })`, exported frozen as `NOT_QUEUED_FINAL`, is the SDK's own value for a refusal the gateway will repeat (`SHADOW_NOT_QUEUED`, the version wall, a write's 4xx). Use it as it is instead of spreading `classification('not_queued')` and overriding `retryable`. ### Where the failure happened: `error.phase` and `isPreSendError` Every `GSwapSDKError` carries `phase`, measured against the request the operation exists to send (for a write, the POST with the signed DTO): | `phase` | Meaning | Consequence | | --- | --- | --- | | `pre_send` | NOTHING was transmitted: validation, symbol resolution, the signer, the wallet, a key provider failed. | The write cannot have been queued. The outcome is `invalid_input` (change the input) or `not_sent` (repeat is safe). It is never `unknown` or `rejected`. | | `in_flight` | The request left (or may have) and no answer was read: a timeout, a broken connection. | For a write the outcome is `unknown`; for a read it is `transient`. | | `post_send` | An answer was read, or the write was already accepted: a refusal, an acknowledgement that proves nothing, an unusable body, any confirmation failure. | Decided by the code (`rejected`, `not_queued`, `unknown`). | Each catalog entry declares the phase of its code (the table below has a column for it), and a throw site that can see the same code in another phase refines it. `isPreSendError(error)` reads it. **An app never needs an error class of its own to say "nothing was sent".** Every point where the SDK calls code the app supplied before the request leaves wraps what that code throws into a catalogued pre-send error with the original as `cause`: | App-supplied code | Failure becomes | | --- | --- | | `signer.signObject` (swaps, every position write, the fee DryRun) | `SIGNING_FAILED` with `params.method` and `params.reason` (`user_rejected` when the wallet says the person declined: code `4001`, `ACTION_REJECTED`, or the wallet's own "User rejected ..." text; else `failed`), and `error.walletCode` (the wallet's own `code`: a number such as `4001` or a string such as `'ACTION_REJECTED'`, `undefined` when the wallet set none; a typed field on the error, not a param, and never in `message`) | | the key provider of `createLazyPrivateKeySigner` (from `@gala-chain/gala-core-sdk`) | `KEY_PROVIDER_FAILED`; a provider that returns nothing is `INVALID_PRIVATE_KEY` with `reason: 'no_key_provided'`. Both are `not_sent`. | | a `TokenResolver` / the registry read it makes through your requestor | `TOKEN_RESOLUTION_FAILED` with `params.token` | | a signed body that cannot be serialized | `SIGNING_FAILED` (checked before the POST, so a transport hook can never call it "maybe queued") | An SDK error those callbacks throw themselves (for example `SIGNER_ADDRESS_MISMATCH`) keeps its code. Nothing is wrapped AFTER the request left: a rejection of your own `httpRequestor` that the SDK cannot read stays what it is (use `isTransportFailure` and `answerOfRejection` below). The pending-swap store never throws and the SDK never calls it, and there is no `uniqueKey` generator hook, so neither needs a wrapper. ### Relaying the gateway's answer: `isRelayableRefusal` and `isUninterpretedAnswer` `isRelayableRefusal(error)` is true for the errors whose `params.serverMessage` is the gateway's own answer to this write and may be shown as sent: `GATEWAY_REPORTED_ERROR`, the gateway bounces (`METHOD_NOT_ALLOWED`, `SIGNATURE_INVALID`, `SIGNER_MISMATCH`, `DTO_INVALID`, `BOUNDS_VIOLATION`, `SYMBOL_CONFLICT`, `RATE_LIMITED`, `GATEWAY_REJECTED`) and `CHAIN_DISPATCH_FAILED`. Called with an SDK error it narrows it, so `error.params.serverMessage` is typed (with an `unknown` or a view it answers `boolean`). Show it when it is not empty and your own line when it is; never the SDK's English `message`. `CHAIN_REJECTED` (worded by where it is shown), `HTTP_ERROR` and the five unproven acknowledgements are not relayable. A `CHAIN_DISPATCH_FAILED` with `status` 409 is the "uniqueKey already consumed" replay (`classifyFailure`: `unknown`): an app that words it itself asks `isUniqueKeyConsumed(error)` first. ```typescript import { isGSwapError, isRelayableRefusal } from '@gala-chain/gswap-sdk'; function present(error: unknown): void { if (isGSwapError(error) && isRelayableRefusal(error)) show(error.params.serverMessage || t('swap.requestFailed')); } ``` `isUninterpretedAnswer(error)` answers a different question: did the gateway ANSWER 2xx with something the SDK refused to interpret, so that the answer itself (`error.body` / `error.bodyText`) is the thing to read? It is true for the five unproven acknowledgements and `GATEWAY_REPORTED_ERROR`, and replaces an app's own `isUnprovenAcknowledgement(e) || isGSwapError(e, 'GATEWAY_REPORTED_ERROR')`. ### Did the person decline? `isWalletUserRejection` For a signature the SDK asks for, read `SIGNING_FAILED` and `params.reason === 'user_rejected'`. For wallet code of your own (a connect or registration flow, a v1 write path, an analytics hook), `isWalletUserRejection(value)` runs the same test the SDK applies to what a signer throws, so you keep no matcher of your own: ```typescript import { isWalletUserRejection } from '@gala-chain/gala-core-sdk'; try { await wallet.connect(); } catch (error) { if (!isWalletUserRejection(error)) report(error); // a decline is the person's choice, not a failure } ``` It decides from the wallet's own fields first: `code` `4001` (EIP-1193), `'ACTION_REJECTED'` (ethers) or `'USER_REJECTED'`, or `name === 'UserRejectedRequestError'` (viem). Only when those are absent does it read the wallet's text (`message`, `Message`, `shortMessage`, `details`, `errorDetails`, `reason`, three levels deep, or a bare string) for "user rejected", "user denied", "user cancelled", "request rejected", "rejected by user", "rejected the request", "cancelled" / "canceled" or a "signature ... cancel" sentence. **The wording fallback is a last resort for wallets that do not set codes**: it reads a third party's text and is deliberately broad, so wherever you control the wallet, set a `code`. An SDK error is never read by its text (`SIGNING_FAILED` with reason `user_rejected` is a decline; every other SDK error is not, and the same holds for a plain-object view of one: `{ code: 'SIGNING_FAILED', params: { reason: 'user_rejected' } }`). `walletDeclineCode(value)` reads the wallet's code the same way `error.walletCode` is filled. **Import it from the light subpath in app-shell code.** `@gala-chain/gala-core-sdk/wallet` holds only the dependency-free wallet helpers (`isWalletUserRejection`, `walletDeclineCode`, `isGalaErrorLike`) and never loads the catalog or the rest of the SDK (under 2 kB, against 85 kB for the same function through the rc.6 main entry). The `@gala-chain/gswap-sdk/wallet` subpath was removed in 2.0.0: ```typescript import { isWalletUserRejection } from '@gala-chain/gala-core-sdk/wallet'; ``` The main entry's browser build is tree-shakeable and every failure decider (`classifyFailure`, `mayHaveBeenQueued`, `pendingSwapFateFor`, `isNoMarket`, `isRelayableRefusal`, ...) is shell-safe too, each with a measured byte budget. [Bundle size](/gswap-sdk/next/other/bundle-size.md) lists what each helper costs an app shell that also lazy-loads the whole SDK, and how the budgets are tested. ### Dark swaps: `error.shadow` and `isShadowError` Everything `swapShadow`, `submitSwapShadow` and `ChainGateway.submitShadow` throw has `error.shadow === true` (validation, the signer, the transport, `SHADOW_NOT_QUEUED`), and `isShadowError(error)` also answers for a non-SDK object that escaped (your requestor's own rejection; a thrown primitive cannot be remembered). The classification is the same as on the public path, so an app that never retries or falls back publicly after a dark swap applies that on top: `retryable && !isShadowError(error)`. A shadow gateway refusal that resolves (`{ ok: false, kind }`) is an outcome, not an error; its kinds are `SHADOW_FAILURE_KINDS` (`unavailable`, the only retryable one; `disabled`, the route answered 400, for example `SHADOW_UNSUPPORTED_TYPE` for a method that is not a swap; `rejected`, with the gateway's `message`; `unknown`). Shadow Swaps are enabled in every environment, so `disabled` never means the feature is off. ### Reading an HTTP answer out of a rejection: `answerOfRejection` A requestor on an HTTP client that rejects every non-2xx (an axios interceptor, a version wall) loses the answer the SDK reads. `new ChainGateway({ answerOfRejection })` maps such a rejection to `{ status, body, headers? }` and the write is handled exactly as if the answer had been resolved: `DTO_INVALID`, `RATE_LIMITED`, `CHAIN_DISPATCH_FAILED`, ... or `HTTP_ERROR` for an uncoded body, carrying the signed `uniqueKey` and classified as a write. `isTransportFailure` is asked first. For a requestor that wraps `fetch` and rejects with its own errors, pass `isTransportFailure: isFetchTransportFailure` (from `@gala-chain/gala-core-sdk`): a `TypeError` (any engine's wording) or a `NetworkError` means no answer arrived; an `AbortError` or `TimeoutError` never does (the request layer reports those itself). `isUnprovenAcknowledgement(error)` is true for the five 2xx codes that do not prove a write was queued (one line of copy, outcome `unknown`). ## Narrowing by code `isGSwapError(error, code)` narrows `error.params` to that code's params. It accepts a code of either catalog and any `GalaSDKError`, so it also answers for an error core threw: ```typescript import { isGSwapError } from '@gala-chain/gswap-sdk'; try { await gSwap.swaps.swap('GALA', 'GUSDC', 3000, { exactIn: '100' }); } catch (error) { if (isGSwapError(error, 'RATE_LIMITED')) { wait(error.retryAfterMs ?? 60_000); } else if (isGSwapError(error, 'NON_CANONICAL_PAIR')) { show(t('errors.NON_CANONICAL_PAIR', error.params)); // { token0, token1 } } else if (isGSwapError(error)) { // error.code is the union of every catalog code: switch on it exhaustively. show(t(`errors.${error.code}`, error.params)); } else { throw error; } } ``` `isGSwapError(error)` with no code narrows to `AnyGSwapError`, the union of one `GSwapSDKError` per code, so `error.code === 'INVALID_FEE'` narrows `error.params` to `{ field, value, allowed }`. ## Localizing: i18next `gswapErrorTemplates` maps every DEX code to its English template, `{placeholders}` included, and `galaErrorTemplates` (from `@gala-chain/gala-core-sdk`) does the same for the signing, transport, wallet, typed-data and uniqueKey codes; merge the two. Use them as the English seed of your resource file and translate it; i18next interpolates with `{{name}}`, so convert the markers once when you build the seed: ```typescript import i18next from 'i18next'; import { isGSwapError, gswapErrorTemplates } from '@gala-chain/gswap-sdk'; import { galaErrorTemplates } from '@gala-chain/gala-core-sdk'; // en/errors.json, generated once from the SDK's templates: const en = Object.fromEntries( Object.entries({ ...galaErrorTemplates, ...gswapErrorTemplates }).map(([code, template]) => [ code, template.replace(/\{(\w+)\}/gu, '{{$1}}'), ]), ); // de/errors.json, hand-written: // { "NON_CANONICAL_PAIR": "Das Paar {{token0}}/{{token1}} ist nicht in kanonischer Reihenfolge." } function errorText(error: unknown): string { if (!isGSwapError(error)) return i18next.t('errors.UNKNOWN'); return i18next.t(`errors.${error.code}`, { ...error.params, defaultValue: i18next.t('errors.UNKNOWN'), }); } ``` ## Localizing: ICU MessageFormat (FormatJS) ICU uses `{name}` exactly as the SDK's templates do, so the English seed is usable as is, and plurals or selects are possible where a language needs them: ```typescript import { createIntl } from '@formatjs/intl'; import { gswapErrorTemplates, isGSwapError } from '@gala-chain/gswap-sdk'; import { galaErrorTemplates } from '@gala-chain/gala-core-sdk'; const templates: Record = { ...galaErrorTemplates, ...gswapErrorTemplates }; const intl = createIntl({ locale: 'fr', messages: { NON_CANONICAL_PAIR: 'La paire {token0}/{token1} n’est pas dans l’ordre canonique.', INVALID_FEE: '{field} : {value} n’est pas un palier de frais valide ({allowed}).', }, }); function errorText(error: unknown): string { if (!isGSwapError(error)) return intl.formatMessage({ id: 'UNKNOWN', defaultMessage: 'Something went wrong' }); return intl.formatMessage( { id: error.code, defaultMessage: templates[error.code] ?? error.code }, error.params, ); } ``` `params` never contain a nested object or an `Error`, so they can be passed straight through. A per-field validation error carries the field name and the offending value or limits (`{ field: 'fee', value: 250, allowed: '0,500,3000,10000' }`, lists pre-joined into a string), so a form can attach the message to the right input. ## Mapping a chain refusal: `chainErrorKeyOf` and the gateway's `errorKey` A refusal by the chain reaches you in two shapes, and both carry the chain's own machine-readable `ErrorKey` so an app maps the key and never the English: - `CHAIN_REJECTED`: a queued write's apply result with `Status: 0` (or a synchronous write the chain refused). `params.errorKey` is the apply result's `ErrorKey` (`CHAIN_ERROR` when it carried none) and `params.serverMessage` its `Message`. - `CHAIN_DISPATCH_FAILED`: the gateway failed the dispatch itself. The swap backend puts the chain's key in a top-level `errorKey` field of its failure body, present only when the chain supplied one, and the SDK copies it to `params.errorKey`. It is the empty string when the body has none (an older deployment, or a failure the chain gave no key), so treat `''` as "no key", not as a key. `chainErrorKeyOf(error)` reads the key from either, from an SDK error or a failure view: it is `params.errorKey` of a `CHAIN_REJECTED` or `CHAIN_DISPATCH_FAILED`, and `undefined` for any other code and for the empty key. It is shell-safe (no catalog), so a presenter can map a key without the SDK: ```typescript import { chainErrorKeyOf, isGSwapError } from '@gala-chain/gswap-sdk'; function chainRefusalText(error: unknown): string | undefined { const key = chainErrorKeyOf(error); if (key === undefined) return undefined; // not a chain refusal, or the gateway sent no key const serverMessage = isGSwapError(error, 'CHAIN_REJECTED') ? error.params.serverMessage : ''; return t(`chain.${key}`, { defaultValue: serverMessage }); } ``` ## What an app should treat as what - **Rejected on chain:** only `CHAIN_REJECTED`. `params.errorKey` is the chain `ErrorKey`; fix the business condition and never retry the same key. - **Outcome unknown, never resubmit, confirm `error.uniqueKey` later:** `SUBMISSION_OUTCOME_UNKNOWN`, `CONFIRMATION_TIMEOUT`, `CONFIRMATION_ABORTED`, `CONFIRMATION_FAILED`, `CONFIRMATION_MALFORMED` and `CONFIRMATION_KEY_MISMATCH`. Branch on "is it `CHAIN_REJECTED`?", not on "is it one of the unknown ones": any code you did not list must not be treated as a rejection. - **Not queued (the write did not happen):** `MISSING_UNIQUE_KEY`, `UNIQUE_KEY_MISMATCH`, `GATEWAY_SYNC_REQUEST_TRADE`, `GATEWAY_MODE_INVALID`, `GATEWAY_DATA_MISSING`, `GATEWAY_REPORTED_ERROR` and the gateway bounces (`METHOD_NOT_ALLOWED`, `SIGNATURE_INVALID`, `SIGNER_MISMATCH`, `DTO_INVALID`, `BOUNDS_VIOLATION`, `SYMBOL_CONFLICT`, `RATE_LIMITED`, `GATEWAY_REJECTED`). The exception is `CHAIN_DISPATCH_FAILED` with `error.status === 409`: the `uniqueKey` was already consumed, so confirm the original key and do not retry. - **Transport:** `TRANSPORT_ERROR` (nothing answered; the original error is `cause`), `REQUEST_TIMEOUT`, `HTTP_ERROR` (`params.status`). A caller's own abort is not wrapped: it comes back as the abort it is. ## Rate limiting The write limiter allows 30 writes per recovered signer in a sliding 60-second window, matching `signer-rate-limiter.ts` in the defi-backend. The SDK does not automatically retry writes. Honor the server's `Retry-After` header through `error.retryAfterMs`; if it is absent, wait for the window to pass before trying again with the same intent. `SIGNER_MISMATCH` is only relevant to contract operations that explicitly name an actor, such as a token or fee operation. The v2 DEX operations have no `signerField`: their identity is the signer recovered from the signature. `X-Wallet-Address` is an attribution hint, not an identity assertion. ## The catalog Generated from `src/classes/gswap_error_catalog.ts` (`npm run docs:error-catalog`); a test fails while this table differs from the catalog. The template column is the English the SDK's `message` is generated from, shipped as `gswapErrorTemplates` for use as a seed or fallback. "App flows" is the flow of the two Gala apps that maps the code today. Since 2.0.0 this table lists gswap-sdk's own DEX codes. The signing, transport, wallet, typed-data and uniqueKey codes (`INVALID_PRIVATE_KEY`, `SIGNING_FAILED`, `KEY_PROVIDER_FAILED`, `REQUEST_TIMEOUT`, `TRANSPORT_ERROR`, `INVALID_TIMEOUT`, `PERSONAL_SIGN_*`, `EIP712_*`, `TYPED_DATA_*`, `INVALID_UNIQUE_KEY`, `INVALID_UNIQUE_KEY_PREFIX`, `CSPRNG_UNAVAILABLE`, ...) moved with the signing code to `@gala-chain/gala-core-sdk`, which documents them in its `docs/error-catalog.md` and ships their templates as `galaErrorTemplates`. A `GSwapSDKError` can carry a code of either catalog, `classifyFailure` answers for both, and `isGSwapError` recognises an error core threw itself (a signer, the fetch requestor) as well as a `GSwapSDKError`. {/* error-catalog:start (generated by npm run docs:error-catalog) */} | code | phase | params | English template (seed only) | when thrown | | --- | --- | --- | --- | --- | | `HTTP_ERROR` | `post_send` | `status`:number, `url`:string, `serverMessage`:string (not in `message`) | Unexpected HTTP error \{status\} from \{url\}. | An HTTP failure with no readable relay or chain answer (a proxy 502, a WAF page, an empty 500); the raw text is `bodyText`. | | `UPDATE_REQUIRED` | `post_send` | `status`:number | The backend refused this app version and requires an update (HTTP \{status\}); nothing was queued. | The backend answered HTTP 426: it refuses this app or extension version (the version wall). Thrown for a 426 on any read or write request, whatever the body says; the body is `error.body`. A write is `not_queued` and a read `invalid_input`, never retryable: only an update helps. A confirmation read that gets a 426 stays `CONFIRMATION_FAILED` (`params.status` 426) because the write it confirms may be applied. | | `REQUEST_FAILED` | `in_flight` | `operation`:string | The \{operation\} request failed. | A read failed in a way that is not an SDK error (an unreadable body, an app requestor's own rejection); `params.operation` is `pool`, `quote` or `position`. The failed error is `cause`. | | `METHOD_NOT_SUPPORTED` | `pre_send` | `method`:string | The method \{method\} is not supported; swaps are queued through RequestTrade. | The retired synchronous `Trade` method was submitted. | | `SUBMISSION_OUTCOME_UNKNOWN` | `in_flight` | `reason`:timeout\|transport | The submission outcome is unknown (\{reason\}): the request may have reached the gateway. Confirm before retrying. | The write POST got no answer: `params.reason` is `timeout` (it exceeded the gateway timeout) or `transport` (the connection failed or the body broke off; also a rejection the app names in `ChainGatewayOptions.isTransportFailure`). The swap may have been accepted: confirm `error.uniqueKey`; whether to offer Retry (a new key) is the app's policy. Reads keep `TRANSPORT_ERROR`. | | `GATEWAY_REPORTED_ERROR` | `post_send` | `serverMessage`:string | The gateway reported an error for this write: \{serverMessage\} | A 2xx answer whose envelope says `error: true`; the envelope is `error.body`. | | `GATEWAY_DATA_MISSING` | `post_send` | - | The gateway response is missing its data object. | A 2xx answer without a `data` object. | | `GATEWAY_MODE_INVALID` | `post_send` | - | Gateway response must contain data.mode="sync" with data.result, or data.mode="queued". | A 2xx answer whose `data.mode` / `result` / ids are not a valid sync or queued acknowledgement. | | `GATEWAY_SYNC_REQUEST_TRADE` | `post_send` | - | The gateway executed RequestTrade synchronously, which this SDK refuses; RequestTrade must be queued. | RequestTrade answered as executed synchronously, which the SDK refuses. | | `MISSING_UNIQUE_KEY` | `post_send` | - | The gateway acknowledged RequestTrade without echoing its uniqueKey, so it cannot be tied to the signed request. | A queued RequestTrade acknowledgement that does not echo a uniqueKey. | | `UNIQUE_KEY_MISMATCH` | `post_send` | - | Gateway response data.uniqueKey must match the signed RequestTrade uniqueKey. | A queued RequestTrade acknowledgement for another uniqueKey than the signed one. | | `SHADOW_NOT_QUEUED` | `post_send` | - | The swap backend did not queue the shadow request. | A shadow RequestTrade success that does not queue the signed key. | | `SHADOW_SUBMIT_NEEDS_WALLET_ADDRESS` | `pre_send` | - | A shadow submission needs a walletAddress (the X-Wallet-Address header): pass one to the GSwap constructor or to this call. | `submitShadow` without a wallet address. | | `METHOD_NOT_ALLOWED` | `post_send` | `serverMessage`:string | The gateway does not expose this contract method: \{serverMessage\} | Gateway bounce 403: the contract method is not exposed. | | `SIGNATURE_INVALID` | `post_send` | `serverMessage`:string | The gateway could not verify the signature: \{serverMessage\} | Gateway bounce 401: the signature cannot be verified. | | `SIGNER_MISMATCH` | `post_send` | `serverMessage`:string | The recovered signer does not match an actor named by the operation: \{serverMessage\} | Gateway bounce 403: recovered signer differs from a named actor. | | `DTO_INVALID` | `post_send` | `serverMessage`:string | The gateway rejected the DTO shape: \{serverMessage\} | Gateway bounce 400: DTO shape or field validation failed. | | `BOUNDS_VIOLATION` | `post_send` | `serverMessage`:string | The gateway rejected a numeric, tick, symbol or range bound: \{serverMessage\} | Gateway bounce 400: a numeric, tick, symbol or range bound failed. | | `SYMBOL_CONFLICT` | `post_send` | `serverMessage`:string | The CreatePool symbol is already owned by another class: \{serverMessage\} | Gateway bounce 409: the CreatePool symbol belongs to another class. | | `RATE_LIMITED` | `post_send` | `serverMessage`:string | The gateway rate-limited this signer: \{serverMessage\} | Gateway bounce 429: 30 writes / 60 s exceeded; `error.retryAfterMs` when sent. | | `CHAIN_DISPATCH_FAILED` | `post_send` | `errorKey`:string, `serverMessage`:string | The chain dispatch failed (chain error key "\{errorKey\}"): \{serverMessage\} | The chain refused or failed the dispatch. `params.errorKey` is the chain's own key when the gateway body carries `errorKey` (`""` when it does not, as an older gateway): map it, not the text. HTTP 409 means the uniqueKey was already consumed (confirm the original key, never retry with a new one); 422 is a definite refusal; another 5xx is an upstream outage and the dispatch may have landed. | | `GATEWAY_REJECTED` | `post_send` | `gatewayCode`:string, `serverMessage`:string | Gateway rejected \{gatewayCode\}: \{serverMessage\} | Any gateway bounce code the SDK has no entry for; `params.gatewayCode` carries it. | | `CHAIN_REJECTED` | `post_send` | `errorKey`:string, `serverMessage`:string | GalaChain error \{errorKey\}: \{serverMessage\} | The chain refused: a `Status: 0` apply result, a sync write result, or an HTTP error body with `ErrorKey`. `params.errorKey` is the chain key. | | `INVALID_CHAIN_RESPONSE` | `post_send` | `resource`:string | Backend returned an invalid \{resource\}. | A read answer that is not the expected shape; `params.resource` names it, the answer is `error.body`. | | `INVALID_POSITION_RESPONSE` | `post_send` | `reason`:string | Backend returned an invalid position (\{reason\}). | A `/position` answer that is not a position. | | `CONFIRMATION_TIMEOUT` | `post_send` | - | Transaction confirmation timed out; the trade may still apply. Confirm the same uniqueKey again later instead of resubmitting. | No terminal apply result before the deadline. The trade may still apply: confirm the same key later, never resubmit. | | `CONFIRMATION_ABORTED` | `post_send` | - | Transaction confirmation was aborted. | The caller's `signal` aborted confirmation; the outcome is unknown. | | `CONFIRMATION_FAILED` | `post_send` | `status`:number, `serverMessage`:string (not in `message`) | Transaction confirmation failed with HTTP \{status\}. | The apply-results read got a terminal HTTP status (`params.status`); the outcome is unknown. | | `CONFIRMATION_MALFORMED` | `post_send` | - | Transaction confirmation returned a malformed body. | A 200 apply result that is not a usable body; the outcome is unknown. | | `CONFIRMATION_KEY_MISMATCH` | `post_send` | - | Apply result key did not match the requested key. | A 200 apply result for another key; the outcome is unknown. | | `NO_SIGNER` | `pre_send` | - | This method requires a signer. Please provide a signer to the GSwap constructor. | A write on a client built without a signer. | | `NO_WALLET_ADDRESS` | `post_send` | - | Cannot confirm this write: no walletAddress was provided to the GSwap constructor, so the resulting position cannot be looked up to confirm it landed on chain. | Confirming a liquidity write without a configured walletAddress. | | `NO_POOL_AVAILABLE` | `post_send` | `tokenIn`:string, `tokenOut`:string, `fee`:string | No pool is available for \{tokenIn\}/\{tokenOut\} (fee tier \{fee\}). | A quote the backend answered with 404 / "no pools" / "pool does not exist": the pair has no market. `notFound` is true. A token with no trading symbol is `UNKNOWN_TOKEN` instead. | | `INSUFFICIENT_LIQUIDITY` | `post_send` | `tokenIn`:string, `tokenOut`:string, `fee`:string | The selected pool has insufficient liquidity for \{tokenIn\}/\{tokenOut\} (fee tier \{fee\}). | A quote the backend answered with 400 "Insufficient liquidity". `notFound` is false. | | `UNKNOWN_TOKEN` | `pre_send` | `token`:string | Token \{token\} is not registered on the DEX contract: it has no trading symbol. | A token the symbol registry does not know: a symbol lookup, or a quote the backend refused with `Token has no trading symbol on the new DEX contract` (`params.token` is the token as the caller gave it; the answer is `error.status` / `error.body`). `notFound` is true. | | `SYMBOL_NOT_FOUND` | `pre_send` | `token`:string | Token \{token\} could not be resolved to a trading symbol. | A resolver that returned no trading symbol. | | `STREAM_API_KEY_UNUSABLE` | `pre_send` | - | GdexStreamConfig.apiKey needs a non-empty key and an explicit webSocketImpl that accepts upgrade headers as its third argument (the "ws" package, or React Native). A browser WebSocket cannot send x-api-key, so the key would be silently dropped. | `GdexStreamConfig.apiKey` without a usable `webSocketImpl`. | | `STREAM_WEBSOCKET_UNAVAILABLE` | `pre_send` | - | GdexStreamService requires a standards-compatible WebSocket constructor. Node.js versions before 22 must provide one with config.webSocketImpl (for example, from the "ws" package). | No WebSocket constructor for the realtime stream. | | `STREAM_NOT_CONNECTED` | `pre_send` | - | GDEX stream is not connected. Call connect() first. | A stream request before `connect()`. | | `STREAM_DISCONNECTED` | `in_flight` | - | GDEX stream disconnected. | `disconnect()` while requests were pending. | | `STREAM_REQUEST_TIMEOUT` | `in_flight` | `method`:string, `timeoutMs`:number | GDEX request "\{method\}" timed out after \{timeoutMs\} ms. | A stream request got no answer in time. | | `STREAM_CONNECT_FAILED` | `in_flight` | `url`:string | Failed to connect to GDEX stream at \{url\}. | The socket errored before opening. | | `STREAM_CLOSED_BEFORE_CONNECT` | `in_flight` | `closeCode`:number | GDEX stream closed before connecting (code \{closeCode\}). | The socket closed before opening. | | `STREAM_CONNECTION_CLOSED` | `in_flight` | `closeCode`:number | GDEX stream connection closed (code \{closeCode\}). | The socket closed while requests were pending. | | `TOKEN_RESOLUTION_FAILED` | `pre_send` | `token`:string | Token \{token\} could not be looked up; nothing was sent. | A token resolver, or the HTTP stack it reads the registry through, threw something that is not an SDK error while a swap or position write was being built. `params.token` names the token (a pair is `a/b`); the original error is `cause`. `not_sent`: Retry is safe. | | `MISSING_WALLET_ADDRESS` | `pre_send` | - | Invalid wallet address: No wallet address provided. Either provide a wallet address to the function you are calling, or set one when instantiating GSwapSDK. | No wallet address was given where one is required. | | `NON_CANONICAL_PAIR` | `pre_send` | `token0`:string, `token1`:string | The pair \{token0\}/\{token1\} is not in canonical order: token0 must sort before token1. | A pair not in canonical order (token0 must sort before token1) was about to be signed. | | `UNORDERABLE_SYMBOLS` | `pre_send` | `received`:string | Unable to order trading symbols: expected a pair of symbols, got \{received\}. | A pair-ordering helper got something that is not a pair. | | `INVALID_TOKEN_CLASS_KEY` | `pre_send` | `tokenClassKey`:string | Invalid token class key "\{tokenClassKey\}": expected a collection followed by category, type and additionalKey | A token class key string that is not collection/category/type/additionalKey. | | `INCOMPLETE_TOKEN_CLASS_KEY` | `pre_send` | `compositeKey`:string, `part`:string | Token class key "\{compositeKey\}" is missing \{part\}. | A class key object with an empty part; `params.part` names it. | | `INVALID_TRADING_SYMBOL` | `pre_send` | `symbol`:string | Invalid trading symbol "\{symbol\}": must be 1-32 ASCII letters and digits and not a reserved word (Token, Unit, none). | A proposed symbol that is not 1-32 ASCII letters/digits or is reserved. | | `NO_VALID_TRADING_SYMBOL` | `pre_send` | `classKey`:string, `displaySymbol`:string | No valid trading symbol for token class \{classKey\}: "\{displaySymbol\}" is not an acceptable symbol and none is registered | No registered symbol and the display symbol is not proposable. | | `TOKEN_SYMBOL_NOT_REGISTERED` | `pre_send` | `token`:string | Token \{token\} is not registered in the trading-symbol registry yet; pass token0Symbol/token1Symbol (the token class symbol) to propose one. A symbol cannot be derived from a class key. | CreatePool on an unregistered token without a supplied symbol. | | `SYMBOL_DISAGREES_WITH_REGISTRY` | `pre_send` | `token`:string, `suppliedSymbol`:string, `registeredSymbol`:string | Supplied symbol \{suppliedSymbol\} for \{token\} disagrees with the registered trading symbol \{registeredSymbol\}. | A supplied symbol that differs from the registered one. | | `CREATE_POOL_NEEDS_CLASS_KEY` | `pre_send` | `token`:string | createPool needs each token as a class key; \{token\} is a bare trading symbol, which does not carry one. | CreatePool given a bare symbol instead of a class key. | | `AMOUNT_IS_JS_NUMBER` | `pre_send` | `field`:string | Invalid \{field\}: use a decimal string or BigNumber, not a JavaScript number | A JavaScript number was given where a decimal string is required; `params.field` names it. | | `AMOUNT_NOT_FINITE` | `pre_send` | `field`:string, `value`:string | Invalid \{field\}: must be a finite number (got \{value\}) | A non-finite or unparseable amount; `params.field`, `params.value`. | | `AMOUNT_NOT_POSITIVE` | `pre_send` | `field`:string, `value`:string | Invalid \{field\}: must be positive (got \{value\}) | A zero amount where a positive one is required. | | `AMOUNT_NEGATIVE` | `pre_send` | `field`:string, `value`:string | Invalid \{field\}: must not be negative (got \{value\}) | A negative amount. | | `PRICE_VALUES_IS_JS_NUMBER` | `pre_send` | - | Invalid price values: use decimal strings or BigNumber values, not JavaScript numbers | `validatePriceValues` got JavaScript numbers. | | `INVALID_PRICE_VALUES` | `pre_send` | `spotPrice`:string, `lowerPrice`:string, `upperPrice`:string | Invalid price values: all prices must be finite and positive (spot \{spotPrice\}, lower \{lowerPrice\}, upper \{upperPrice\}) | A price that is not finite and positive. | | `INVALID_PRICE_RANGE` | `pre_send` | `lowerPrice`:string, `upperPrice`:string | Invalid price range: lower price \{lowerPrice\} must be less than or equal to upper price \{upperPrice\} | lowerPrice above upperPrice. | | `INVALID_PRICE_BOUNDS` | `pre_send` | `minPrice`:string, `maxPrice`:string | Price bounds must be finite and positive (minPrice \{minPrice\}, maxPrice \{maxPrice\}). | `addLiquidityByPrice` min/max not finite and positive. | | `PRICE_BOUNDS_ORDER` | `pre_send` | `minPrice`:string, `maxPrice`:string | minPrice \{minPrice\} must be less than or equal to maxPrice \{maxPrice\}. | `addLiquidityByPrice` minPrice above maxPrice. | | `INVALID_STARTING_PRICE` | `pre_send` | `value`:string | Starting price must be finite and positive (got \{value\}). | A CreatePool starting price that is not finite and positive. | | `INVALID_SQRT_PRICE` | `pre_send` | `sqrtPrice`:string | Cannot invert a non-positive sqrt price (\{sqrtPrice\}). | A non-positive sqrt price could not be inverted. | | `INVALID_TOKEN_DECIMALS` | `pre_send` | `field`:string, `value`:number | Invalid \{field\}: must be a non-negative integer (got \{value\}) | Token decimals that are not a non-negative integer. | | `TICKS_NOT_INTEGERS` | `pre_send` | `tickLower`:number, `tickUpper`:number | Invalid tick values: ticks must be integers (got \{tickLower\} and \{tickUpper\}) | Tick bounds that are not integers. | | `INVALID_TICK_RANGE` | `pre_send` | `tickLower`:number, `tickUpper`:number | Invalid tick range: tickLower \{tickLower\} must be less than tickUpper \{tickUpper\} | tickLower not below tickUpper. | | `TICKS_OUT_OF_BOUNDS` | `pre_send` | `tickLower`:number, `tickUpper`:number, `minTick`:number, `maxTick`:number | Invalid tick range: ticks \{tickLower\} and \{tickUpper\} must be between \{minTick\} and \{maxTick\} | Ticks outside the chain's global min/max. | | `TICKS_NOT_ALIGNED` | `pre_send` | `tickLower`:number, `tickUpper`:number, `spacing`:number | Ticks \{tickLower\} and \{tickUpper\} must be aligned to spacing \{spacing\}. | Ticks not aligned to the fee tier's spacing. | | `INVALID_TICK_SPACING` | `pre_send` | `value`:number | Invalid tick spacing: must be a positive integer (got \{value\}) | A tick spacing that is not a positive integer. | | `INVALID_FEE` | `pre_send` | `field`:string, `value`:number, `allowed`:string | Invalid \{field\}: \{value\} is not a supported fee tier; must be one of \{allowed\}. | A fee tier that is not 0, 500, 3000 or 10000; `params.field` names the option. | | `EXACT_AMOUNT_REQUIRED` | `pre_send` | `field`:string | \{field\} is required for this swap. | A swap request without `exactIn` / `exactOut`. | | `EXACTLY_ONE_OF_REQUIRED` | `pre_send` | `first`:string, `second`:string | Provide exactly one of \{first\} or \{second\}. | Neither or both of two mutually exclusive fields. | | `AT_MOST_ONE_OF_ALLOWED` | `pre_send` | `first`:string, `second`:string | Provide at most one of \{first\} or \{second\}. | Both of two mutually exclusive optional fields. | | `POOL_MISMATCH` | `pre_send` | `tokenIn`:string, `tokenOut`:string, `poolToken0`:string, `poolToken1`:string | tokenIn \{tokenIn\} and tokenOut \{tokenOut\} must be the two tokens of the pinned pool \{poolToken0\}/\{poolToken1\}. | tokenIn/tokenOut are not the two tokens of the pinned pool. | | `INVALID_DTO` | `pre_send` | `method`:string, `field`:string, `expected`:string | \{method\} DTO field \{field\} is invalid (expected \{expected\}). | A DTO handed to `submit*` has a field of the wrong shape; `params.field`, `params.expected`. | | `DTO_NOT_CANONICAL` | `pre_send` | `method`:string | The \{method\} DTO is not in the form the SDK builders produce; build it with the matching build function and submit that. | A DTO handed to `submit*` is not exactly what the builder produces. | | `SEARCH_TOO_LONG` | `pre_send` | `length`:number, `maxLength`:number | search must be at most \{maxLength\} characters (got \{length\}). | Pool list `search` over 64 characters. | | `INVALID_SORT_BY` | `pre_send` | `value`:string, `allowed`:string | sortBy "\{value\}" is not allowed; it must be one of \{allowed\}. | Pool list `sortBy` not allowed. | | `INVALID_SORT_ORDER` | `pre_send` | `value`:string | sortOrder "\{value\}" is not allowed; it must be asc or desc. | Pool list `sortOrder` not asc/desc. | | `INVALID_PAGE` | `pre_send` | `value`:number | page must be an integer of at least 1 (got \{value\}). | `page` not an integer of at least 1. | | `INVALID_LIMIT` | `pre_send` | `value`:number, `min`:number, `max`:number | limit must be an integer from \{min\} to \{max\} (got \{value\}). | `limit` outside `params.min`..`params.max`. | | `INVALID_MARKET_TOKEN` | `pre_send` | `token`:string | A market read names a token by a symbol or class key of 1 to 120 letters, digits and . _ $ + / : \| - characters (got "\{token\}"). | A `market` token string outside the backend asset-id alphabet or over 120 characters. | | `INVALID_TIMEFRAME` | `pre_send` | `value`:string, `allowed`:string | timeframe "\{value\}" is not allowed; it must be one of \{allowed\}. | `market.getPriceSeries` timeframe not 1D / 1W / 1M / 1Y / ALL. | | `INVALID_SEASON_ID` | `pre_send` | `value`:string | seasonId must be an integer of at least 1 (got \{value\}). | `leaderboard.getLeaderboard` seasonId not an integer of at least 1. | | `INVALID_POLL_INTERVAL` | `pre_send` | `value`:string | intervalMs must be a finite number of milliseconds of at least 1 (got \{value\}). | `pools.watchNewPools` intervalMs not a finite number of at least 1. | {/* error-catalog:end */} --- # Signing and Identity The SDK signs the unsigned DTO exactly as it will be posted to the Chain Gateway. Each signer has a default scheme, and two of them have an opt-in second one. The signers and the signing primitives are exported by `@gala-chain/gala-core-sdk` (since 2.0.0; this package does not re-export them): ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; import { BrowserWalletSigner, GalaWalletSigner, PrivateKeySigner } from '@gala-chain/gala-core-sdk'; ``` | Signer | Signature | Account/address input | | -------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------- | | `PrivateKeySigner` | GalaChain native signature (`signNative`) | Recovered from the private key | | `GalaWalletSigner` on current wallets | `gala_signChainDto` with `native` | `0x` + 40 hex, `eth\|` + 40 hex, `client\|` + 24 hex, or the bare 24 hex | | `GalaWalletSigner` `{ scheme: 'personal-sign' }` (opt-in, needs a wallet with the fix) | Personal-sign via `gala_signChainDto` | The same account | | `BrowserWalletSigner` | EIP-1193 `personal_sign` with the SDK prefix | Selected `0x` + 40 hex Ethereum account | | `BrowserWalletSigner` `{ scheme: 'eip712' }` (opt-in) | `eth_signTypedData_v4` for the EIP-712-capable methods | Selected `0x` + 40 hex Ethereum account; resolves a registered `client\|` alias | Native signatures have no prefix, EIP-712 domain, or typed-data envelope. Personal-sign signatures cover the bare serialized DTO and send the EIP-191 header for it as the DTO's `prefix`; neither involves an EIP-712 domain. `BrowserWalletSigner` defaults to `personal_sign`, which resolves the bare `eth|<40 hex>` identity. `{ scheme: 'eip712' }` signs typed data instead, for the methods in `EIP712_CAPABLE_METHODS` (`RequestTrade`, `AddLiquidity`, `RemoveLiquidity`, `CollectPositionFees`), and so resolves a registered `client|` alias; `CreatePool` and any other method still use `personal_sign` in that mode. The domain `chainId` is read from the wallet with `eth_chainId` on every signature (a malformed answer is `INVALID_CHAIN_ID`). Use it only when the app must act as the `client|` identity of the connected account. ## Native private-key signing ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(process.env.GALACHAIN_PRIVATE_KEY!), walletAddress: '0x0123456789012345678901234567890123456789', }); ``` The native signature identifies the key to the chain. `walletAddress`, when provided, is the selected Ethereum account used for gateway attribution; the SDK does not add `signerAddress` or `signerPublicKey` hints to the DTO. ## Gala Wallet version note Current Gala Wallet builds support the four-parameter call: ```text gala_signChainDto([serialize(dto), address, methodName, 'native']) ``` There is no automatic fallback: a wallet that rejects `native` surfaces its error. Passing `{ scheme: 'personal-sign' }` explicitly uses the three-argument `gala_signChainDto` contract without the final `native` parameter: `[serialize({...dto, prefix}), address, methodName]`, resolving the bare `eth|<40 hex>` identity. This **requires a Gala Wallet build that signs the bare serialized DTO** (the string without the `prefix` field; the wallet applies the EIP-191 header itself). Wallet builds that predate that fix hash the string with the `prefix` field still inside, so the signature recovers to an address nobody holds. Nothing in the SDK selects this scheme on its own. `new GalaWalletSigner(account, { selectAddress })` accepts the account as `0x` + 40 hex, `eth|` + 40 hex (normalized to `0x...`), `client|` + 24 hex, or the bare 24 hex a direct `client|` login keeps. `selectAddress` is the identity (`client|...` or `eth|...`) the wallet is switched to with `window.gala.setAddress` before each signature, when the wallet offers it. The wallet's 130-hex answer is passed through bare or `0x`-prefixed; anything else is `INVALID_SIGNATURE`. A page without `window.gala` gets `GALA_WALLET_NOT_AVAILABLE`. ## Browser wallets Pass an EIP-1193 provider and the selected `0x` Ethereum account to `BrowserWalletSigner`. By default the signer requests `personal_sign` (see the `eip712` option above) and sends `{ ...dto, prefix, signature }` to the gateway. To use an ethers `BrowserProvider` as the provider, wrap it with `eip1193ProviderFromEthers(provider)` (also from `@gala-chain/gala-core-sdk`). A wallet or app that holds the key itself signs with the core package's primitives (`signNative`, `signChainDtoNative`, `signChainDtoPersonalSign`, `signTypedDataPayload`, `createLazyPrivateKeySigner`); see "Signing primitives for wallets" in [App and Wallet Integration](/gswap-sdk/next/other/app-integration.md). The primitives are pinned byte for byte to the Gala Wallet's signing code by golden-vector fixtures (the fixtures and their suite live in `packages/gala-core-sdk/tests`). For v2 DEX operations, `X-Wallet-Address` is only an attribution hint; it does not cause a `SIGNER_MISMATCH` check because these operations have no `signerField`. `SIGNER_MISMATCH` applies to contract operations that explicitly name an actor. A mismatched signing scheme can still produce `SIGNATURE_INVALID`. --- # App and Wallet Integration Everything in this guide is platform neutral: it uses only `fetch` (or an injected `httpRequestor`), `globalThis.crypto`, timers, and adapters you pass in. No Node, DOM, or `chrome.*` API is touched, so the same code runs in a browser page, a Manifest V3 service worker, Node.js, and React Native. | Platform piece | Adapter you provide | | ------------------------ | ------------------------------------------------------------------------------------------------ | | HTTP | `httpRequestor` (default: global `fetch`) | | Signing | a `GalaChainSigner` (`PrivateKeySigner`, `GalaWalletSigner`, `BrowserWalletSigner`, or your own), imported from `@gala-chain/gala-core-sdk` | | Pending-swap persistence | a `StorageAdapter` | | Realtime stream | a `webSocketImpl` constructor | ## Write keys Every write carries a fresh `uniqueKey` of the form ``. The prefix defaults to `galaswap-operation-` (what the Gala Wallet and the gSwap web app send) and is configurable with `new GSwap({ uniqueKeyPrefix })`. It must be at most 92 characters of `A-Z a-z 0-9 . _ : -`, so the key can always be read back from apply-results. To know the key before signing (to remember it, to show it, to retry the same attempt after a lost response), pass `uniqueKey` to any write: the `options` of `swap` / `swapShadow` / `buildSwap`, or the `uniqueKey` field of the position and pool methods. It must match `^[A-Za-z0-9._:-]{1,128}$`; reuse a key only to retry the very same attempt. The key's UUID is minted by `@gala-chain/gala-core-sdk` from `crypto.getRandomValues` (never `crypto.randomUUID`, which React Native/Hermes lacks). On a platform without `getRandomValues` the mint throws `CSPRNG_UNAVAILABLE`; on React Native install `react-native-get-random-values`. The helpers `createUniqueKey`, `assertUniqueKey`, `resolveUniqueKeyPrefix`, `isValidUniqueKey` and `DEFAULT_UNIQUE_KEY_PREFIX` are exported by core. ## Build, show, then sign: the pure DTO builders `buildRequestTradeDto`, `buildAddLiquidityDto`, `buildRemoveLiquidityDto`, `buildCollectPositionFeesDto` and `buildCreatePoolDto` are the only code that builds a v2 write DTO (the `Swaps` and `Positions` services call them). They take canonical inputs (`token0 < token1`, ticks and prices in that orientation; a reversed pair is refused as `NON_CANONICAL_PAIR`), validate, write decimals as `BigNumber#toFixed()` and fix the key order. Use them to put the exact DTO in an approval popup before it is signed: ```typescript import { swapRouteFromQuote } from '@gala-chain/gswap-sdk'; const route = swapRouteFromQuote(quote); // tokenIn, tokenOut, fee and pool, verbatim from the quote const dto = await gSwap.swaps.buildSwap( route.tokenIn, route.tokenOut, route.fee, { exactIn: '100', amountOutMinimum: '14' }, { pool: route.pool, uniqueKey }, ); showApproval(dto); const submitted = await gSwap.swaps.submitSwap(dto); // signs and submits exactly `dto` ``` `submitSwap`, `submitSwapShadow`, `submitAddLiquidity`, `submitRemoveLiquidity`, `submitCollectPositionFees` and `submitCreatePool` refuse any DTO that is not exactly the builder's output (`assertCanonicalV2Dto`: no signature, canonical decimals, builder key order), so what was shown is what is signed. A position write built this way keeps its own `confirm()`. ## Matching an app's own requests An app that already talks to the backend with its own HTTP stack can move to the SDK without changing what goes on the wire. Every option is on an object the app constructs (`ChainGateway`, `Quoting`, `Pools`, `Positions`), and on `GSwap`: - `wire: { queryEncoding: 'readable' }` keeps `$ | : ,` unescaped in a query (`token0=GALA$Unit$none$none`); the default `'standard'` is `URLSearchParams`. Anything that would change a query's meaning (`& = # % +`) is always escaped. `wire.userAgent` is a string, or `false` for none; `wire.headers` adds headers (for example axios' `Accept`). They apply to every request: reads, the `submit` / `submitShadow` POSTs and the apply-results polls. A GET never sends `Content-Type`; a POST sends `Content-Type: application/json` unless `wire.headers` sets one, and always ends with `X-Wallet-Address` (and `X-Shadow: true` for a shadow write), which `wire.headers` cannot replace. - A queued RequestTrade acknowledgement must echo the signed `uniqueKey`; without it (`MISSING_UNIQUE_KEY`) or with another (`UNIQUE_KEY_MISMATCH`) `submit` throws that code. A returned `SubmittedTransaction` has `mode`, `status` (`'queued'` or `'executed'`), `uniqueKey` and `envelope`; `isSubmitQueued`, `isSubmitExecuted`, `isSubmitRejected` and `classifySubmitEnvelope` classify a raw envelope. - `eip1193ProviderFromEthers(browserProvider)` lets `BrowserWalletSigner` sign through an ethers `BrowserProvider`; `httpRequestorFromAxios(instance, { rejectOnHttpError })` sends the SDK's requests through an axios instance. Both, like the signers, are imported from `@gala-chain/gala-core-sdk`. - `symbolResolution: 'canonical'` on `GSwap` (or `new CanonicalSymbols()` for a service built by hand) makes no `GET /v2/trade/symbols`: writes take the canonical trading symbols the caller already holds from a quote, estimate or position, and reads send tokens (composite keys included) and ticks as given, leaving the pair's orientation to the backend. - `chainCallTimeoutMs: Infinity` arms no timer, for an app whose HTTP stack owns request lifetimes. - `new ChainGateway({ isTransportFailure, answerOfRejection })` teach the SDK what your requestor's rejections mean: `isTransportFailure` names a rejection that proves no answer arrived (a write is then `SUBMISSION_OUTCOME_UNKNOWN`; `isFetchTransportFailure`, from `@gala-chain/gala-core-sdk`, fits a `fetch` wrapper), and `answerOfRejection` maps a rejection that IS an HTTP answer (an axios interceptor, a version wall) to `{ status, body, headers? }`, so the write is classified exactly as if that answer had been resolved. See [Error Handling](/gswap-sdk/next/other/error-handling.md). - `onInvalidEntry` receives every row of a pool, symbol or position list that was skipped as unusable (`{ source, index, entry, reason }`); one bad row never fails the list. - `GalaWalletSigner(account, { selectAddress })` accepts `0x`+40 hex, `eth|`+40 hex, `client|`+24 hex or the bare 24 hex, passes a 130-hex signature through bare or `0x`-prefixed, and calls `window.gala.setAddress(selectAddress)` before each signature. - Failures carry a stable `error.code` and flat `error.params` that an app localizes (see [Error Handling](/gswap-sdk/next/other/error-handling.md)), plus `error.status`, `error.body` (parsed JSON), `error.bodyText` (a non-JSON answer, never in `message`) and, for a missing market, `error.notFound` (HTTP 404, `NO_POOL_AVAILABLE`, `UNKNOWN_TOKEN`). `error.message` is English for logs: never show it, never match on it. ## Confirming a swap: `confirmAppliedTrade` `SubmittedTransaction.confirm()` and `swaps.confirmSwap()` use this function; call it directly when you only hold a stored `uniqueKey` (a resumed swap): ```typescript import { AppliedTradeError, confirmAppliedTrade } from '@gala-chain/gswap-sdk'; const controller = new AbortController(); try { const applied = await confirmAppliedTrade( { dexBackendBaseUrl: 'https://dex-backend-prod1.defi.gala.com', httpRequestor: galaFetch }, { uniqueKey, requestTransactionId }, { initialDelayMs: 0, timeoutMs: 60_000, signal: controller.signal }, ); } catch (error) { if (!(error instanceof AppliedTradeError)) throw error; switch (error.code) { case 'CONFIRMATION_ABORTED': // the signal aborted; the outcome is unknown case 'CONFIRMATION_TIMEOUT': // the trade may still apply; confirm again later, never resubmit case 'CONFIRMATION_FAILED': // the read got a terminal HTTP status; the outcome is unknown case 'CONFIRMATION_MALFORMED': // the answer was not an apply result; the outcome is unknown case 'CONFIRMATION_KEY_MISMATCH': // the answer was for another key; the outcome is unknown break; case 'CHAIN_REJECTED': // the chain refused the trade; params.errorKey is its ErrorKey console.log(error.params.errorKey); break; default: // INVALID_UNIQUE_KEY: nothing was read break; } } ``` It polls `GET /v1/chain/apply-results/{uniqueKey}?channel=asset&contract=dex-contract` after `initialDelayMs` (default 3 s), retrying 404, 429, 500, 502, 503, 504 and transport errors with jittered backoff (`Retry-After` honored as seconds or an HTTP date) until `timeoutMs`. Any other status is terminal (`CONFIRMATION_FAILED` with `params.status`). `AppliedTradeError` extends `GSwapSDKError`; its `uniqueKey` field is always set and, where known, so are `requestTransactionId`, `applyTransactionId`, `blockNumber`, `status`, `body`, `url` and the last transport `cause`. `confirmationStateOf(error)` (`'aborted'`, `'timeout'`, `'failed'`) and `isConfirmationAborted` / `isConfirmationTimeout` read the state without matching codes; every one of them is an unknown outcome. ## Remembering pending swaps: `PendingSwapStore` Persist the `uniqueKey` of every accepted swap so its outcome can be confirmed after the UI that submitted it is gone. The store persists structured values through a `StorageAdapter` (`get(key)` / `set(key, value)`, both async): ```typescript import { PendingSwapStore, confirmAppliedTrade, storageAdapterFromChromeStorage, webStorageAdapter, } from '@gala-chain/gswap-sdk'; // Chrome extension: the value is stored as is, under the key `pendingSwaps.v1`. Pass a function // to look the area up at each call, so a module imported where `chrome` is absent still loads. const store = new PendingSwapStore(storageAdapterFromChromeStorage(() => chrome.storage.local)); // A web app that keeps a JSON string in localStorage, with its own key, flag name and order. const webStore = new PendingSwapStore( webStorageAdapter(() => localStorage), { storageKey: 'galaswap:pending-swaps:v1', darkFlagField: 'shadow', insertAt: 'start', listOrder: 'newest-first', }, ); await store.remember({ uniqueKey, requestTransactionId, wallet, token0Symbol: 'GALA', token1Symbol: 'GUSDC', isDarkSwap: false, createdAt: Date.now(), }); for (const swap of await store.list(wallet)) { await confirmAppliedTrade(client, swap, { initialDelayMs: 0 }); // then store.forget(swap.uniqueKey) } ``` Persistence is best effort and never throws, operations of one store are serialized, and entries expire after seven days (`list` prunes them). The defaults are the Chrome extension's shape: key `pendingSwaps.v1`, `isDarkSwap`, new entries at the end, `list` in stored order; the options above reproduce the web app's. A `get` that rejects is treated as "storage unavailable" and makes `remember` a no-op, so an adapter must return corrupt data as a value instead of rejecting; `webStorageAdapter` does (a missing key is `undefined`, corrupt JSON comes back as the raw string, a blocked or full storage rejects) and `storageAdapterFromChromeStorage` stores the structured value as is. Both are structural (`WebStorageLike`, `ChromeStorageAreaLike`), so a React Native key-value store with `getItem` / `setItem` fits `webStorageAdapter`. Two stores over the same storage (popup and service worker) are not coordinated. `new PendingSwapStore(adapter, { onPrune })` hears every entry the store drops, with the reason (`PENDING_SWAP_PRUNE_REASONS`: `expired`, `invalid_unique_key` for a key `confirmAppliedTrade` would always refuse with `INVALID_UNIQUE_KEY`, `chain_rejected`, `unconfirmable`); `remember` refuses to save an invalid key. `onPrune` is diagnostics only: what it does or throws never changes the store. ### Resolving a swap after a failed confirmation: `pendingSwapFateFor` and `settle` When `confirmAppliedTrade` fails, the SDK says what to do with the stored swap, so an app keeps no table of its own: `pendingSwapFateFor(error)` is `'forget'` (the chain rejected it: drop it and tell the user), `'forget_quietly'` (the key is refused, so it can never be confirmed: drop it, claim nothing) or `'keep'` (every other outcome, and anything the SDK cannot judge: it may have been applied, look again later). `store.settle(uniqueKey, error)` applies it and returns the fate: ```typescript continue for (const swap of await store.list(wallet)) { try { await confirmAppliedTrade(client, swap, { initialDelayMs: 0 }); await store.forget(swap.uniqueKey); } catch (error) { if ((await store.settle(swap.uniqueKey, error)) === 'forget') tellTheUserItFailed(swap); } } ``` `onPrune` hears `chain_rejected` (forget) and `unconfirmable` (forget_quietly) with the swap; `keep` changes nothing. `pendingSwapFateOfOutcome(outcome)` is the same table for an app that already holds the outcome. `pendingSwapFateFor` also accepts a plain-object failure view of an SDK error. ### Parsing a token class key without a `try`: `tryParseTokenClassKey` (`tryParseTokenClassKey` and `tryParseCompositeKey` are imported from `@gala-chain/gala-core-sdk`.) `tryParseTokenClassKey(value)` is `parseTokenClassKey` that returns `undefined` instead of throwing, for untrusted input (a stored token, a URL parameter, a wallet row); it validates an object (four non-empty strings) instead of copying it. `tryParseCompositeKey(value)` reads ONLY the `$` form (`Collection$Category$Type$AdditionalKey`): a `|` stays part of a segment there, whereas `parseTokenClassKey` and `tryParseTokenClassKey` switch to the pipe form when the key contains one. Both read from the right, so a collection that contains `$` (`$GMUSIC`) stays whole. ## Fee quotes: `DexFees` A wallet asks the backend what a DEX operation will cost by signing a DryRun wrapper (`{ callerPublicKey, method, dto, uniqueKey }`, the inner DTO unsigned) and posting it to `/wallet/connect/galachain/api/{channel}/{contract}/{method}/fee`: ```typescript import { DexFees, isDexFeeMethod } from '@gala-chain/gswap-sdk'; import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; const fees = new DexFees( { dexBackendBaseUrl, httpRequestor: galaFetch }, new PrivateKeySigner(key), ); if (isDexFeeMethod(method)) { // The EIP-712 approval message can be passed as is: the signing envelope is stripped. const quote = await fees.quote(publicKey, method, message, { contract: 'dex-contract' }); const feeInGala = quote?.fees[0]?.feeInGala; // null when the backend was unreachable } ``` The client never invents a fee: the backend serves `source: 'default'` when the chain cannot price the operation. The one local default mirrors the wallet: a `dex-contract` quote answered `403` or `404` resolves a zero default. Transport failures resolve `null`; only a signer error (for example a locked wallet) is thrown. `gSwap.fees` is the same service bound to the client's signer. ## Dark (shadow) swaps ```typescript const outcome = await gSwap.swaps.swapShadow('GALA', 'GUSDC', 3000, { exactIn: '100' }); if (outcome.ok) { await gSwap.swaps.confirmSwap(outcome.queued.uniqueKey); // `queued` is always there on a success } else { // 'unavailable' (retryable), 'disabled', 'rejected' (outcome.message), 'unknown' } ``` Shadow Swaps are enabled in every environment, so `disabled` does not mean the feature is off. It is the answer to a shadow request the route refused with a 400 (`SHADOW_UNSUPPORTED_TYPE`, a shadow request for a method that is not a swap, or any other 400 such as a validation failure): the request will not succeed as sent and is not retryable. The kinds are `SHADOW_FAILURE_KINDS`; the body codes behind them are `SHADOW_SUBMIT_CODES`. A successful `ShadowSubmitOutcome` always carries `queued` (a RequestTrade answer that does not queue the signed key throws `SHADOW_NOT_QUEUED` instead), so there is no `undefined` branch to write. `readShadowSubmitOutcome` for another method may also return a `ShadowSyncSuccess` (a synchronous liquidity write: nothing queued, `queued` absent). `swapShadow` signs the same `RequestTrade` and posts it with `X-Wallet-Address` and `X-Shadow: true`, so the backend marks it private before it reaches the contract (a `walletAddress` is required). Unlike `swap`, every HTTP status resolves, because shadow failures are classified from the status together with the body's `code`. For other methods use `gateway.submitShadow(method, signedDto)` and `readShadowSubmitOutcome(method, signedDto, result)`. Never fall back to a public swap when a shadow swap fails. ## Realtime stream and authentication `gSwap.stream` (or `new GdexStreamService({ url, webSocketImpl })`) speaks JSON-RPC 2.0 over the `gdex.jsonrpc.v1` WebSocket subprotocol, with automatic reconnect and resubscribe (see the [realtime stream guide](/gswap-sdk/next/tutorial/realtime-stream.md)). It uses the platform `WebSocket` unless you inject a constructor. **Authentication.** Public data needs none. The server serves a privileged view (shadow swaps with the wallet unredacted) only to connections whose upgrade request carries a valid `x-api-key` header; a missing or wrong key is indistinguishable from no key. The server reads no other credential (not the query string, not a message), and a browser `WebSocket` cannot set request headers. So: - **Browsers** (and anything using the global `WebSocket`, including Node 22's): public view only. Do not try to smuggle a key through the URL. - **Node.js and React Native**: pass the constructor that accepts headers as its third argument and the key: ```typescript import { GdexStreamService } from '@gala-chain/gswap-sdk'; import { WebSocket } from 'ws'; const stream = new GdexStreamService({ webSocketImpl: WebSocket, apiKey: process.env.GDEX_API_KEY, }); // or: new GSwap({ webSocketImpl: WebSocket, streamApiKey: process.env.GDEX_API_KEY }) ``` `apiKey` requires an explicit `webSocketImpl` (the constructor throws otherwise), so a key is never silently dropped by a platform that ignores headers. Use it from trusted server-side code: a key shipped inside an app bundle is not a secret. ## Signing primitives for wallets A wallet that holds the key itself (the Gala Wallet extension) signs with these instead of carrying its own crypto. They are exported by `@gala-chain/gala-core-sdk` (since 2.0.0 this package no longer re-exports them). Keys are `0x`-optional hex, base64 or 32 raw bytes; every call normalizes a private copy and zeroes it before returning. ```typescript import { createLazyPrivateKeySigner, resolvePersonalSignChainDtoPayload, serialize, signChainDtoNative, signChainDtoPersonalSign, signTypedDataPayload, stripEip712DomainType, } from '@gala-chain/gala-core-sdk'; // Native: keccak256 of the exact string the user reviewed. const native = signChainDtoNative(key, serialize(dto)); // Personal-sign (`gala_signChainDto`): refuse BEFORE signing, then sign what was reviewed. resolvePersonalSignChainDtoPayload(data); // throws GalaSDKError PERSONAL_SIGN_NOT_JSON, ... const personal = signChainDtoPersonalSign(key, data); // A dApp's typed-data approval (no ethers needed); resolves to `0x` + r + s + v. const typed = await signTypedDataPayload(key, { domain, types: stripEip712DomainType(types), message, }); // A signer for GSwap that never keeps the key: it is fetched per signature and zeroed. const signer = createLazyPrivateKeySigner(() => readSessionKey(), { expectedAddress: account.address, // refuse if the key slot now belongs to another account }); ``` `resolvePersonalSignChainDtoPayload` fails closed on malformed JSON, non-objects, a `prefix` that is not an EIP-191 "Ethereum Signed Message" header, signing-envelope fields (`signature`, `multisig`, `trace`, `types`, `domain`, `stringsInstructions`) and any string that is not already the canonical serialization of what it parses to. The personal-sign payload it returns is `{ prefix, message }`: the dApp's own `prefix` and the DTO serialized WITHOUT it, which is what the chain recovers from. `signTypedDataPayload` infers the primary type like ethers and is stricter about coercion (see `packages/gala-core-sdk/src/utils/typed_data.ts`). A JavaScript string key cannot be wiped; pass the key as a `Uint8Array` if you can. Other exports: `signRawObject` (raw strip-signature-then-sign for transfers and bridge DTOs), `canonicalDecimalString`, `tokenClassDollarKey`, `hashTypedData`, `withPrivateKey`. ## Behavior notes for apps that wrote these helpers themselves An app that already has its own confirmation polling, fee-quote, pending-swap or requestor code will see these deliberate, user-invisible differences when it moves to the SDK modules. - **Apply-results:** a non-JSON 4xx or 5xx body (for example a proxy's HTML 502) is retried rather than failing at once with `CONFIRMATION_FAILED`. Timeout, abort and invalid-key failures are codes (`CONFIRMATION_TIMEOUT`, `CONFIRMATION_ABORTED`, `INVALID_UNIQUE_KEY`); the wording is the app's. `pollIntervalMs` has a 500 ms floor. - **Fee quotes:** a transport error, or a 426 an injected requestor throws, resolves `null` instead of propagating, so one fallback covers both. - **Pending swaps:** the defaults suit a wallet; a web app that needs another layout passes `{ storageKey, darkFlagField: 'shadow', insertAt: 'start', listOrder: 'newest-first' }`. Entries exactly seven days old are expired, `list` prunes storage, and JSON key order inside an entry is not preserved. - **Requestors:** every request goes through the injected `httpRequestor`, so base URL, interceptor headers (such as an extension version header) and credentials must come from it. For `submitShadow` the requestor must resolve every HTTP status; an axios instance that rejects 4xx and 5xx must be wrapped (or replaced by a `fetch`-based requestor) rather than used directly. - **Signing primitives** are public (see "Signing primitives for wallets"). Their error type is `GalaSDKError` (from `@gala-chain/gala-core-sdk`) with one code per refusal; `error.message` is English for logs (seed your own strings from `galaErrorTemplates`, never match on the text; `isGSwapError` and `isGalaError` both recognise it). The old-name to new-name table for code written against the 1.x exports is in [Migration](/gswap-sdk/next/other/migration-from-0x.md). --- # Tick and Price Math The SDK exports the contract's tick arithmetic, so an app does not carry its own copy. Everything on this page is exact to 60 significant digits (`decimal.js`) and, unless it says otherwise, returns `NaN` or `false` for an input it cannot use instead of throwing. ## Bounds, fee tiers and spacing ```typescript import { ALL_FEE_TIERS, GC_MAX_TICK, GC_MIN_TICK, TICK_SPACING_BY_FEE, } from '@gala-chain/gswap-sdk'; console.log(GC_MIN_TICK, GC_MAX_TICK); // -887272 887272 console.log(ALL_FEE_TIERS); // [0, 500, 3000, 10000] console.log(TICK_SPACING_BY_FEE[3000]); // 60 ``` | Fee tier | Spacing | | --- | --- | | `0` | 200 | | `500` | 10 | | `3000` | 60 | | `10000` | 200 | A position's ticks must be integers, `tickLower < tickUpper`, inside the bounds and multiples of the pool's spacing. `assertTickRange(lower, upper, fee)` checks all of that and throws a coded error (`TICKS_NOT_INTEGERS`, `INVALID_TICK_RANGE`, `TICKS_OUT_OF_BOUNDS`, `TICKS_NOT_ALIGNED`, `INVALID_FEE`). ## Ticks and prices ```typescript import { tickFromPrice, tickToPrice, tickToSqrtPrice, sqrtPriceToTick } from '@gala-chain/gswap-sdk'; const price = tickToPrice(6000); // BigNumber: 1.0001 ** 6000 (token1 per token0) const display = price.toNumber(); const floor = tickFromPrice('0.5'); // the greatest tick whose price is no greater than 0.5 const snapped = tickFromPrice('0.5', { rounding: 'nearest' }); // what a price input wants const sqrt = tickToSqrtPrice(6000); const back = sqrtPriceToTick(sqrt); // 6000 ``` - `tickToPrice(tick)` is `1.0001 ** tick` as a `BigNumber`, the lower edge of the tick's price range. Use `.toNumber()` for display. - `tickFromPrice(price, options?)` floors by default, which is how the contract places a price. `{ rounding: 'nearest' }` rounds half away from zero, which is what a price field that snaps to a tick wants. The result is `NaN` for a price that is not positive and finite. - `tickToSqrtPrice(tick)` and `sqrtPriceToTick(sqrtPrice)` are the square-root forms; `sqrtPriceToTick` is the greatest tick whose square-root price is no greater than the input (`NaN` for one that is not positive and finite). - `isSqrtPriceInRange` and `isTickInRange` are below. `tickToPrice` agrees with the common float formula (`Math.exp(tick * ln 1.0001)`) to 8 significant digits for every tick and differs only in the last digits of a double, because the SDK's value is exact. `tickFromPrice(price, { rounding: 'nearest' })` returns the same tick as a float `priceToTick` helper. ## Aligning to the spacing ```typescript import { alignTickDown, alignTickDownOrNaN, alignTickUp } from '@gala-chain/gswap-sdk'; alignTickDown(-61, 60); // -120: it floors, it does not truncate toward zero alignTickUp(-61, 60); // -60 alignTickDownOrNaN(-61, 0); // NaN: a spacing that has not loaded yet ``` `alignTickDown` and `alignTickUp` throw `INVALID_TICK_SPACING` for a spacing that is not a positive integer. `alignTickDownOrNaN` and `alignTickUpOrNaN` return the same value and answer `NaN` instead, for a drag handler or a price field that runs before the pool has loaded. ## In range: lower inclusive, upper exclusive A position is in range when the pool's current tick is at or above `tickLower` and strictly below `tickUpper`. That is the contract's own test (`tickCurrent >= tickLower && tickCurrent < tickUpper`): a pool sitting exactly on `tickUpper` is already out of range, and the position is entirely token1. ```typescript import { isSqrtPriceInRange, isTickInRange } from '@gala-chain/gswap-sdk'; isTickInRange(-60, -60, 60); // true: the lower tick is inclusive isTickInRange(60, -60, 60); // false: the upper tick is exclusive isTickInRange('59', '-60', '60'); // true: ticks may be the decimal strings a backend returns // A position row carries the pool's sqrtPrice (when the backend sent it), not its tick: const inRange = position.sqrtPrice === undefined ? undefined // not loaded: show a neutral state : isSqrtPriceInRange(position.sqrtPrice, position.tickLower, position.tickUpper); ``` - `isTickInRange(currentTick, tickLower, tickUpper)` takes numbers or decimal strings. Anything that is not an integer (`NaN`, an empty string, a fraction) makes the answer `false`. - `isSqrtPriceInRange(sqrtPrice, tickLower, tickUpper)` derives the tick from the price exactly as the contract does (`sqrtPriceToTick`) and then applies the same rule, so no float rounding can flip a pool that sits exactly on a boundary. It is `false` for a price that is not positive and finite. An app that needs a neutral "not loaded" state checks for the missing price first. Do not decide range by comparing a price with `tickToPrice(tickUpper)` using `<=`, or by mixing a square-root price with a price: at an exact boundary that reports the upper edge as in range, and two representations of the same boundary can round to opposite sides. ## Slot0 in the requested frame `pools.getSlot0(tokenA, tokenB, fee)` answers in the pool's canonical order with `flippedFromRequest`. `frameSlot0(slot0)` puts it in the order that was requested: when flipped, the square-root price is inverted at 60 digits and the tick is re-derived from it with the contract's greatest-tick rule (negating the tick is wrong for a price between ticks). It throws `INVALID_SQRT_PRICE` for a price that cannot be inverted. ## Which of these are safe in an app shell `isTickInRange`, `alignTickDownOrNaN`, `alignTickUpOrNaN`, `ALL_FEE_TIERS`, `TICK_SPACING_BY_FEE` cost a few hundred bytes. `tickToPrice`, `tickFromPrice` and `isSqrtPriceInRange` cost the two number libraries they compute with (`decimal.js` and `bignumber.js`, about 53 kB minified together), and nothing of the error catalog. The functions that throw (`alignTickDown`, `alignTickUp`, `assertTickRange`, `frameSlot0`) are not shell-safe; use the `...OrNaN` siblings there. See [Bundle size](/gswap-sdk/next/other/bundle-size.md). --- # Branded Types The GalaSwap SDK uses TypeScript branded types to prevent common mistakes when working with prices and amounts. These types help avoid, for example, mixing up regular prices with square root prices, which can lead to calculation errors. ## What are Branded Types? Branded types are a TypeScript pattern that adds compile-time safety by "branding" primitive types with additional metadata. This prevents you from accidentally passing the wrong type of value to a function. ## Available Branded Types ### Price Types | Type | Description | Usage | | ------------- | -------------------------------------------------------------------- | ---------------------------------------------- | | `PriceIn` | Input price values (decimal string or BigNumber) | When providing price parameters to functions | | `Price` | Calculated price values (always BigNumber) | When receiving price results from calculations | | `SqrtPriceIn` | Input square root price values (decimal string or BigNumber) | When providing square root price parameters | | `SqrtPrice` | Calculated square root price values (always BigNumber) | When receiving square root price results | ## Usage Example ### Casting Financial amounts are decimal strings or `BigNumber` instances, never JavaScript numbers. Price inputs are branded on top of that, so a price API (for example `addLiquidityByPrice`'s `minPrice` and `maxPrice`) takes a `PriceIn`: a calculated `Price`, or a string or `BigNumber` you cast with `as PriceIn`. An unbranded string does not compile: ```typescript import BigNumber from 'bignumber.js'; import type { PriceIn } from '@gala-chain/gswap-sdk'; function myFunction(price: PriceIn) { // ... } myFunction('0.5' as PriceIn); myFunction(new BigNumber('0.5') as PriceIn); ``` A bare number is refused at compile time: ```text myFunction(0.5); // ERROR: Argument of type 'number' is not assignable to parameter of type 'PriceIn' ``` The point of forcing this casting is to require the caller to declare explicitly that they are passing in a price value (as opposed to a square root price value, or some other numeric value) thus helping to prevent incorrect data being used. --- # Bundle size: the core `/wallet` subpath and shell-safe helpers An app has a SHELL (the code in the initial bundle: a connect flow, a failure presenter, a router) and LAZY chunks (the swap and pool screens) that use the whole SDK. This page says what the shell can import without paying for the rest. ## The core `/wallet` subpath Since 2.0.0 the subpath lives in the peer package: `@gala-chain/gswap-sdk/wallet` no longer exists. `@gala-chain/gala-core-sdk/wallet` holds only the dependency-free wallet helpers and never loads the error catalog or the rest of the SDK: ```typescript import { isGalaErrorLike, isWalletUserRejection, walletDeclineCode } from '@gala-chain/gala-core-sdk/wallet'; ``` - `isWalletUserRejection(value)`: did the person decline? (see [Error Handling](./error-handling.md), "Did the person decline?") - `walletDeclineCode(value)`: the wallet's own `code` (`4001`, `'ACTION_REJECTED'`), the same reader that fills `error.walletCode`. - `isGalaErrorLike(value)` (and the type `GalaErrorShape`; named `isGSwapErrorLike` and `GSwapErrorShape` before 2.0.0): recognises an SDK error by a brand (`Symbol.for('@gala-chain/gala-core-sdk/error')`) or by the documented shape (a string `code` and an object `params`), never `instanceof`, so it also works when two copies of the SDK are in one page. The core main entry re-exports the same functions from the same source modules. The subpath is built as its own self-contained bundle (`dist/wallet.mjs`, `dist/wallet.cjs`, `dist/browser/wallet.js`), so it does not depend on the app bundler's tree shaking at all: the built browser file is about 1.2 kB. `packages/gala-core-sdk/tests/wallet_entry.test.ts` and core's `check:pack` fail if the subpath's bundle contains any module besides its own, has any import, or exceeds 2048 bytes minified. core's `exports["./wallet"]` carries `types`, `browser`, `import` and `require` conditions, and the package declares `"sideEffects": false`. Use it in every flow that has no SDK call of its own (a connect or registration flow, an analytics hook, a route guard). Measured with rolldown, a file whose only SDK import is `isWalletUserRejection` was 85,089 bytes minified from the rc.6 main entry (the function reached `GSwapSDKError` and the whole catalog) and is 986 bytes from the subpath. ## Shell-safe helpers on the main entry The key, failure-view and wallet helpers (`compositeKeyOf`, `tryParseCompositeKey`, `tryParseTokenClassKey`, `toFailureView`, `isWriteView`, `FAILURE_OUTCOMES`, `isFetchTransportFailure`, `isValidUniqueKey`, `isWalletUserRejection` and the rest) moved to `@gala-chain/gala-core-sdk` in 2.0.0. Their budgets are enforced by core's tree-shaking test, `packages/gala-core-sdk/tests/tree_shaking.test.ts` (for example `isWalletUserRejection` 1,536 bytes). The table and budgets below are the helpers that stay in this package. The deciders reach core's light modules (the failure view and core's phase table) through the peer package. The browser build of the main entry is a folder of preserved modules (one file per source module, `dist/browser/`), so a bundler that honours `"sideEffects": false` loads only the modules an import reaches. The `import` / `require` builds (`dist/index.mjs`, `dist/index.cjs`, for Node) are still one unminified file each. A bundler puts every module that the shell and a lazy chunk both reach into the initial load WHOLE, so a helper is only as light as the module it lives in. The helpers below each live in a module that imports neither `GSwapSDKError` nor the error catalog: | Module | Helpers | | --- | --- | | `utils/classification.ts` (imports nothing) | `classification`, `NOT_QUEUED_FINAL`, `notSentClassification`, `FailureClassification` | | `utils/failure_classification.ts` | `classifyFailure`, `mayHaveBeenQueued` (the table of every error code) | | `utils/failure_guards.ts` | `isNoMarket`, `isRelayableRefusal`, `isUniqueKeyConsumed`, `isUnprovenAcknowledgement`, `isUninterpretedAnswer`, `chainErrorKeyOf` | | `classes/pending_swap_fate.ts` | `pendingSwapFateFor`, `pendingSwapFateOfOutcome`, `PENDING_SWAP_FATES` | | `classes/storage_adapters.ts` (imports nothing) | `webStorageAdapter`, `storageAdapterFromChromeStorage` | | `utils/tick_range.ts`, `utils/tick_align.ts` (import nothing) | `isTickInRange`, `alignTickDownOrNaN`, `alignTickUpOrNaN` | | `utils/tick_math.ts` (only `decimal.js` and `bignumber.js`) | `tickToPrice`, `tickFromPrice`, `isSqrtPriceInRange`, `GC_MIN_TICK`, `GC_MAX_TICK` | | `utils/confirmation_state.ts` | `confirmationStateOf`, `isConfirmationAborted`, `isConfirmationTimeout` | A function that throws an SDK error is not shell-safe, by construction. Each has a non-throwing sibling in a light module: `alignTickDownOrNaN` / `alignTickUpOrNaN` for `alignTickDown` / `alignTickUp`, `tryParseCompositeKey` / `tryParseTokenClassKey` (from `@gala-chain/gala-core-sdk`) for `parseTokenClassKey`, and `NaN` from `tickToPrice` / `tickFromPrice`. A shell that needs the class itself imports the whole SDK lazily. ## Budgets The initial-load budget of each helper, measured in the shell shape (a static `import { X }` in the entry plus a lazy chunk that does `import * as sdk`), minified bytes, through the packed tarball, with about 20% margin: | Helper | Budget (measured) | | --- | --- | | `classification`, `NOT_QUEUED_FINAL` | 512 (363) | | `isTickInRange` | 512 (294) | | `alignTickDownOrNaN`, `alignTickUpOrNaN` | 512 (251) | | `ALL_FEE_TIERS`, `TICK_SPACING_BY_FEE` | 512 (369) | | `webStorageAdapter`, `storageAdapterFromChromeStorage` | 768 (478) | | `confirmationStateOf`, `isConfirmationAborted`, `isConfirmationTimeout` | 1,792 (1,376) | | `isNoMarket`, `isRelayableRefusal`, `isUniqueKeyConsumed`, `chainErrorKeyOf` | 2,560 (2,027) | | `classifyFailure`, `mayHaveBeenQueued` | 9,216 (7,772) | | `pendingSwapFateFor` | 9,728 (7,943) | | `tickToPrice`, `tickFromPrice`, `isSqrtPriceInRange` | 62,464 (53,674) | The decider family carries the table of every error code (about 135 names, 4 kB of strings no minifier removes) and the phase table, but no class and no catalog templates. It reaches core's light modules (the failure view and core's phase table) through `@gala-chain/gala-core-sdk`, which stays a peer dependency of the app. The combined shell of this package's helpers measures 64,114 bytes. The three price functions are the two number libraries they compute with (`decimal.js` and `bignumber.js`, about 53 kB together) and about 1.3 kB of the SDK; an app that already ships both pays only the SDK's part. `tests/shell_shape.ts` holds the table (`SHELL_SAFE_HELPERS`) and, when a helper breaks its budget, names the modules that came with it. `tests/tree_shaking.test.ts` runs it from `src` (rolldown), `npm run check:pack` from the packed tarball through the `browser` condition, and `GSWAP_VITE_PACKAGE= npm test` repeats it through a real Vite build (which adds Vite's own ~1.2 kB dynamic-import preload helper; the test subtracts it). A second test walks the run-time import graph of every light module from its source and fails on any path to the class or the catalog. To print the numbers yourself: ```bash tsx scripts/measure-shell-shape.ts classification compositeKeyOf tsx scripts/measure-shell-shape.ts --entry @gala-chain/gswap-sdk --cwd /path/to/app classifyFailure tsx scripts/measure-shell-shape.ts --vite /path/to/node_modules/vite classifyFailure ``` --- # Production dependency audit `npm audit --omit=dev` was run for the packed SDK dependency graph and reports zero vulnerabilities. Signing no longer depends on `@gala-chain/api` (and so no longer on `elliptic`, `secp256k1` native bindings, `bn.js` or `class-validator`): the SDK owns its signing primitives in `src/utils/signing.ts` on the audited, pure-JS `@noble/curves` and `@noble/hashes`. The golden-vector suites (`tests/signing-golden.test.ts`, `tests/signing.test.ts`) pin every serialization, signature and prefix byte-for-byte to the Gala Wallet and `@gala-chain/api` outputs. `@gala-chain/api` remains a devDependency only, for those cross-checks. Set `GSWAP_SDK=*` only while debugging in a trusted environment. Read logging prints backend request URLs and response data, which can include quote amounts and other application-sensitive values. It does not log private keys or signed write bodies. --- # Migration from 0.x The 1.0 line (1.0.0) is a breaking migration to the current GalaChain DEX contract. Legacy names are removed; do not add compatibility fields to v2 DTOs. ## From 1.2.x to 2.0.0: signing moved to `@gala-chain/gala-core-sdk` The signing, transport, wallet-helper and base-error layer moved out of this package into the peer package `@gala-chain/gala-core-sdk`. The DEX API, the write protocol and the DTOs are unchanged. Install both packages (`npm install @gala-chain/gswap-sdk@next @gala-chain/gala-core-sdk@next`: both are release candidates under the `next` dist-tag); the peer range is `>=1.0.0-rc.7 <2`. | 1.2.x | 2.0.0 | | --- | --- | | `import { PrivateKeySigner, GalaWalletSigner, BrowserWalletSigner, serialize, signNative, ... } from '@gala-chain/gswap-sdk'` | The same names from `@gala-chain/gala-core-sdk` (no re-export from this package) | | `@gala-chain/gswap-sdk/wallet` | `@gala-chain/gala-core-sdk/wallet` | | `isGSwapErrorLike`, `GSwapErrorShape`, `GSWAP_ERROR_PHASES`, `GSwapErrorPhase`, `GSwapErrorContext`, `renderGSwapErrorTemplate` | `isGalaErrorLike`, `GalaErrorShape`, `GALA_ERROR_PHASES`, `GalaErrorPhase`, `GalaErrorContext`, `renderGalaErrorTemplate` | | Error brand `Symbol.for('@gala-chain/gswap-sdk/error')` | `Symbol.for('@gala-chain/gala-core-sdk/error')` | | `error instanceof GSwapSDKError` | `isGSwapError(error)` or core's `isGalaError(error)`: a signer or transport error is a plain `GalaSDKError` | | `gswapErrorTemplates` held every code | DEX codes only; merge with core's `galaErrorTemplates` | See core's [Migrating from gswap-sdk 1.x](/gala-core-sdk/next/migrating-from-gswap.md) for the full old-path to new-path table. ## From 1.1.x to 1.2.0 (release candidates on the `rc` tag) The 1.2.0 line changes how errors reach your code. The write protocol and DTOs are unchanged. | 1.1.x | 1.2.0-rc | | --- | --- | | `new GSwapSDKError(message, code, details)`, `error.details`, `userMessage`, `chainMessage` | `new GSwapSDKError(code, params, context)`; `error.params` (flat primitives), typed `status`, `url`, `uniqueKey`, `requestTransactionId`, `applyTransactionId`, `blockNumber`, `retryAfterMs`, `body`, `bodyText`, `cause`. `error.message` is English for logs only; branch on `code`. | | A chain `ErrorKey` as `error.code` | `CHAIN_REJECTED` with `params.errorKey` and `params.serverMessage` | | `VALIDATION_ERROR` / `INVALID_GATEWAY_RESPONSE` with `details.type` | One code per fault (`INVALID_FEE`, `NON_CANONICAL_PAIR`, `GATEWAY_DATA_MISSING`, ...) | | Retry and outcome rules kept in each app | `classifyFailure(error)`, `isNoMarket`, `mayHaveBeenQueued`, `pendingSwapFateFor` | | Signing through `@gala-chain/api` | The SDK's own primitives on `@noble/curves` / `@noble/hashes`; `@gala-chain/api` is a devDependency only | | `GalaWalletSigner` fell back to personal-sign on a wallet that rejected `native` | No fallback; `{ scheme: 'personal-sign' }` is explicit and needs a wallet build with the fix | See [Error Handling](/gswap-sdk/next/other/error-handling.md) and [Signing and Identity](./signing-and-identity.md). ## Changes between 1.0.0-rc.3 and 1.0.0-rc.4 A class key carries no symbol. Collection and symbol disagree for many tokens (GBNB's symbol is BNB, every launchpad token shares the collection `Token`, and some real collections contain the `$` delimiter, e.g. `$GMUSIC`), so the SDK never derives one from the other. - **`createPool` for a token with no registered trading symbol now needs one.** Pass `token0Symbol` / `token1Symbol` (ASCII letters and digits); without it the call throws `TOKEN_SYMBOL_NOT_REGISTERED` instead of proposing the raw collection (which the bouncer rejects for any collection containing `_` or `$`, and always for launchpad tokens). A symbol that disagrees with the one already registered for that class is rejected. The CLI's `create_pool` takes the two optional symbol arguments. - **Class keys parse from the right.** The last three segments are category, type and additionalKey; everything before them is the collection, so `$GMUSIC$Unit$none$none` resolves instead of failing as a five-part key. - Docs and examples no longer treat `collection` as the symbol (`full_dex` passes full class keys and carries an explicit `symbol` per token). ## Changes between 1.0.0-rc.2 and 1.0.0-rc.3 - `BrowserWalletSigner` personal-sign now signs the **bare** serialized DTO and sends the EIP-191 header (`\u0019Ethereum Signed Message:\n`) as the DTO's `prefix`. The previous recipe embedded `prefix` in the signed message, which the chain recovers to an address nobody holds, so a personal-sign `CreatePool` could execute under a phantom creator; the swap backend now rejects that shape. No caller changes are needed; re-sign nothing. `GalaWalletSigner`'s personal-sign scheme carries the same header value (the wallet prepends it before hashing). ## Changes between 1.0.0-rc.1 and 1.0.0-rc.2 Swaps are queued. The synchronous `Trade` method was removed from the contract and from this SDK, with no fallback. | rc.1 | rc.2 | | --- | --- | | `swaps.swap()` signed and submitted `Trade`; the executed result came back inline | signs and submits `RequestTrade`; the gateway acknowledges with `mode: 'queued'` and `result === undefined` | | `SubmittedTransaction.mode` was always `'sync'` | `'sync'` for liquidity writes, `'queued'` for swaps | | `confirm()` polled the indexed transaction and returned `IndexedTransaction` | reads apply-results and returns `AppliedTrade` (apply `transactionId`, `blockNumber`, `requestTransactionId`, executed `result`), or throws the chain's rejection (in 1.1.x its `ErrorKey` was `error.code`; since 1.2.0-rc.3 it is `CHAIN_REJECTED` with `params.errorKey`) | | — | `swaps.confirmSwap(uniqueKey)` resolves a swap from the persisted key alone | | `TradeDTO` | `RequestTradeDTO` (same fields) | | `ConfirmOptions` had `timeoutMs`, `pollIntervalMs` | adds `initialDelayMs` (default 3 s for swaps, 0 for liquidity writes) | | `CONFIRMATION_TIMEOUT` meant "not indexed yet" | means the outcome is unknown: confirm the same key again, never resubmit | | `gateway.submit('Trade', …)` | refused locally with `METHOD_NOT_SUPPORTED` | ## API replacements | 0.x | v2 replacement | | --- | --- | | `Bundler` | `Chain Gateway` writes through `GSwap` | | `Events` / `EventSocketClient` | No socket; call `SubmittedTransaction.confirm()` | | `PendingTransaction` | `SubmittedTransaction` | | `TxWaiter` | `SubmittedTransaction.confirm()` | | `PendingTransaction.wait()` | `SubmittedTransaction.confirm()` | | `TransactionPendingResponse` | `AppliedTrade` returned by `confirm()` for a queued swap | | `stringsInstructions` | Removed; the gateway derives chain references | | bundle IDs | `uniqueKey` | | `transactionId` as the only correlation key | `uniqueKey`; request `transactionId` may be `null` | | `GSwap.events.connectEventSocket()` | Removed | | `GSwap.swap(...)` | `gSwap.swaps.swap(tokenIn, tokenOut, fee, params)` | | `pools.getPoolData(...)` | `pools.getPool(...)` | | `positions.getPositionById(...)` | `positions.getPosition({ t0, t1, fee, owner, tickLower, tickUpper })` | ## DTO field replacements | Removed field or shape | v2 shape | | --- | --- | | Class-key object `token0` / `token1` in writes | Trading-symbol `token0` / `token1`; SDK accepts a symbol or class key as input | | `amount` | One of `sell0Qty`, `sell1Qty`, `buy0Qty`, `buy1Qty` | | `zeroForOne` | Derived from token ordering and exact-in/exact-out side | | `sqrtPriceLimit` | Removed; use quote slippage fields | | `positionId` | Position identity: symbols, fee, owner, and tick range | | `amount0Desired`, `amount1Desired` | Exactly one `depositQuantityToken0` or `depositQuantityToken1` | | `amount0Min`, `amount1Min` | `amountOutMinimum` for trades, or estimate before a liquidity write | | Partial collect amounts | Removed; `collectPositionFees` sweeps everything | | Partial remove percentage | Optional `withdrawalQuantityToken0` or `withdrawalQuantityToken1`; omit both to close | | CreatePool class-key `token0` / `token1` | `token0Key` / `token1Key` plus `token0Symbol` / `token1Symbol` | | `FEE_TIER` without zero | Fee tiers `0`, `500`, `3000`, `10000` | ## Transaction flow Build a quote, choose the fee and slippage bound, submit through the SDK, then persist `uniqueKey` and confirm. A queued swap acknowledgement has `mode: 'queued'`, no result, and a request `transactionId` when provided; the applied outcome is returned by `confirm()`. ```typescript const quote = await gSwap.quoting.quoteExactOutput('GALA', 'GUSDC', '50'); const tx = await gSwap.swaps.swap('GALA', 'GUSDC', quote.feeTier, { exactOut: '50', amountInMaximum: quote.amountIn, }); await tx.confirm(); ``` ## Signing migration `PrivateKeySigner` remains native. `GalaWalletSigner` no longer signs EIP-712; it uses native `gala_signChainDto`. The older-wallet personal-sign fallback was removed (on released wallets it recovered a phantom signer); `scheme: 'personal-sign'` remains as an explicit opt-in that requires a wallet build containing the fix. Use `BrowserWalletSigner` for generic EIP-1193 wallets. See [Signing and Identity](/gswap-sdk/next/other/signing-and-identity.md). # Gala Launchpad SDK 9.0.0-rc.5 (@gala-chain/launchpad-sdk) The TypeScript SDK for the Gala Launchpad backend: token launches, bonding-curve trading, balances, bridging and real-time events. --- # Agent guide: launchpad-sdk This page is for an AI agent (or a developer working with one) that writes code against `@gala-chain/launchpad-sdk`, the client of the Gala Launchpad backend: pools, bonding-curve buys and sells, token creation, balances, transfers and real-time events. Every recipe compiles against the package's built types (the docs build fails otherwise), and every invariant names the test that enforces it. ## Which package for which job | Job | Package | | --- | --- | | Launchpad pools, buy and sell on the bonding curve, create a token, balances, transfers | `@gala-chain/launchpad-sdk` (this package) | | Trade a token after it graduates to the DEX, quotes, liquidity | `@gala-chain/gswap-sdk` (this package has no DEX client) | | Signers, wallet providers, bridge, plain gateway reads and writes | `@gala-chain/gala-core-sdk` (the peer dependency of this package) | | The same abilities as MCP tools (`GALA_TOOLSETS=core,launchpad`) | `@gala-chain/gala-mcp-server` | Install with `npm install @gala-chain/launchpad-sdk@next` and the peers next to it (core range `>=1.0.0-rc.7 <2`). ## Recipes ### Read pools without a wallet ```ts import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const recent = await sdk.fetchPools({ type: 'recent', pageSize: 10 }); for (const pool of recent.items) console.log(pool.tokenName, pool.symbol); ``` ### Quote and buy a bonding-curve token Quote first: the quote's amount and reverse-fee bound go into the buy so the transaction carries slippage protection. ```ts import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const quote = await sdk.calculateBuyAmount({ tokenName: 'anime', amount: '100', type: 'native' }); const result = await sdk.buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: quote.amount, maxAcceptableReverseBondingCurveFee: quote.reverseBondingCurveFee, slippageToleranceFactor: 0.01, }); console.log(result.transactionId, result.outputAmount); ``` ### Quote and sell ```ts import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const quote = await sdk.calculateSellAmount({ tokenName: 'anime', amount: '100', type: 'exact' }); const result = await sdk.sell({ tokenName: 'anime', amount: '100', type: 'exact', expectedAmount: quote.amount, maxAcceptableReverseBondingCurveFee: quote.reverseBondingCurveFee, slippageToleranceFactor: 0.01, }); console.log(result.transactionId, result.outputAmount); ``` ### Create a token ```ts import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const available = (await sdk.isTokenNameAvailable('anime')) && (await sdk.isTokenSymbolAvailable('ANIME')); if (!available) throw new Error('Name or symbol is taken'); const fee = await sdk.fetchLaunchTokenFee(); console.log('launch fee:', fee); const created = await sdk.launchToken({ tokenName: 'anime', tokenSymbol: 'ANIME', tokenDescription: 'Example token', tokenImage: 'https://example.test/anime.png', }); console.log(created.transactionId); ``` ### Write through the bundler and wait for it The `sdk.launchpad` writes are submitted to the bundler: the submission exposes `bundleId`, `uniqueKey` and `wait()`. Acknowledgement is not confirmation: `wait()` resolves when the bundle is applied. ```ts import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const submission = await sdk.launchpad.buyWithNative({ vaultAddress: 'client|example-token', quantity: '1', expectedAmount: '1', }); const result = await submission.wait(); console.log(submission.bundleId, submission.uniqueKey, result); ``` ### Transfer GALA ```ts import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const { transactionId, blockNumber } = await sdk.transferToken({ to: 'eth|9876543210987654321098765432109876543210', tokenId: 'GALA|Unit|none|none', amount: '1', }); console.log(transactionId, blockNumber); ``` After a token graduates, trade it with `@gala-chain/gswap-sdk` using its class key, not with `buy`. ## Invariants - A launchpad token name is 1 to 25 letters and digits: the DTO schema refuses an empty name, a longer one and any other character (a pipe-delimited class key is not a name). Enforced by `packages/launchpad-sdk/tests/dto-token-name-schema.test.ts` ("refuses 26 characters with the cap in the message, and an empty or non-alphanumeric name"). - A token sale's pre-buy is signed as a plain decimal string in the canonical spelling the chain parses. Enforced by `packages/launchpad-sdk/tests/create-sale-preflight.test.ts` ("signs a plain decimal pre-buy in the canonical spelling the chain parses"). - A user address is `eth|` (or a `client|` alias): every Ethereum spelling is converted to it. Enforced by `packages/launchpad-sdk/tests/user_identity_wire.test.ts` ("sends every Ethereum spelling as eth|"). - `eth|0x` is REFUSED with a `ValidationError` naming the field and the correct spelling, before anything is signed or sent; a bare `0x<40 hex>` is converted. Enforced by `packages/launchpad-sdk/tests/user_identity_wire.test.ts` ("refuses eth|0x, a wrong checksum, partial and foreign spellings with a ValidationError naming the field"). - A bundle write signs a `uniqueKey` with the `galaswap-operation-` prefix and at most 64 characters, with no spaces. Enforced by `packages/launchpad-sdk/tests/bundle-service-trading.test.ts` ("signs a uniqueKey matching the galaswap-operation- prefix and length constraint"). - A bundle submission's `wait()` is the confirmation: a failed confirmation read does not end a wait the socket can still settle, and a wait that never settles ends at its deadline naming the last failure. Enforced by `packages/launchpad-sdk/tests/bundle-wait-resilience.test.ts` ("BundleSubmission.wait: a failed confirmation read does not end a wait the socket can settle") and `packages/launchpad-sdk/tests/bundle-wait-resilience.test.ts` ("a read failure ends the wait only at the deadline, with the last failure named in the timeout error"). - A client built without a wallet refuses to `buy` and to `sell` (the call throws; the read methods keep working). Enforced by `packages/launchpad-sdk/tests/launchpad-sdk-methods.test.ts` ("should require wallet"). ## Errors The SDK throws typed errors (`ValidationError`, `ConfigurationError`, `NetworkError` and the others exported by the package); branch on the class or on `error.code`, never on message text. A signing or transport failure of a gateway write is a core `GalaSDKError` with a catalog code, listed at `/errors.json`. | Failure | Meaning | Fix | | --- | --- | --- | | `ValidationError` naming a field | An input failed the SDK's checks before anything was sent. | Correct the named field; nothing was submitted. | | `ValidationError('WALLET_REQUIRED')` | A write was attempted on a client with no wallet. | Build the client with `wallet` (or `setWallet`). | | `ConfigurationError` naming `bridge` | A bridge or wrap method was called without the `bridge` loader option. | Pass `bridge: () => import('@gala-chain/gala-core-sdk/bridge')`. | | Bundle `wait()` timeout | The bundle was submitted but its confirmation was not seen in time. | Read the submission's `uniqueKey` status again; do not submit a second bundle. | --- # @gala-chain/launchpad-sdk The SDK signs with `@gala-chain/api` and `ethers`; it does not depend on `@gala-chain/connect`. The TypeScript SDK for Gala Launchpad (9.0, a release candidate under the `next` dist-tag; `latest` is still 8.1.0). It provides read APIs for launchpad data, typed launchpad submissions and gateway-backed token transactions. Version 9.0 is launchpad-only: the DEX is a separate SDK, `@gala-chain/gswap-sdk` (this package has no DEX client and does not depend on it), and the gateway-generic pieces (signers, wallet helpers and providers, React hooks, the bridge) are `@gala-chain/gala-core-sdk`'s. See [MIGRATING-TO-9.0.md](/launchpad-sdk/next/migrating-to-9.md) for every removed export and where it went. ## Install ```bash pnpm add @gala-chain/launchpad-sdk@next @gala-chain/gala-core-sdk@next @gala-chain/api axios bignumber.js ethers socket.io-client zod ``` An install without `@next` gets 8.1.0. Pin the exact versions in an app build. `@gala-chain/gala-core-sdk` and the others are peer dependencies: install them next to this package. An app that bridges or wraps tokens installs the bridge's own peers (`ethers`, `@solana/web3.js`, `@solana/spl-token`) and hands the bridge module to the SDK: `new LaunchpadSDK({ ..., bridge: () => import('@gala-chain/gala-core-sdk/bridge') })` (loaded at the first bridge or wrap call). This package never loads that module or Solana itself, so an app that does not bridge bundles and installs neither; without the loader the bridge and wrap methods throw a `ConfigurationError` naming the `bridge` option. For the DEX, install `@gala-chain/gswap-sdk` 2.0 (also under `next`) next to this package: `pnpm add @gala-chain/gswap-sdk@next`. ## Configure ```ts import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const pools = await sdk.fetchPools({ pageSize: 10 }); console.log(pools); ``` `Environment` is `'prod' | 'stage'`. The SDK defaults to `prod`; it does not infer an environment from a custom `baseUrl`. Use `gatewayBaseUrl` for the chain gateway override. ## Launchpad writes Launchpad buys, sells, and sale creation are submitted to the bundler. The result exposes `bundleId`, `uniqueKey`, and `wait()`: ```ts const submission = await sdk.launchpad.buyWithNative({ vaultAddress: 'client|example-token', quantity: '1', expectedAmount: '1', }); const result = await submission.wait(); console.log(submission.bundleId, result); ``` ## Token writes Token transfers, burns, locks and unlocks go straight to the GalaChain gateway (signed and sent by `@gala-chain/gala-core-sdk`'s `GatewayWrites`) and report the chain transaction id and block from the gateway's `x-transaction-id` and `x-block-number` headers. They are made as the SDK's wallet, or, for an SDK configured with `{ signer, walletAddress }`, as that identity (an `eth|` account or a `client|` alias): ```ts const { transactionId, blockNumber } = await sdk.transferToken({ to: 'eth|9876543210987654321098765432109876543210', tokenId: 'GALA|Unit|none|none', // or tokenName: 'anime' for a launchpad token amount: '1', // whole tokens, sent as written }); const locked = await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '100' }] }); console.log(locked.transactionId, locked.blockNumber); ``` To send to a `client|` recipient, or to write without a launchpad SDK, use `GatewayWrites` from `@gala-chain/gala-core-sdk` directly. Never place a private key in source control. For a write-capable SDK, provide a signer through the supported wallet configuration. ## GSwap DEX DEX calls use `@gala-chain/gswap-sdk`'s `GSwap` client. An app that trades on both builds both clients from the same key (`sdk.dex` is gone, and so are `fetchAllDexSeasons`, `fetchCurrentDexSeason`, `fetchDexLeaderboardBySeasonId`, `fetchCurrentDexLeaderboard`, `fetchDexAggregatedVolumeSummary` and `onDexPoolCreation`: they are `gSwap.leaderboard.*`, `gSwap.market.getVolumeSummary()` and `gSwap.pools.watchNewPools()`): ```ts import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(process.env.PRIVATE_KEY!), walletAddress: sdk.getAddress(), // the launchpad SDK built with the same key }); const quote = await gSwap.quoting.quoteExactInput( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', '100', ); const swap = await gSwap.swaps.swap( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', quote.feeTier, { exactIn: '100', amountOutMinimum: quote.amountOut }, ); // The swap is queued (swap.mode === 'queued'); confirm() resolves the applied trade // or throws the chain's rejection. const applied = await swap.confirm(); console.log(applied.transactionId, applied.result); ``` Use `gSwap.pools`, `gSwap.positions`, `gSwap.symbols`, `gSwap.assets`, `gSwap.market` and `gSwap.leaderboard` for pool discovery, liquidity, token identifiers, user assets, prices and volume, and the trading competition. DEX reads are unsigned; state-changing DEX calls require the client's signer. Runnable DEX demos and guides live in `packages/gswap-sdk/examples/demos`. ## Prices `sdk.fetchTokenPrice({ tokenName })` prices a launchpad token (the bonding curve, or the swap backend once graduated). It takes `tokenName` only: `fetchGalaPrice`, `fetchTokenPrice({ tokenId })`, `fetchPriceHistory` and `fetchAllPriceHistory` are gone. Prices and price series for any token by class key are gswap-sdk's `gSwap.market.getPrice(tokenId)` and `gSwap.market.getPriceSeries(key, timeframe)`; `sdk.resolveTokenClassKey(name)` gives a launchpad token's key. The MCP tools of the same names still work. ## Hosts `env: 'stage'` selects the Gala staging backends for launchpad reads and DEX reads, and `gateway-testnet.galachain.com` for gateway operations. Production host values are selected by `env: 'prod'`; `baseUrl` overrides the launchpad host. ## Further reading - [Migrating to 9.0](/launchpad-sdk/next/migrating-to-9.md) - Changelog: `CHANGELOG.md` in the package root - [API reference](/launchpad-sdk/next/api-reference.md) - [Examples](/launchpad-sdk/next/examples.md) - [gswap-sdk](/gswap-sdk/next/overview.md): the DEX SDK, with its own runnable demos --- # Gala Launchpad SDK - Usage Examples Practical code examples for the launchpad SDK (9.0.0), organized by category. For complete API documentation, see [API Reference](/launchpad-sdk/next/api-reference.md). > **9.0 is launchpad-only.** The DEX (quotes, swaps, pools, liquidity, fees, market prices, leaderboards) is > `@gala-chain/gswap-sdk`; its runnable demos are in > `packages/gswap-sdk/examples/demos`. Gateway-generic pieces > (signers, wallet providers, React hooks, the bridge) are `@gala-chain/gala-core-sdk`'s. See > [MIGRATING-TO-9.0.md](/launchpad-sdk/next/migrating-to-9.md) for where each removed export went. ## Table of Contents - [Token Format Decision Tree](#token-format-decision-tree) - [Quick Start](#quick-start) - [Recommended Learning Path](#recommended-learning-path) - [Core Operations](#core-operations) - [Bonding Curve Trading](#bonding-curve-trading) - [Real-Time Monitoring](#real-time-monitoring) - [Streaming & Chat](#streaming--chat) - [Utilities](#utilities) - [Error Handling](#error-handling) --- ## Token Format Decision Tree **Launchpad tokens are addressed by `tokenName`; standard GalaChain tokens by a token id (`collection|category|type|additionalKey`).** ```text Q: What operation am I performing? │ ├── Buying/selling tokens on the bonding curve (pre-graduation)? │ └── Use tokenName: sdk.buy({ tokenName: 'anime', amount: '100', type: 'native' }) │ ├── Transferring tokens? │ ├── Launchpad token? → sdk.transferToken({ tokenName: 'anime', ... }) │ └── Standard GalaChain token? → sdk.transferToken({ tokenId: 'GALA|Unit|none|none', ... }) │ ├── Checking a launchpad token's price? │ └── sdk.fetchTokenPrice({ tokenName: 'anime' }) (bonding curve, or the swap backend once graduated) │ ├── Need a launchpad token's class key? │ └── await sdk.resolveTokenClassKey('anime') (never construct it by hand) │ ├── Trading a graduated token / any other token on the DEX, or a price by token id? │ └── @gala-chain/gswap-sdk: gSwap.swaps.swap(...), gSwap.market.getPrice(tokenId) │ └── Graduating a token from bonding curve to DEX? └── Use tokenName: sdk.graduateToken('anime') ``` ### Format Reference | Format | Pattern | Example | Used For | |--------|---------|---------|----------| | **tokenName** | Letters and digits, 1-25 chars | `'anime'` | Bonding curve ops, price | | **token id / class key** | `collection\|category\|type\|additionalKey` | `'GALA\|Unit\|none\|none'` | Transfers, balances, locks, standard tokens | ### Common Mistakes Table | ❌ Wrong | ✅ Correct | Why | |----------|------------|-----| | `sdk.buy({ tokenName: 'ANIME\|Unit\|...' })` | `sdk.buy({ tokenName: 'anime' })` | Bonding curve uses simple names | | `sdk.fetchTokenPrice({ tokenId: 'GALA\|Unit\|none\|none' })` | `gSwap.market.getPrice('GALA\|Unit\|none\|none')` (gswap-sdk) | 9.0 prices launchpad tokens only; a `tokenId` is refused with a `ValidationError` | | Assuming `buy()` works for graduated tokens | Check `isGraduated`, trade on the DEX with gswap-sdk if true | Graduated tokens trade on the DEX | ### Detecting Graduation Status ```typescript const pool = await sdk.fetchPools({ tokenName: 'anime' }); const isGraduated = pool.items[0]?.isGraduated ?? false; if (isGraduated) { // Token is on the DEX: trade it with @gala-chain/gswap-sdk using its class key. // Always resolve the key, never construct it: the symbol may differ from the tokenName. const tokenClassKey = await sdk.resolveTokenClassKey('anime'); console.log('Trade on the DEX with', tokenClassKey); } else { console.log('Still on the bonding curve: use sdk.buy / sdk.sell with tokenName "anime"'); } ``` ### Method Reference | Method | tokenName | token id | Notes | |--------|:---------:|:--------:|-------| | `buy()` | ✅ | ❌ | Bonding curve only | | `sell()` | ✅ | ❌ | Bonding curve only | | `graduateToken()` | ✅ | ❌ | Triggers DEX migration | | `calculateBuyAmount()` | ✅ | ❌ | Pre-trade calculation | | `calculateSellAmount()` | ✅ | ❌ | Pre-trade calculation | | `fetchPools()` | ✅ | ❌ | Query bonding curve pools | | `fetchTokenPrice()` | ✅ | ❌ | Launchpad token price (`{ tokenName }` only) | | `transferToken()` | ✅ | ✅ | Both work | | `lockTokens()` | ✅ | ✅ | Both work | | `fetchTokenBalance()` | ✅ | ✅ | Both work | > **See Also:** For complete type definitions and utilities, see `src/types/token.types.ts` --- ## Quick Start ### Installation ```bash npm install @gala-chain/launchpad-sdk@next @gala-chain/gala-core-sdk@next zod ``` `@gala-chain/gala-core-sdk` and `zod` are peer dependencies. 9.0 is a release candidate under the `next` dist-tag (an install without `@next` gets 8.1.0). ### Basic Setup ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; // Read-only mode (no wallet required) const sdk = createLaunchpadSDK({ env: 'prod' }); // Full-access mode (with wallet for trading) const sdkWithWallet = createLaunchpadSDK({ env: 'prod', privateKey: process.env.WALLET_PRIVATE_KEY }); ``` ### Run Your First Demo ```bash # Complete SDK feature demonstration npm run demo # Basic bonding curve buy/sell npm run demo:trades # Watch for new launchpad token launches npm run demo:watch:tokens ``` --- ## Recommended Learning Path ### 1. Start with Core Operations ```bash npm run demo # Complete SDK overview npm run demo:read-only # Read-only operations (no wallet needed) npm run demo:authenticated # Authenticated operations (wallet required) ``` **Learn:** SDK initialization, configuration, read-only vs full-access modes ### 2. Understand Bonding Curve Trading ```bash npm run demo:trades # Basic buy/sell operations npm run demo:bonding:graduation # Token graduation workflow npm run demo:bonding:pool-discovery # Pool filtering and discovery ``` **Learn:** Pre-graduation token trading, bonding curve mechanics, token launch lifecycle ### 3. Try Real-Time Features ```bash npm run demo:watch:tokens # Watch for new launchpad token launches npm run demo:monitoring:websocket-events ``` **Learn:** WebSocket event monitoring, token discovery ### 4. Explore Advanced Topics ```bash npm run demo:cache # Metadata cache performance npm run demo:token-supply # Token supply metrics from GalaChain ``` **Learn:** Performance optimization, token supply queries ### 5. The DEX Swaps, liquidity, fees, pools and market data are `@gala-chain/gswap-sdk`'s. Its demos: `packages/gswap-sdk/examples/demos/README.md` (`npx tsx src//.ts`). --- ## Core Operations ### Initialize SDK **Read-Only Mode** (no wallet required): ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'prod' }); // Query operations work without wallet const pools = await sdk.fetchPools({ type: 'popular', pageSize: 10 }); const price = await sdk.fetchTokenPrice({ tokenName: 'anime' }); ``` **Full-Access Mode** (with wallet for trading): ```typescript const sdk = createLaunchpadSDK({ env: 'prod', privateKey: process.env.WALLET_PRIVATE_KEY! }); // Now you can submit trades const result = await sdk.buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: '1' }); ``` **Dynamic Wallet Configuration:** ```typescript import { Wallet } from 'ethers'; // Start in read-only mode const sdk = createLaunchpadSDK({ env: 'prod' }); // Later, upgrade to full-access sdk.setWallet(new Wallet(process.env.WALLET_PRIVATE_KEY!)); // Now signing operations work const result = await sdk.buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: '1' }); ``` **Demos:** - `npm run demo` - Complete SDK showcase - `npm run demo:read-only` - Wallet-free operations - `npm run demo:authenticated` - Wallet-required operations --- ## Bonding Curve Trading Trade tokens that are still in bonding curve pools (pre-graduation). ### Buy Tokens on Bonding Curve ```typescript const sdk = createLaunchpadSDK({ env: 'prod', privateKey: process.env.WALLET_PRIVATE_KEY! }); // Calculate purchase amounts const quote = await sdk.calculateBuyAmount({ tokenName: 'anime', amount: '100', type: 'native' }); console.log(`For 100 GALA:`); console.log(` Receive: ${quote.amount} tokens`); console.log(` Fees: ${quote.transactionFee} GALA transaction, ${quote.gasFee} GALA gas`); // Execute purchase const result = await sdk.buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: quote.amount, slippageToleranceFactor: 0.01 }); console.log(`✓ Purchase completed: ${result.transactionId}`); ``` ### Sell Tokens on Bonding Curve ```typescript // Calculate sale amounts const quote = await sdk.calculateSellAmount({ tokenName: 'anime', amount: '10000', type: 'exact' }); console.log(`Selling 10,000 tokens:`); console.log(` Receive: ${quote.amount} GALA`); console.log(` Fee: ${quote.reverseBondingCurveFee} GALA`); // Execute sale const result = await sdk.sell({ tokenName: 'anime', amount: '10000', type: 'exact', expectedAmount: quote.amount, slippageToleranceFactor: 0.01 }); console.log(`✓ Sale completed: ${result.transactionId}`); ``` **Bonding Curve Demos:** - `npm run demo:trades` - Basic buy/sell operations - `npm run demo:bonding:graduation` - Token graduation workflow and simulation - `npm run demo:bonding:pool-discovery` - Pool filtering and discovery - `npm run demo:bonding:price-impact` - Price impact analysis and calculations - `npm run demo:bonding:token-launch` - Token launch lifecycle demonstration - `npm run demo:bonding:volume-trading` - High-volume trading simulation - `npm run demo:bonding:pool-analysis` - Deep pool analytics and metrics - `npm run demo:bonding:user-holder` - Holder context - `npm run demo:bonding:pagination-variants` - Pagination variants - `npm run demo:bonding:pool-creator-filtering` - Creator filtering --- ## Real-Time Monitoring Monitor token creation events with the SDK's watchers. (New DEX pools are gswap-sdk's: `gSwap.pools.watchNewPools()`.) ### Watch for Launchpad Token Creation ```typescript // Monitor for new token launches const unsubscribe = sdk.onLaunchpadTokenCreation( (token) => { console.log(`🚀 New token: ${token.tokenName}`); console.log(` Symbol: ${token.symbol}`); console.log(` Creator: ${token.creatorAddress}`); console.log(` Created: ${new Date(token.createdAt).toISOString()}`); }, { creatorAddress: 'eth|...', // Optional: watch specific creator intervalMs: 30000 // Poll every 30 seconds } ); // Stop watching after 2 minutes setTimeout(() => { unsubscribe(); console.log('Stopped watching for new tokens'); }, 120000); ``` **Monitoring Demos:** - `npm run demo:watch:tokens` - Watch for new launchpad token launches - `npm run demo:watch:integration` - Token creation integration - `npm run demo:monitoring:stream-events` - Stream events - `npm run demo:monitoring:websocket-events` - WebSocket event handlers --- ## Streaming & Chat Live streaming and real-time chat features for token communities. ### Basic Stream Management ```typescript const sdk = createLaunchpadSDK({ env: 'prod', privateKey: process.env.WALLET_PRIVATE_KEY!, streamWebSocketUrl: 'wss://stream.example.com' }); // Stream credentials (stream key, RTMP URL, playback id) of a token you own const creds = await sdk.getStreamCredentials('mytoken'); console.log(`RTMPS URL: ${creds.rtmpsUrl}`); console.log(`Playback ID: ${creds.playbackId}`); // Check global streaming status const globalStatus = await sdk.getGlobalStreamingStatus(); console.log(`Streaming enabled globally: ${globalStatus.enabled}`); ``` ### Engagement Statistics ```typescript // Engagement metrics for analytics dashboards arrive on the token room about every 15 seconds // while there is chat activity const unsubscribe = sdk.onEngagementStatsUpdated((event) => { console.log(`${event.tokenName}: ${event.chat.messageCount} chat messages`); console.log(`Comments: ${event.comments.count} from ${event.comments.uniqueCommenters} users`); }); ``` ### Real-Time Chat with WebSocket ```typescript // Connect to stream WebSocket with event handlers await sdk.connectStreamWebSocket({ onTypingIndicator: (event) => { const count = event.typingUsers.length; if (count === 1) { console.log(`${event.typingUsers[0]?.fullName} is typing...`); } else if (count > 1) { console.log(`${count} people are typing...`); } }, onChatMessage: (event) => { console.log(`[${event.user?.fullName}]: ${event.content}`); } }); // Subscribe to a stream await sdk.subscribeToStream('mytoken'); // Send typing indicators sdk.sendTypingStart('mytoken'); // ... user types ... sdk.sendTypingStop('mytoken'); // Send a message via WebSocket await sdk.sendStreamChatViaWebSocket('mytoken', 'Hello everyone!'); // Cleanup await sdk.unsubscribeFromStream('mytoken'); await sdk.disconnectStreamWebSocket(); ``` ### Typing Indicators ```typescript // Typing indicators are ephemeral (not persisted) // Auto-expire after 5 seconds of inactivity // Start typing indicator sdk.sendTypingStart('mytoken'); // Stop typing indicator (or wait for auto-expire) sdk.sendTypingStop('mytoken'); // Handle typing events from other users await sdk.connectStreamWebSocket({ onTypingIndicator: (event) => { // event.typingUsers: TypingUser[] // Each user has: userAddress, fullName, profileImage? const names = event.typingUsers.map(u => u.fullName); if (names.length === 0) { console.log('No one is typing'); } else if (names.length === 1) { console.log(`${names[0]} is typing...`); } else if (names.length === 2) { console.log(`${names[0]} and ${names[1]} are typing...`); } else { console.log('Several people are typing...'); } } }); ``` **Streaming & Chat Demos (a selection; `npm run demo:list` shows all):** - `npm run demo:streaming` - Basic stream management - `npm run demo:streaming:recordings` - Recording management - `npm run demo:streaming:simulcast` - Simulcast target management - `npm run demo:chat` - REST chat operations - `npm run demo:chat:websocket` - WebSocket real-time chat - `npm run demo:chat:typing-indicators` - Typing indicator demo --- ## Utilities ### Portfolio & Balances ```typescript const sdk = createLaunchpadSDK({ env: 'prod' }); // GALA balance const galaBalance = await sdk.fetchGalaBalance('eth|...'); console.log(`GALA: ${galaBalance?.quantity}`); // Tokens you hold const held = await sdk.fetchTokensHeld({ address: 'eth|...', search: 'dragon' // Optional: filter by search }); console.log('Tokens held:'); held.tokens.forEach(token => { console.log(` ${token.symbol}: ${token.balance}`); }); ``` ### Token Supply Metrics ```typescript // Query GALA supply information const supplies = await sdk.fetchTokenClassesWithSupply([ { collection: 'GALA', category: 'Unit', type: 'none', additionalKey: 'none' } ]); const gala = supplies[0]; if (gala === undefined) throw new Error('GALA token class not returned'); console.log(`Token: ${gala.symbol} (${gala.name})`); console.log(`Total Supply: ${gala.totalSupply}`); console.log(`Max Supply: ${gala.maxSupply}`); console.log(`Total Burned: ${gala.totalBurned}`); console.log(`Decimals: ${gala.decimals}`); // Calculate health metrics const totalSupply = parseFloat(gala.totalSupply); const maxSupply = parseFloat(gala.maxSupply); const burned = parseFloat(gala.totalBurned); const circulationPercent = (totalSupply / maxSupply) * 100; const burnPercent = (burned / totalSupply) * 100; console.log(`\nCirculation: ${circulationPercent.toFixed(2)}% of max supply`); console.log(`Burned: ${burnPercent.toFixed(2)}% of total supply`); ``` ### Metadata Cache Performance ```typescript // Warm cache by fetching pools console.log('Warming cache...'); await sdk.fetchPools({ type: 'popular', pageSize: 50 }); // Check cache statistics const stats = sdk.getCacheInfo(); console.log(`Cache warmed with ${stats.totalTokens} tokens`); console.log(`Memory: ${(stats.cacheSize / 1024).toFixed(2)} KB`); // 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) { const poolDetails = await sdk.fetchPoolDetailsForCalculation(token); const buy100 = await sdk.calculateBuyAmountLocal({ tokenName: token, amount: '100', type: 'native', currentSupply: poolDetails.currentSupply }); console.log(`${token}: 100 GALA → ${buy100.amount} tokens`); } console.timeEnd('Batch Calculations'); // Output: Batch Calculations: ~50ms (vs ~2000ms without cache) ``` **Utility Demos:** - `npm run demo:cache` - Metadata cache warming and performance - `npm run demo:token-supply` - Token supply metrics from GalaChain - `npm run demo:utilities:balance` - Single token balance check - `npm run demo:utilities:multi-token-portfolio` - Multi-token portfolio - `npm run demo:utilities:trade-history` - Trade history Wallet balances and price history on the DEX are gswap-sdk's (`src/assets/balances.ts`, `src/market/price-history.ts` in its demos). --- ## Error Handling Common error patterns and solutions. ### Wallet Requirements ```typescript import { ValidationError } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'prod' }); // No wallet configured try { await sdk.buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: '1' }); } catch (error) { if (error instanceof ValidationError && error.code === 'WALLET_REQUIRED') { console.log('This operation requires a wallet'); console.log('Configure wallet: sdk.setWallet(privateKey)'); } } ``` ### Slippage Protection ```typescript try { const quote = await sdk.calculateBuyAmount({ tokenName: 'anime', amount: '1000', type: 'native' }); await sdk.buy({ tokenName: 'anime', amount: '1000', type: 'native', expectedAmount: quote.amount, slippageToleranceFactor: 0.01 }); } catch (error) { if (error instanceof Error && error.message.includes('slippage')) { console.log('Price moved beyond slippage tolerance'); console.log('Increase slippage or retry with a fresh quote'); } } ``` --- ## More Examples See the `examples/` directory for the working demos by category (`examples/README.md` lists them); `npm run demo:list` browses them. DEX demos live in `packages/gswap-sdk/examples/demos`. For migration from old demo structure, see `docs/DEMO_MIGRATION_GUIDE.md` in the package. --- # Migrating from launchpad-sdk 8.1.0 to 9.0.0-rc.4 Generated by `scripts/generate-migration-doc.ts` from the built declarations of the published `@gala-chain/launchpad-sdk@8.1.0` tarball and of this build (do not edit by hand). launchpad-sdk 9.0 is launchpad-only. Gateway-generic GalaChain pieces (signing, signers, the token reads and writes, wallet helpers, wallet providers, React hooks, the bridge) are `@gala-chain/gala-core-sdk`'s, a peer dependency: install it beside launchpad-sdk. The DEX (swap backend: quotes, swaps, pools, positions, market prices and price series, leaderboards) is `@gala-chain/gswap-sdk`'s: launchpad-sdk no longer depends on it; an app that needs both builds both clients. See CHANGELOG.md for behaviour changes. ## `@gala-chain/launchpad-sdk` | Removed export | Kind | Now | | --- | --- | --- | | `AuthenticatedEvent` | type | removed: the wire payload is `StreamChatAuthenticatedEvent` (`RealtimeEventPayloads['authenticated']`) | | `BaseBridgeStrategy` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BaseContentItem` | type | removed: `Message`: the item `GET /v1/messages` lists (`id` and `messageId`, `user`, `reactions: { counts, userReacted? }`) | | `BaseTokenCrossRate` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BRIDGE_CONTRACT_ABI` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BRIDGE_TOKEN_METADATA` | value | `STATIC_TOKEN_METADATA` from `@gala-chain/gala-core-sdk/bridge` | | `BridgeableNetwork` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeableToken` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeConfig` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeConfigurationToken` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeFeeEstimate` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeFeeResponse` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeInParams` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeLegResult` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeOutParams` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeRateLimiter` | value | `RateLimiter` from `@gala-chain/gala-core-sdk/bridge` | | `BridgeRequestDto` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeStatus` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeStatusCode` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeStatusResponse` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeStrategy` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeToken` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeTokenDescriptor` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeTokenInstance` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeTokenOutResponse` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeTransaction` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `BridgeTransactionRegistrationResponse` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `CHAIN_IDS` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `ChainResult` | type | removed: `sdk.tokens` (TokenWrites) is gone: `transferToken` / `burnTokens` / `lockTokens` / `unlockTokens` return receipts | | `ChatMessageItem` | type | removed: `Message` for a listed chat message; `SentChatMessage` / `EditedChatMessage` for what `sendChatMessage` / `updateChatMessage` answer | | `ChatStatusChangedEvent` | type | removed: the wire payload is `StreamChatStatusEvent` (`RealtimeEventPayloads['CHAT_STATUS_CHANGED']`) | | `CommentData` | type | removed: the shape of the removed `/v1/comments` route: a listed comment is `Message`, a written one `WrittenComment` | | `CommentItem` | type | removed: `Message` for a listed comment; `WrittenComment` for what `createComment` / `updateComment` answer | | `compareAmounts` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `ConnectionEvent` | type | removed: the wire payload is `ConnectionGreetingEvent` (`RealtimeEventPayloads['connection']`) | | `createProviderFromEip1193` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `createProviderFromWallet` | value | `PrivateKeyProvider` from `@gala-chain/gala-core-sdk/providers` (`PrivateKeyProvider.fromWallet(wallet)`) | | `createSolanaWallet` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `createWallet` | value | same name, from `@gala-chain/gala-core-sdk` | | `createWalletProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `CROSS_RATE_TYPED_DATA_TYPES` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DEFAULT_ETHEREUM_BRIDGE_CONTRACT` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DEFAULT_ETHEREUM_RPC_URL` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DEFAULT_ETHEREUM_TOKENS` | value | `ETHEREUM_TOKENS_PROD` from `@gala-chain/gala-core-sdk/bridge` | | `DEFAULT_POLL_INTERVAL_MS` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DEFAULT_POLL_TIMEOUT_MS` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DEFAULT_RATE_LIMIT_RPS` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DEFAULT_SOLANA_BRIDGE_PROGRAM` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DEFAULT_SOLANA_RPC_URL` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DEFAULT_SOLANA_TOKENS` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DeleteCommentOptions` | type | removed: the removed `/v1/comments` route: `deleteComment(messageId)` | | `DestinationChainTxFee` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `DetectedWallet` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `detectWallets` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `DexAggregatedVolumeSummary` | type | `VolumeSummary` from `@gala-chain/gswap-sdk` | | `DexSeason` | type | `LeaderboardSeason` from `@gala-chain/gswap-sdk` | | `Eip1193Provider` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `Eip6963AnnounceProviderEvent` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `Eip6963ProviderDetail` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `Eip6963ProviderInfo` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `EIP712Domain` | type | `EIP712DomainValue` from `@gala-chain/gala-core-sdk` | | `EIP712TypeField` | type | removed: one field of gala-core-sdk's `EIP712Types` (`EIP712Types[string][number]`) | | `EIP712Types` | type | same name, from `@gala-chain/gala-core-sdk` | | `EngagementStatsData` | type | removed: `fetchTokenStats` returns `TokenStatsData`: `{ holdersCount, chatMessageCount, commentCount, roomCount }`, what the backend sends | | `ensureConnected` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `ERC20_ABI` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `EstimateBridgeFeeParams` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `ETHEREUM_BRIDGE_CONTRACT_SEPOLIA` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `ETHEREUM_TOKENS_PROD` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `ETHEREUM_TOKENS_STAGE` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `EthereumBridgeConfig` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `EthereumBridgeStrategy` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `EthereumTokenConfig` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `EthereumTransactionStatus` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `EthereumWalletBalanceResult` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `ExternalChainBalance` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `ExternalNetwork` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `ExternalTokenInfo` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `ExternalWalletProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `FetchBalancesResponse` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `FetchBridgeableTokensOptions` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `FetchBridgeableTokensResult` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `FetchCommentsOptions` | type | removed: the removed `/v1/comments` route: `GetCommentsOptions` | | `FetchCommentsResult` | type | removed: the removed `/v1/comments` route: `CommentsResult` | | `FetchPriceHistoryOptions` | type | `PriceSeriesTimeframe` from `@gala-chain/gswap-sdk` (`getPriceSeries(token, timeframe)`) | | `FetchWrappableTokensOptions` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `FetchWrappableTokensResult` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `formatTokenAmount` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `formatTokenDescriptor` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `fromBaseUnits` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GALA_BRIDGE_TYPED_DATA_DOMAIN` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GALA_TOKEN_CLASS_KEY` | value | same name, from `@gala-chain/gala-core-sdk` | | `GALACHAIN_CHANNELS` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GalaChainChannel` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GalaChainSigner` | type | same name, from `@gala-chain/gala-core-sdk` | | `GALACONNECT_PRODUCTION_URL` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GalaConnectClient` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GalaConnectConfig` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GalaConnectHttpError` | value | `GalaSDKError` from `@gala-chain/gala-core-sdk` (code `GALACONNECT_HTTP_ERROR` (`isGalaError(error, code)`)) | | `GalaExchangeCrossRate` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GalaExchangeRate` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GeneratedSolanaWallet` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `generateEIP712Types` | value | same name, from `@gala-chain/gala-core-sdk` | | `generateUniqueKey` | value | `createUniqueKey` from `@gala-chain/gala-core-sdk` (`createUniqueKey('galaconnect-operation-')` (``)) | | `getEnv` | value | removed: demo tooling: read `process.env` (and load `.env` with dotenv) in the app | | `getEnvOrThrow` | value | removed: demo tooling: read `process.env` (and load `.env` with dotenv) in the app | | `getEthereumAddressFromPrivateKey` | value | same name, from `@gala-chain/gala-core-sdk` | | `getEthereumBridgeContractByEnvironment` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `getEthereumTokenConfig` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `getEthereumTokensByEnvironment` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `getGalaBridgeTypedDataTypes` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `getInjectedEip1193Provider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `getPublicKeyFromPrivateKey` | value | same name, from `@gala-chain/gala-core-sdk` | | `getSolanaTokenConfig` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `getStaticTokenMetadata` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `getWalletByRdns` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `GetWrappableTokenOptions` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `GlobalFeedEvent` | type | removed: the global feed delivers the token-room payload types: `RealtimeEventPayloads`; `FeedTokenEvent` names each occurrence | | `GlobalFeedEventType` | type | removed: the feed events are the wire names (`FeedEventName`), not lowercase discriminators | | `GlobalFeedSiteConfigEvent` | type | removed: `SiteConfigChangedEvent` / `FeatureGlobalStatusEvent` | | `GlobalFeedSiteConfigEventType` | type | removed: the feed events are the wire names (`FeedEventName`) | | `GlobalFeedStatsUpdatedEvent` | type | removed: `StatsUpdatedEvent` | | `GlobalFeedSubscriptionOptions` | type | removed: `subscribeToGlobalFeed(callbacks)` returns an unsubscribe; there are no options | | `GlobalFeedTokenConfigUpdatedEvent` | type | removed: `TokenConfigUpdatedEvent` | | `GlobalFeedTokenEvent` | type | removed: `FeedTokenEvent`: `{ event, data }`, named by the wire event | | `GlobalFeedTokenEventType` | type | removed: the feed events are the wire names (`FeedTokenEventName`) | | `GSwap` | value | same name, from `@gala-chain/gswap-sdk` | | `hasAnyWallet` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `HttpRequestor` | type | same name, from `@gala-chain/gala-core-sdk` | | `isChatMessageItem` | value | removed: `isMessage` | | `isEip1193Provider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `isExternalProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `isPrivateKeyProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `isStreamingEvent` | value | removed: `StreamingEventService` is deleted (nothing fed it) | | `IsTokenBridgeableOptions` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `IsTokenBridgeableResult` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `IsTokenWrappableResult` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `isValidGalaChainChannel` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `isWalletAvailable` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `KNOWN_WALLET_RDNS` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `LeaderboardEntry` | type | same name, from `@gala-chain/gswap-sdk` | | `LeaderboardResult` | type | `SeasonLeaderboard` from `@gala-chain/gswap-sdk` | | `LEGACY_TYPED_DATA_TYPES` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `loadEnvWithFallback` | value | removed: demo tooling: load `.env` with dotenv in the app | | `LockInput` | type | removed: `sdk.tokens` (TokenWrites) is gone: `sdk.lockTokens({ tokens: [...] })` | | `MasteryTitle` | type | same name, from `@gala-chain/gswap-sdk` | | `ModeratedTokenInviteScope` | type | removed: `InviteScope` | | `PostCommentOptions` | type | removed: the removed `/v1/comments` route: `CreateCommentOptions` | | `PostCommentResult` | type | removed: the removed `/v1/comments` route: `CreateCommentResult` | | `PriceHistoryResult` | type | `PriceSeries` from `@gala-chain/gswap-sdk` (`gSwap.market.getPriceSeries(token, timeframe)` answers the whole series) | | `PriceSnapshot` | type | `PriceSeriesPoint` from `@gala-chain/gswap-sdk` | | `PriceSortOrder` | type | `PriceSeriesTimeframe` from `@gala-chain/gswap-sdk` (a series comes oldest first; sort it yourself) | | `PrivateKeyProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `providerToWallet` | value | removed: `isPrivateKeyProvider(p) ? new Wallet(p.exportPrivateKey()) : undefined` (ethers stays the app's) | | `PublicKeyResult` | type | same name, from `@gala-chain/gala-core-sdk` | | `QuoteTokenCrossRate` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `RecordingStatusChangedEvent` | type | removed: the wire payload is `RecordingStatusEvent` | | `RequestBridgeOutResponse` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `RoomLeftEvent` | type | removed: the wire payload is `RoomAckEvent` | | `RoomSubscribedEvent` | type | removed: the wire payload is `RoomAckEvent` | | `SimulcastStatusChangedEvent` | type | removed: the wire payload is `SimulcastStatusEvent` | | `SOLANA_COMPUTE` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `SOLANA_DISCRIMINATORS` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `SolanaBridgeConfig` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `SolanaBridgeStrategy` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `SolanaTokenConfig` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `SolanaTransactionStatus` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `SolanaWalletBalanceResult` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `StreamCountdownUpdatedEvent` | type | removed: the wire payload is `StreamCountdownEvent` | | `StreamingEvent` | type | removed: `StreamingEventService` is deleted (nothing fed it): `RealtimeEventPayloads` types every event the socket delivers | | `StreamingEventCallback` | type | removed: `StreamingEventService` is deleted (nothing fed it): a subscriber is `RealtimeListener<'EVENT_NAME'>` | | `StreamingEventRegistry` | type | removed: `StreamingEventService` is deleted (nothing fed it): `StreamWebSocketService` keeps the one registry of subscribers | | `StreamingEventService` | value | removed: nothing fed it. The `LaunchpadSDK.on*` methods and `sdk.realtime.subscribe*` are subscribers of the `StreamWebSocketService` registry | | `StreamLanguageUpdatedEvent` | type | removed: the wire payload is `StreamLanguageEvent` | | `StreamStatusChangedEvent` | type | removed: the wire payload is `StreamStatusEvent` | | `stripHexPrefix` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `subscribeToWalletChanges` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `toBaseUnits` | value | same name, from `@gala-chain/gala-core-sdk/bridge` | | `TokenAmountInput` | type | removed: `sdk.tokens` (TokenWrites) is gone | | `TokenBalanceEntry` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `TokenClassKey` | type | `GalaChainTokenClassKey` from `@gala-chain/gala-core-sdk` | | `TokenClassWithSupply` | type | `GalaChainTokenClass` from `@gala-chain/gala-core-sdk` | | `TokenHold` | type | `GalaChainTokenHold` from `@gala-chain/gala-core-sdk` | | `tokenHoldSchema` | value | removed: the zod schema of a hold; holds are `GalaChainTokenHold` (gala-core-sdk) and core checks them | | `TokenIdentifier` | type | removed: `sdk.tokens` (TokenWrites) is gone: a token is a `TokenId` | | `TokenInstanceKey` | type | `GalaChainTokenInstanceKey` from `@gala-chain/gala-core-sdk` | | `TokenRoundTripResult` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `TokenSubscribedEvent` | type | removed: the wire payload is `StreamSubscribedEvent` | | `TokenUnsubscribedEvent` | type | removed: the wire payload is `StreamUnsubscribedEvent` | | `TokenWrites` | value | removed: `sdk.tokens` is gone: `transferToken` / `burnTokens` / `lockTokens` / `unlockTokens`; or `GatewayWrites` (gala-core-sdk) | | `TRADES_QUERY_CONSTRAINTS` | value | removed: a deprecated composite: `TOKEN_NAME_DTO_CONSTRAINT` for the token name | | `TradesListResult` | type | removed: `TradesQueryResult`: the `{ trades, pageInfo }` `getTrades` returns | | `TransferInput` | type | removed: `sdk.tokens` (TokenWrites) is gone: `sdk.transferToken({ to, tokenId, amount })` | | `TypedDataDomain` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `TypedDataField` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `UnwrapTokenOptions` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `UserTypingEvent` | type | removed: the wire payload is `TypingIndicatorEvent` | | `ViewerCountChangedEvent` | type | removed: the wire payload is `ViewerCountEvent` | | `WaitForBridgeOptions` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `WaitOptions` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `WalletConnectionState` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletDetectionResult` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletProvider` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletProviderConfig` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletProviderType` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `walletToProvider` | value | `PrivateKeyProvider` from `@gala-chain/gala-core-sdk/providers` (`PrivateKeyProvider.fromWallet(wallet)`) | | `WrappableToken` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `WrappableTokenApiResponse` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `WrappableTokenCacheStats` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `WrappableTokenPrices` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `WrapTokenOptions` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `WrapUnwrapFeeEstimate` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `WrapUnwrapResult` | type | same name, from `@gala-chain/gala-core-sdk/bridge` | | `WrapUnwrapStatus` | type | removed: a wrap resolves only once completed (`WrapUnwrapResult`); there is no status read | | `WrapUnwrapStatusResult` | type | removed: a wrap resolves only once completed (`WrapUnwrapResult`); there is no status read | ## `@gala-chain/launchpad-sdk/native` | Removed export | Kind | Now | | --- | --- | --- | | `createWallet` | value | same name, from `@gala-chain/gala-core-sdk` | | `EIP712Domain` | type | `EIP712DomainValue` from `@gala-chain/gala-core-sdk` | | `EIP712TypeField` | type | removed: one field of gala-core-sdk's `EIP712Types` (`EIP712Types[string][number]`) | | `EIP712Types` | type | same name, from `@gala-chain/gala-core-sdk` | | `GalaChainSigner` | type | same name, from `@gala-chain/gala-core-sdk` | | `generateEIP712Types` | value | same name, from `@gala-chain/gala-core-sdk` | | `getEthereumAddressFromPrivateKey` | value | same name, from `@gala-chain/gala-core-sdk` | | `getPublicKeyFromPrivateKey` | value | same name, from `@gala-chain/gala-core-sdk` | | `PublicKeyResult` | type | same name, from `@gala-chain/gala-core-sdk` | | `TokenClassKey` | type | `GalaChainTokenClassKey` from `@gala-chain/gala-core-sdk` | ## `@gala-chain/launchpad-sdk/wallet` This entry point is REMOVED (34 exports). | Removed export | Kind | Now | | --- | --- | --- | | `createProviderFromEip1193` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `createProviderFromWallet` | value | `PrivateKeyProvider` from `@gala-chain/gala-core-sdk/providers` (`PrivateKeyProvider.fromWallet(wallet)`) | | `createWalletProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `DetectedWallet` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `detectWallets` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `Eip1193Provider` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `Eip6963AnnounceProviderEvent` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `Eip6963ProviderDetail` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `Eip6963ProviderInfo` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `ensureConnected` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `ExternalWalletProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `GalaWalletProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `getInjectedEip1193Provider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `getPrivateKeyIfAvailable` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `getWalletByRdns` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `hasAnyWallet` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `isEip1193Provider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `isExternalProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `isPrivateKeyProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `isWalletAvailable` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `KNOWN_WALLET_RDNS` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `PrivateKeyProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `providerToWallet` | value | removed: `isPrivateKeyProvider(p) ? new Wallet(p.exportPrivateKey()) : undefined` (ethers stays the app's) | | `subscribeToWalletChanges` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `TypedDataDomain` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `TypedDataField` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletConnectionState` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletDetectionResult` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletProvider` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletProviderConfig` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletProviderError` | value | `GalaSDKError` from `@gala-chain/gala-core-sdk` (`isGalaError(error, code)` with the wallet codes) | | `WalletProviderErrorCode` | value | `GalaErrorCode` from `@gala-chain/gala-core-sdk` (the wallet codes (`WALLET_NOT_CONNECTED`, ...)) | | `WalletProviderType` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `walletToProvider` | value | `PrivateKeyProvider` from `@gala-chain/gala-core-sdk/providers` (`PrivateKeyProvider.fromWallet(wallet)`) | ## `@gala-chain/launchpad-sdk/react` This entry point is REMOVED (25 exports). | Removed export | Kind | Now | | --- | --- | --- | | `ConnectionStatus` | type | same name, from `@gala-chain/gala-core-sdk/react` | | `DetectedWallet` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `detectWallets` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `Eip6963ProviderInfo` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `ExternalWalletProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `KNOWN_WALLET_RDNS` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `PrivateKeyProvider` | value | same name, from `@gala-chain/gala-core-sdk/providers` | | `useGalaAddress` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `useIsWalletConnected` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `useWallet` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `useWalletAddress` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `useWalletConnection` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `UseWalletConnectionReturn` | type | same name, from `@gala-chain/gala-core-sdk/react` | | `useWalletContext` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `useWalletDetection` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `UseWalletDetectionReturn` | type | same name, from `@gala-chain/gala-core-sdk/react` | | `useWalletProvider` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `WalletConnectionState` | type | same name, from `@gala-chain/gala-core-sdk/providers` | | `WalletContext` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `WalletContextActions` | type | same name, from `@gala-chain/gala-core-sdk/react` | | `WalletContextState` | type | same name, from `@gala-chain/gala-core-sdk/react` | | `WalletContextValue` | type | same name, from `@gala-chain/gala-core-sdk/react` | | `WalletProvider` | value | same name, from `@gala-chain/gala-core-sdk/react` | | `WalletProviderInterface` | type | `WalletProvider` from `@gala-chain/gala-core-sdk/providers` | | `WalletProviderProps` | type | same name, from `@gala-chain/gala-core-sdk/react` | ## Removed `LaunchpadSDK` members | Member | Now | | --- | --- | | `dex` | gswap-sdk's own client: `new GSwap({ env, signer, walletAddress })` | | `fetchAllDexSeasons` | gswap-sdk `gSwap.leaderboard.getSeasons()` | | `fetchAllPriceHistory` | gswap-sdk `gSwap.market.getPriceSeries(key, timeframe)` (one read answers the whole series) | | `fetchCurrentDexLeaderboard` | gswap-sdk `gSwap.leaderboard.getCurrentLeaderboard()` | | `fetchCurrentDexSeason` | gswap-sdk `gSwap.leaderboard.getCurrentSeason()` | | `fetchDexAggregatedVolumeSummary` | gswap-sdk `gSwap.market.getVolumeSummary()` | | `fetchDexLeaderboardBySeasonId` | gswap-sdk `gSwap.leaderboard.getLeaderboard(seasonId)` | | `fetchGalaPrice` | gswap-sdk `gSwap.market.getPrice('GALA\|Unit\|none\|none')` | | `fetchPriceHistory` | gswap-sdk `gSwap.market.getPriceSeries(await sdk.resolveTokenClassKey(name), timeframe)` | | `getWrapStatus` | none: a wrap resolves only once completed | | `onDexPoolCreation` | gswap-sdk `gSwap.pools.watchNewPools(onPool, { minTvl })` | | `tokens` | `transferToken`, `burnTokens`, `lockTokens`, `unlockTokens` (or gala-core-sdk `GatewayWrites`) | ## Changed `LaunchpadSDK` members - `fetchTokenPrice(params)` takes `{ tokenName }` only (a launchpad token: bonding curve, or the swap backend once graduated). A token by class key is gswap-sdk's `gSwap.market.getPrice(tokenId)`; a `tokenId` is refused with a `ValidationError`. - `getSupportedBridgeTokens()` is `async` (it returned a Promise already). --- # 🤖 Gala Launchpad SDK - AI Agent Integration Guide > **Comprehensive guide for AI agents to understand, integrate, and build upon the Gala Launchpad SDK** **SDK Version**: 9.0.0 (launchpad-only; 343 public instance methods, counted from the `LaunchpadSDK` class body) **MCP Server**: `@gala-chain/gala-mcp-server` (tool catalog in its README; `GALA_TOOLSETS=core,launchpad` selects the launchpad tools) **Target Audience**: AI agents, MCP servers, automation tools, trading bots --- ## 📖 Table of Contents 1. [Quick Start for AI Agents](#quick-start-for-ai-agents) 2. [SDK Architecture Overview](#sdk-architecture-overview) 3. [Complete Method Catalog](#complete-method-catalog) 4. [Common AI Agent Workflows](#common-ai-agent-workflows) 5. [Type Reference for Code Generation](#type-reference-for-code-generation) 6. [Error Handling Patterns](#error-handling-patterns) 7. [Best Practices for Agent Implementation](#best-practices-for-agent-implementation) 8. [Example MCP Tool Schemas](#example-mcp-tool-schemas) 9. [Environment Configuration](#environment-configuration) 10. [Testing and Validation](#testing-and-validation) --- ## Quick Start for AI Agents ### Minimal Setup (3 Lines) ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; const { sdk, validation } = await AgentConfig.quickSetup(); console.log(`Agent ready: ${validation?.ready}`); ``` ### What Just Happened? 1. **Auto-detected environment** from `LAUNCHPAD_ENV` or `ENVIRONMENT` (`stage` or `prod`), defaulting to `prod` 2. **Created or imported wallet** from `process.env.PRIVATE_KEY` or generated new one 3. **Configured SDK** with appropriate timeouts and debug settings 4. **Validated setup** including balance checks and connectivity tests 5. **Ready for operations** with full error context if something failed `quickSetup` resolves to `{ sdk, wallet, config, validation? }`: `wallet` is the `AgentWallet` (gala-core-sdk's generated wallet plus an ethers `Wallet`), `config` the resolved `LaunchpadSDKConfig`, and `validation` a `SetupValidation` that is present unless you pass `autoValidate: false`. It is `{ ready, sdk, wallet, issues: string[], warnings: string[], capabilities: { canTrade (balance >= 0.1 GALA), canCreateTokens (balance >= 100 GALA), hasBalance, connectionHealthy } }`. `AgentConfig.readOnlySetup()` builds a wallet-less SDK, and `multiWalletSetup(wallets, environment = 'stage')` returns `Record` with validation skipped. ### Complete Setup with Options ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; const { sdk, wallet, config, validation } = await AgentConfig.quickSetup({ environment: 'prod', privateKey: process.env.TRADING_WALLET_KEY!, timeout: 60000, debug: false, agentId: 'my-trading-bot-v1', autoValidate: true }); // Check capabilities before proceeding if (validation === undefined || !validation.ready) { console.error('Setup issues:', validation?.issues); process.exit(1); } if (!validation.capabilities.canTrade) { console.warn('Insufficient balance for trading:', validation.warnings); } // All good - start trading! const pools = await sdk.fetchPools({ type: 'recent', pageSize: 10 }); ``` ### Read-Only Mode Setup (No Wallet Required) For data analysis, monitoring, and query-only operations, you don't need a wallet configured. This reduces startup time and enables read-only agents without wallet secrets: ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; // Read-only mode: readOnlySetup builds an SDK with no wallet (it resolves to { sdk, config }). // quickSetup without a privateKey does NOT do this: it falls back to PRIVATE_KEY or generates a wallet. const { sdk } = await AgentConfig.readOnlySetup({ environment: 'prod', timeout: 30000, debug: false, agentId: 'market-monitor-agent' }); // All query operations work fine const pools = await sdk.fetchPools({ type: 'recent', pageSize: 10 }); const price = await sdk.fetchTokenPrice({ tokenName: 'anime' }); const distribution = await sdk.fetchTokenDistribution('anime'); // ❌ This will throw ValidationError('WALLET_REQUIRED') try { await sdk.buy({ tokenName: 'anime', amount: '1', type: 'native', expectedAmount: '100', slippageToleranceFactor: 0.01 }); } catch (error) { console.error('Cannot trade without wallet:', error instanceof Error ? error.message : error); } ``` **Read-Only vs Full-Access Comparison:** ```typescript // ✅ READ-ONLY MODE (No wallet, no secrets needed) const readOnly = await AgentConfig.readOnlySetup({ environment: 'prod', agentId: 'data-analyzer' // No wallet is created - safe for untrusted environments }); // ✅ Available methods in read-only: await readOnly.sdk.fetchPools({ type: 'recent' }); // ✅ Works await readOnly.sdk.fetchPoolDetails('anime'); // ✅ Works await readOnly.sdk.fetchTokenPrice({ tokenName: 'anime' }); // ✅ Works await readOnly.sdk.fetchTokenDistribution('anime'); // ✅ Works await readOnly.sdk.fetchGalaBalance('eth|...'); // ✅ Works await readOnly.sdk.getComments({ tokenName: 'anime' }); // ✅ Works // ❌ Operations requiring wallet: await readOnly.sdk.buy(buyOptions); // ❌ Throws await readOnly.sdk.sell(sellOptions); // ❌ Throws await readOnly.sdk.transferGala(transferOptions); // ❌ Throws await readOnly.sdk.createComment(commentOptions); // ❌ Throws // ✅ FULL-ACCESS MODE (With wallet for signing operations) const fullAccess = await AgentConfig.quickSetup({ environment: 'prod', privateKey: process.env.PRIVATE_KEY!, // Now we have signing capability agentId: 'trading-bot' }); // ✅ Available methods in full-access: await fullAccess.sdk.fetchPools({ type: 'recent' }); // ✅ Works await fullAccess.sdk.buy(buyOptions); // ✅ Works await fullAccess.sdk.transferGala(transferOptions); // ✅ Works await fullAccess.sdk.createComment(commentOptions); // ✅ Works ``` ### Dynamic Wallet Configuration (Upgrade from Read-Only) You can start in read-only mode and upgrade to full-access dynamically when needed: ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; import { Wallet } from 'ethers'; // Start with read-only capability const { sdk } = await AgentConfig.readOnlySetup({ environment: 'prod', agentId: 'adaptive-agent' // No wallet yet }); // Check if wallet is available console.log(`Has wallet: ${sdk.hasWallet()}`); // false // Perform read-only operations const pools = await sdk.fetchPools({ type: 'recent', pageSize: 10 }); console.log(`Found ${pools.items.length} pools`); // Later, upgrade to full-access (e.g., triggered by user input or logic) const shouldTrade = process.env.TRADING_WALLET_KEY !== undefined; if (shouldTrade) { sdk.setWallet(new Wallet(process.env.TRADING_WALLET_KEY!)); console.log(`Wallet configured: ${sdk.hasWallet()}`); // true // Now trading operations work const quote = await sdk.calculateBuyAmount({ tokenName: 'anime', amount: '10', type: 'native' }); const result = await sdk.buy({ tokenName: 'anime', amount: '10', type: 'native', expectedAmount: quote.amount, slippageToleranceFactor: 0.01 }); console.log(`Trade executed: ${result.transactionId}`); } sdk.cleanup(); ``` **Key Points:** - ✅ **Start Simple**: Initialize without wallet for read-only operations - ✅ **Flexible**: Add wallet later with `setWallet()` when needed - ✅ **Type-Safe**: `validateWallet()` checks before signing operations - ✅ **No Secrets**: Read-only agents don't expose private keys - ✅ **Progressive Enhancement**: Begin with queries, add trading capability later --- ## SDK Architecture Overview ### Service-Based Backend Alignment The SDK internally uses 5 backend-aligned services (you don't interact with these directly): 1. **LaunchpadService** → `https://lpad-backend-{env}.defi.gala.com` - Pool management, trade history, comments, profiles 2. **GalaChainService** → `https://galachain-gateway-{env}.galachain.com` - Balances, transfers, blockchain operations 3. **Swap backend** (`dexBackendBaseUrl`) → the `stage` preset, prod `https://dex-backend-prod1.defi.gala.com` - Read-only: `LaunchpadPriceService` reads `GET /market/price` for the USD price of a launchpad token (`fetchTokenPrice`). DEX quotes, pools, positions and market data are gswap-sdk's, not this SDK's 4. **BundleService** → `https://bundle-backend-{env}.defi.gala.com` - Token trading, transaction bundling 5. **WebSocketService** → `wss://bundle-backend-{env}.defi.gala.com` - Real-time transaction monitoring ### Flattened Public API **You interact with a single SDK instance** that exposes most methods directly, with one namespaced exception for DEX trading: ```text // No child controllers for launchpad/chain operations - everything on sdk.* sdk.fetchPools(...) // Pool operations sdk.buy(...) // Trading operations sdk.fetchGalaBalance(...) // Balance queries sdk.createComment(...) // Social features sdk.transferGala(...) // Token transfers // GSwap DEX trading is gswap-sdk's own client (launchpad-sdk has none): // const gSwap = new GSwap({ env, signer: new PrivateKeySigner(key), walletAddress: sdk.getAddress() }); gSwap.pools.getPools(...) // Pool discovery gSwap.quoting.quoteExactInput(...) // Swap quotes gSwap.swaps.swap(...) // Queued swap submission ``` **This flattened design simplifies agent implementation for launchpad/chain operations** - no need to navigate controller hierarchies. DEX trading, quoting, positions, symbols, assets, market data and the trading competition live in `@gala-chain/gswap-sdk`'s `GSwap` client (`gSwap.*`), which you build with the same key. --- ## Complete Method Catalog > **Note**: This section covers a core subset of methods across eight categories. The `LaunchpadSDK` class has 343 public instance methods (plus the `events` and `realtime` getters and the static `cleanupAll`), counted from the class body of the built `dist/LaunchpadSDK.d.ts`: every method declared in the class that is not `private`/`protected`/`static`. They also cover bridging, streaming, chat, session auth and more. GSwap DEX trading is gswap-sdk's `GSwap` client (`gSwap.*`), not part of this SDK. See the [API Reference](/launchpad-sdk/next/api-reference.md) for the complete list. ### Category 1: Pool Management #### `fetchPools(options?): Promise` Fetch token pools with filtering and pagination. **Options**: ```text { type?: 'recent' | 'popular' | 'recordings' | 'seconds_streamed', tokenName?: string, // Exact match search?: string, // Fuzzy search hasUpcomingShows?: boolean, language?: string, recentlyStreamed?: number, hasRecordings?: boolean, streamStatus?: 'idle' | 'active' | 'disabled', isGraduated?: boolean, // true = graduated, false = still on the curve (both sent) creatorAddress?: string, // 'eth|<40 hex>' or 'client|<24 hex>' cursor?: string, // Omit for the first page pageSize?: number // Cursor-based pagination } ``` **Returns** (`ListResult`): ```text { items: PoolData[], pageInfo: { hasNextPage: boolean, endCursor?: string | null, hasPreviousPage?: boolean, startCursor?: string | null, totalCount?: number // fetchAll... results only } } ``` `PoolData` carries `id`, `tokenName`, `symbol`, `description`, `amount`, `creatorAddress`, `vaultAddress`, `createdAt` (string), `image`, the social URLs, and optional reverse bonding curve fee fields. **Usage**: ```typescript const recent = await sdk.fetchPools({ type: 'recent', pageSize: 10 }); console.log(`Got ${recent.items.length} pools, more: ${recent.pageInfo.hasNextPage}`); for (const pool of recent.items) { console.log(`${pool.tokenName}: ${pool.symbol}`); } ``` #### `fetchPoolDetails(tokenName: string): Promise` Get detailed pool state directly from GalaChain bonding curve contract. **Returns**: ```text { basePrice: string, euler: string, exponentFactor: string, maxSupply: string, nativeToken: TokenInfo, // GALA nativeTokenQuantity: string, // GALA in the vault sellingToken: TokenInfo, sellingTokenQuantity: string, currentSupply?: string, // maxSupply - sellingTokenQuantity saleOwner: string, saleStatus: string, // e.g. 'ACTIVE', 'PENDING', 'COMPLETED' saleStartTime?: number, // Unix seconds isGraduated: boolean, // saleStatus === 'Completed' vaultAddress: string, reverseBondingCurveMinFeePortion: string, reverseBondingCurveMaxFeePortion: string, reverseBondingCurveConfiguration?: { minFeePortion: string, maxFeePortion: string }, hasReverseBondingCurveFee: boolean, reverseBondingCurveMinFeeFactor?: number, reverseBondingCurveMaxFeeFactor?: number, reverseBondingCurveNetFeeFactor?: number } ``` **Usage**: ```typescript const details = await sdk.fetchPoolDetails('dragnrkti'); console.log(`Sale status: ${details.saleStatus}, graduated: ${details.isGraduated}`); console.log(`Current supply: ${details.currentSupply} / ${details.maxSupply}`); console.log(`GALA in vault: ${details.nativeTokenQuantity}`); ``` #### `fetchTokenDistribution(tokenName: string): Promise` Get holder distribution and supply metrics. **Returns**: ```text { holders: Array<{ address: string, balance: string, // Decimal string percentage: number // 0-100 of total supply }>, totalSupply: string, totalHolders: number, lastUpdated: Date } ``` #### `fetchVolumeData(options): Promise` Get time-series graph data points for charting. **Options** (`FetchVolumeDataOptions`): ```text { tokenName: string, from?: number, // Start timestamp to?: number, // End timestamp resolution?: number // Resolution in seconds } ``` **Returns** (`GraphDataResult`): ```text { dataPoints: Array<{ timestamp: number, value: number, [key: string]: unknown // Additional metrics }> } ``` #### `isTokenNameAvailable(tokenName: string): Promise` Check if token name is available for creation. **Usage**: ```typescript const available = await sdk.isTokenNameAvailable('mynewtoken'); if (!available) { console.log('Name already taken'); } ``` #### `isTokenSymbolAvailable(symbol: string): Promise` Check if token symbol is available for creation. #### `resolveVaultAddress(tokenName: string): Promise` Get the GalaChain vault address for a token (needed for some operations). **Returns**: `Promise`, a vault address of the form `"service|Token$Unit$SYMBOL$eth:address$launchpad"`, or `null` when none resolves. --- ### Category 2: Trading Operations #### `calculateBuyAmount(options): Promise` Calculate how many tokens you'll receive for a given GALA amount (or vice versa). **Options**: ```text { tokenName: string, amount: string, // Standard decimal format (e.g., "1", "10.5") type: 'native' | 'exact' // 'native' = spending GALA, 'exact' = buying exact tokens } ``` **Returns**: ```text { amount: string, // Calculated amount (opposite of input type) transactionFee: string, // Platform fee in GALA reverseBondingCurveFee: string, // RBC fee in GALA gasFee: string // Gas fee (fixed at 1 GALA) } ``` There is no price-impact field; derive one from `amount` and the input amount if you need it. **Units**: `amount` and every returned amount are decimal strings in whole units: GALA for `'native'`, tokens for `'exact'` (`'10'` is 10 GALA, `'1000'` is 1000 tokens). They are never base units or wei. **Usage**: ```typescript // How many tokens for 10 GALA? const quote = await sdk.calculateBuyAmount({ tokenName: 'dragnrkti', amount: '10', // 10 GALA type: 'native' }); console.log(`You'll receive: ${quote.amount} DRAGNRKTI tokens`); console.log(`Transaction fee: ${quote.transactionFee} GALA`); ``` #### `calculateSellAmount(options): Promise` Calculate how much GALA you'll receive for selling tokens (or how many tokens needed for target GALA). **Same interface as `calculateBuyAmount`** #### `buy(options): Promise` Execute a token purchase via GalaChain. `amount` and `expectedAmount` are decimal strings in whole GALA (`type: 'native'`) or whole tokens (`type: 'exact'`), never base units. **Options**: ```text { tokenName: string, amount: string, type: 'native' | 'exact', expectedAmount: string, // From calculateBuyAmount - REQUIRED slippageToleranceFactor?: number, // Decimal format (0.05 = 5%) - optional maxAcceptableReverseBondingCurveFee?: string, maxAcceptableReverseBondingCurveFeeSlippageFactor?: number, privateKey?: string // Optional per-call key override } ``` **Returns** (`TradeResult`, confirmed over the bundler socket): ```text { transactionId: string, blockHash?: string, gasUsed?: string, timestamp: number, // Confirmation time, number not Date type: 'buy' | 'sell', method: 'native' | 'exact', inputAmount: string, // GALA for buys, tokens for sells outputAmount: string, // Tokens for buys, GALA for sells totalFees: string, tokenName: string, vaultAddress: string, slippageTolerance?: number } ``` **Usage**: ```typescript // Step 1: Get quote const quote = await sdk.calculateBuyAmount({ tokenName: 'dragnrkti', amount: '5', // 5 GALA type: 'native' }); // Step 2: Execute trade with slippage protection const result = await sdk.buy({ tokenName: 'dragnrkti', amount: '5', // 5 GALA, same unit as the quote type: 'native', expectedAmount: quote.amount, // REQUIRED slippageToleranceFactor: 0.05 // 5% slippage }); console.log(`Transaction ID: ${result.transactionId}`); console.log(`Spent ${result.inputAmount} GALA, received ${result.outputAmount} tokens`); ``` #### `sell(options): Promise` Execute a token sale via GalaChain. **Same interface as `buy()`** (`SellTokenOptions`; `type: 'exact' | 'native'`). #### `fetchTrades(options): Promise` Get trade history with filtering. **Options**: ```text { tokenName: string, // Required tradeType?: 'buy' | 'sell', userAddress?: string, cursor?: string, pageSize?: number, startDate?: Date, endDate?: Date, sortOrder?: 'asc' | 'desc' } ``` **Returns** (`ListResult`): ```text { items: Array<{ id: string, userAddress: string, tradeType: 'buy' | 'sell', tokenAmount: string, vaultAddress: string, createdAt: string, updatedAt: string, slippageTolerance?: string, deadline?: number, [key: string]: unknown // Additional trade metadata }>, pageInfo: { hasNextPage, endCursor?, hasPreviousPage?, startCursor?, totalCount? } } ``` --- ### Category 3: Balance & Portfolio #### `fetchGalaBalance(address?: string): Promise` Get GALA balance for a wallet (defaults to SDK wallet). Resolves to `null` when no balance is returned. **Returns** (`TokenBalanceResult`): ```text { quantity: string, // Decimal string in whole GALA (e.g., "100.5") collection: string, // "GALA" category: string, // "Unit" tokenId: string, // "GALA|Unit|none|none" inUseHolds?: GalaChainTokenHold[], lockedHolds?: GalaChainTokenHold[], lockedQuantity?: string, inUseQuantity?: string, availableQuantity?: string // quantity - lockedQuantity - inUseQuantity } ``` **Usage**: ```typescript const balance = await sdk.fetchGalaBalance(); console.log(`Balance: ${balance?.quantity ?? '0'} GALA`); console.log(`Available: ${balance?.availableQuantity}`); ``` #### `fetchTokenBalance(options): Promise` Get a token balance for a wallet. Same result shape as `fetchGalaBalance`. **Options** (`FetchTokenBalanceOptions`): ```text { address: string, // Required: eth|... or 0x... tokenName?: string, // For launchpad tokens tokenId?: TokenId, // string, TokenClassKey or TokenInstanceKey withExpired?: boolean // Include expired holds (default: false) } ``` #### `fetchTokensHeld(options): Promise` Get all tokens held by a wallet. **Options**: ```text { address?: string, // Defaults to the SDK wallet tokenName?: string, // Exact match search?: string, // Fuzzy search cursor?: string, pageSize?: number } ``` **Returns** (`UserTokenListResult`): ```text { tokens: Array<{ id: string, name: string, symbol: string, type: UserTokenType, address: string, balance: string, decimals: number, metadata?: { description?: string, image?: string }, createdAt: string, updatedAt: string }>, pageInfo: PageInfo, total?: number } ``` #### `fetchTokensCreated(options): Promise` Get all tokens created by a wallet. Same options and result as `fetchTokensHeld`. #### `fetchProfile(address?: string): Promise` Get the public profile of an address (defaults to the SDK wallet): `fullName`, `profileImage` and `bio` (each nullable), `stats` (`tokensCreated`, `tokensGraduated`, `graduationRate`, `totalTrades`, `totalVolumeGala`, ...), the four badge ladders (`launchBadge`, `successBadge`, `volumeBadge`, `engagementBadge`, each a `BadgeStatus[]`), `isLiveStreaming` and `liveStreamToken`. An address with no profile row still answers a profile (the name, image and bio are null). --- ### Category 4: Token Creation #### `launchToken(data): Promise` Create a new token on the launchpad. The supply and bonding curve are fixed by the launchpad; you provide identity, optional pre-buy and optional reverse bonding curve fees. **Data** (`LaunchTokenData`): ```text { tokenName: string, // Lowercase, alphanumeric, max 10 chars tokenSymbol: string, // 3-10 chars tokenDescription: string, // Max 500 chars tokenImage?: File | Buffer | string, // File, Buffer or URL string preBuyQuantity?: string, // Whole GALA decimal string, default "0" websiteUrl?: string, telegramUrl?: string, twitterUrl?: string, instagramUrl?: string, facebookUrl?: string, redditUrl?: string, tiktokUrl?: string, reverseBondingCurveConfiguration?: { // Default { minFeePortion: "0.1", maxFeePortion: "0.5" } minFeePortion: string, maxFeePortion: string }, saleStartTime?: number, // Future Unix timestamp in seconds; omit to start immediately privateKey?: string } ``` **Returns** (`TokenLaunchResult`): ```text { transactionId: string, blockHash?: string, gasUsed?: string, timestamp: number, vaultAddress: string, tokenStringKey: string, // Token$Unit$SYMBOL$... tokenName: string, tokenSymbol: string, creatorAddress: string, // eth|... tokenImage?: string, preBuyQuantity?: string } ``` **Usage**: ```typescript const result = await sdk.launchToken({ tokenName: 'mynewtoken', tokenSymbol: 'MNT', tokenDescription: 'My amazing token', tokenImage: 'https://example.com/image.png', preBuyQuantity: '100', // 100 GALA reverseBondingCurveConfiguration: { minFeePortion: '0.1', maxFeePortion: '0.5' } }); console.log(`Token created: ${result.transactionId} (${result.vaultAddress})`); ``` #### `uploadTokenImage(options: UploadImageByTokenNameOptions): Promise` Upload a token image; resolves to the uploaded image URL. Requires a login session, not a wallet. **Options**: ```text { tokenName: string, options: { file: File | Buffer // Browser File or Node.js Buffer }, privateKey?: string // Optional per-call key override ('0x' + 64 hex) } ``` #### `updateProfile(data: UpdateProfileData): Promise` Update user profile. `data` is `{ profileImage: string, fullName: string, address: string, privateKey?: string }`. --- ### Category 5: Comments & Social #### `createComment(options: CreateCommentOptions): Promise` Post a comment on a token pool. Requires a wallet / JWT. **Options**: ```text { tokenName: string, content: string // Max 2000 chars } ``` **Returns**: ```text { comment: WrittenComment // The created comment: numeric id, messageId, content, userAddress, createdAt, updatedAt (no tokenName) } ``` Related: `updateComment(id, { content })`, `deleteComment(id)`, `addReactionToComment(...)`, `removeReactionFromComment(...)`. #### `getComments(options: GetCommentsOptions): Promise` Get comments for a token pool, or by user. At least one of `tokenName` or `userAddress` is required. **Options**: ```text { tokenName?: string, userAddress?: string, // eth|... or 0x... cursor?: string, // Omit for the first page pageSize?: number // Default: 20, max: 50 } ``` **Returns**: ```text { messages: Message[], // id = messageId (string), user, reactions: { counts, userReacted? } pageInfo: PageInfo } ``` --- ### Category 6: Token Transfers #### `transferGala(data: TransferGalaData): Promise` Transfer GALA tokens to another wallet via GalaChain. **Options**: ```text { recipientAddress: string, // Supports 0x... or eth|... format amount: string, // Decimal string in whole GALA (e.g. "0.001", "1.5") uniqueKey?: string, // Optional idempotency key, auto-generated when omitted privateKey?: string // Optional per-call key override } ``` **Returns** (`GalaChainTransferReceipt`): `{ transactionId: string, blockNumber?: number }` **Usage**: ```typescript const result = await sdk.transferGala({ recipientAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0', amount: '1', // 1 GALA uniqueKey: 'galaconnect-operation-my-transfer-123' }); console.log(`Transfer ID: ${result.transactionId}`); ``` #### `transferToken(data: TransferTokenData): Promise` Transfer launchpad tokens to another wallet via GalaChain. **Options**: ```text { to: string, // eth|... or 0x... tokenName?: string, // Or tokenId tokenId?: TokenId, amount: string, // Decimal string in whole tokens uniqueKey?: string, privateKey?: string } ``` **Returns**: `{ transactionId: string, blockNumber?: number }` --- ### Category 7: Token Lock/Unlock #### `lockTokens(data: LockTokensData): Promise` Lock one or more tokens on GalaChain for staking, escrow, or vesting purposes. The batch is a single transaction (all tokens lock or none do); lock parameters (`lockAuthority`, `expires`, `name`) from the first entry that sets them apply to the whole batch. **Options**: ```text { tokens: Array<{ tokenName?: string, // Token to lock (e.g., 'anime'), used when tokenId is absent tokenId?: TokenId, // Or a token id / class key / instance key amount: string, // Amount to lock (standard decimal format) lockAuthority?: string, // Address that can unlock (defaults to caller) expires?: number, // Optional expiration timestamp in milliseconds name?: string // Optional lock name for matching during unlock }>, uniqueKey?: string, // Optional idempotency key (auto-generated) privateKey?: string // Optional per-call key override } ``` **Returns**: ```text { transactionId?: string, blockNumber?: number, locked: Array<{ tokenClassKey, quantity: string, lockAuthority: string }> } ``` **Usage**: ```typescript // Basic lock (caller becomes lock authority) const result = await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '1000' }] // Lock 1000 tokens }); console.log(`Lock transaction: ${result.transactionId}`); // Lock with custom authority (escrow pattern) const escrowResult = await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '500', lockAuthority: 'eth|1234567890abcdef...', // Third party can unlock name: 'escrow-order-001' }] }); // Time-locked (auto-releases after expiration) const timedResult = await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '200', expires: Date.now() + (30 * 24 * 60 * 60 * 1000), // 30 days name: 'vesting-cliff-1' }] }); ``` #### `unlockTokens(data: UnlockTokensData): Promise` Unlock previously locked tokens on GalaChain (batch, single transaction). Must be signed by the lock authority. **Options**: ```text { tokens: Array<{ tokenName?: string, // Token to unlock tokenId?: TokenId, amount: string, // Amount to unlock name?: string // Optional lock name to match specific lock }>, uniqueKey?: string, privateKey?: string } ``` **Returns**: `{ transactionId?: string, blockNumber?: number, unlocked: Array<{ tokenClassKey, quantity }> }` **Usage**: ```typescript // Basic unlock const result = await sdk.unlockTokens({ tokens: [{ tokenName: 'anime', amount: '500' }] }); console.log(`Unlock transaction: ${result.transactionId}`); // Unlock specific named lock const namedResult = await sdk.unlockTokens({ tokens: [{ tokenName: 'anime', amount: '500', name: 'escrow-order-001' // Match the lock by name }] }); ``` **Lock/Unlock Patterns**: ```typescript // Pattern 1: Self-staking (user locks their own tokens) await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '1000' }] }); // Later... await sdk.unlockTokens({ tokens: [{ tokenName: 'anime', amount: '1000' }] }); // Pattern 2: Escrow (third party authority) await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '500', lockAuthority: 'eth|EscrowContract...', // Escrow contract unlocks name: 'trade-12345' }] }); // Pattern 3: Vesting schedule await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '10000', expires: Date.now() + (365 * 24 * 60 * 60 * 1000), // 1 year cliff name: 'employee-vesting-2025' }] }); ``` --- ### Category 8: Utilities #### `getAddress(): string` Get the SDK wallet address in backend format (`eth|...`). #### `getEthereumAddress(): string` Get the SDK wallet address in Ethereum format (`0x...`). #### `cleanup(): void` Cleanup resources (close WebSocket connections, clear timers). **Always call this before exiting your agent!** ```typescript process.on('SIGINT', () => { sdk.cleanup(); process.exit(0); }); ``` --- ## Common AI Agent Workflows ### Workflow 1: Trading Bot ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; // Setup const { sdk } = await AgentConfig.quickSetup({ environment: 'prod', agentId: 'trading-bot', autoValidate: true }); // Monitor pools for opportunities const pools = await sdk.fetchPools({ type: 'popular', pageSize: 50 }); for (const pool of pools.items) { // Get current price const quote = await sdk.calculateBuyAmount({ tokenName: pool.tokenName, amount: '1', // 1 GALA type: 'native' }); // The quote carries amount and fees (no price-impact field): apply your own threshold const minTokensPerGala = 1000; if (Number(quote.amount) >= minTokensPerGala) { console.log(`Good opportunity: ${pool.tokenName}`); // Execute trade const result = await sdk.buy({ tokenName: pool.tokenName, amount: '1', type: 'native', expectedAmount: quote.amount, slippageToleranceFactor: 0.05 }); console.log(`Bought: ${result.transactionId}`); } } // Cleanup sdk.cleanup(); ``` ### Workflow 2: Portfolio Monitor ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; const { sdk } = await AgentConfig.quickSetup(); // Check GALA balance const galaBalance = await sdk.fetchGalaBalance(); console.log(`GALA: ${galaBalance?.quantity ?? '0'}`); // Get held tokens (first page of 100; follow pageInfo.endCursor for more) const held = await sdk.fetchTokensHeld({ address: sdk.getAddress(), pageSize: 100 }); console.log(`Holding ${held.tokens.length} tokens:`); for (const token of held.tokens) { console.log(`${token.name} (${token.symbol}): ${token.balance} tokens`); } sdk.cleanup(); ``` ### Workflow 3: Token Creator Agent ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; const { sdk, validation } = await AgentConfig.quickSetup(); // Check if we have enough GALA if (!validation?.capabilities.canCreateTokens) { console.error('Need at least 100 GALA to create tokens'); process.exit(1); } // Check name availability const available = await sdk.isTokenNameAvailable('mytoken'); if (!available) { console.error('Name already taken'); process.exit(1); } // Upload image first import { readFile } from 'node:fs/promises'; const imageUrl = await sdk.uploadTokenImage({ tokenName: 'mytoken', options: { file: await readFile('/path/to/image.png') } }); // Create token const result = await sdk.launchToken({ tokenName: 'mytoken', tokenSymbol: 'MTK', tokenDescription: 'Agent-created token', tokenImage: imageUrl, preBuyQuantity: '0' }); console.log(`Token created: ${result.transactionId}`); sdk.cleanup(); ``` ### Workflow 4: Multi-Wallet Management ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; // Setup multiple wallets for different purposes const sdks = await AgentConfig.multiWalletSetup({ trader: process.env.TRADER_WALLET!, creator: process.env.CREATOR_WALLET!, monitor: 'generate' // Read-only operations }, 'prod'); const { trader, creator, monitor } = sdks; if (trader === undefined || creator === undefined || monitor === undefined) throw new Error('wallet setup failed'); // Use trader wallet for trading const tradeQuote = await trader.calculateBuyAmount({ tokenName: 'dragnrkti', amount: '5', // 5 GALA type: 'native' }); const tradeResult = await trader.buy({ tokenName: 'dragnrkti', amount: '5', type: 'native', expectedAmount: tradeQuote.amount, slippageToleranceFactor: 0.05 }); // Use creator wallet for token creation const createResult = await creator.launchToken({ tokenName: 'newtoken', tokenSymbol: 'NEW', tokenDescription: 'A new token' }); // Use monitor wallet for read-only operations (no balance needed) const pools = await monitor.fetchPools({ type: 'recent' }); // Cleanup all Object.values(sdks).forEach(sdk => sdk.cleanup()); ``` ### Workflow 5: Token Locking Agent ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; const { sdk } = await AgentConfig.quickSetup({ environment: 'prod', agentId: 'staking-agent' }); // Staking flow - lock tokens for rewards async function stakeTokens(tokenName: string, amount: string) { // Lock tokens (user is the lock authority by default) const lockResult = await sdk.lockTokens({ tokens: [{ tokenName, amount, name: `stake-${Date.now()}` // Track stake ID }] }); console.log(`Staked ${amount} ${tokenName}: ${lockResult.transactionId}`); return lockResult; } // Escrow flow - third party releases funds async function createEscrow( tokenName: string, amount: string, escrowAuthority: string, orderId: string ) { const lockResult = await sdk.lockTokens({ tokens: [{ tokenName, amount, lockAuthority: escrowAuthority, // Escrow contract/service unlocks name: `escrow-${orderId}` }] }); console.log(`Created escrow for order ${orderId}: ${lockResult.transactionId}`); return lockResult; } // Vesting flow - time-locked tokens async function createVestingSchedule( tokenName: string, amount: string, vestingPeriodDays: number ) { const expiresAt = Date.now() + (vestingPeriodDays * 24 * 60 * 60 * 1000); const lockResult = await sdk.lockTokens({ tokens: [{ tokenName, amount, expires: expiresAt, name: `vesting-${Date.now()}` }] }); console.log(`Created ${vestingPeriodDays}-day vesting: ${lockResult.transactionId}`); return lockResult; } // Unlock tokens (must be lock authority) async function unstake(tokenName: string, amount: string, stakeName?: string) { const unlockResult = await sdk.unlockTokens({ tokens: [{ tokenName, amount, ...(stakeName === undefined ? {} : { name: stakeName }) // Match specific lock if named }] }); console.log(`Unstaked ${amount} ${tokenName}: ${unlockResult.transactionId}`); return unlockResult; } // Execute staking workflow await stakeTokens('anime', '1000'); // ... time passes, rewards accrue ... await unstake('anime', '1000'); sdk.cleanup(); ``` --- ## Type Reference for Code Generation ### Key Types to Know ```text // Pool data structure (abridged; see src/types/launchpad.dto.ts) interface PoolData { id: string; tokenName: string; symbol: string; description: string; amount: string; creatorAddress: string; vaultAddress: string; createdAt: string; image: string; // ...social URLs, optional reverse bonding curve fee fields } // Cursor-paginated list results (PoolsResult = ListResult, TradesResult = ListResult) interface ListResult { items: T[]; pageInfo: PageInfo; } interface PageInfo { hasNextPage: boolean; endCursor?: string | null; // the next request's cursor; null on the last page hasPreviousPage?: boolean; startCursor?: string | null; totalCount?: number; // fetchAll... results only (the backend sends none) } // Amount calculation results (decimal strings in whole GALA / whole tokens) interface AmountCalculationResult { amount: string; transactionFee: string; reverseBondingCurveFee: string; gasFee: string; } // Confirmed trade result (buy and sell) interface TradeResult { transactionId: string; blockHash?: string; gasUsed?: string; timestamp: number; type: 'buy' | 'sell'; method: 'native' | 'exact'; inputAmount: string; outputAmount: string; totalFees: string; tokenName: string; vaultAddress: string; slippageTolerance?: number; } // Transfer receipt (transferGala, transferToken) interface GalaChainTransferReceipt { transactionId: string; blockNumber?: number; } // Balance info (fetchGalaBalance, fetchTokenBalance; both may resolve to null) interface TokenBalanceResult { quantity: string; collection: string; category: string; tokenId: string; lockedQuantity?: string; inUseQuantity?: string; availableQuantity?: string; // ...inUseHolds / lockedHolds } // Options patterns (cursor-based pagination everywhere) interface FetchPoolsOptions { type?: 'recent' | 'popular' | 'recordings' | 'seconds_streamed'; tokenName?: string; search?: string; cursor?: string; pageSize?: number; // ...hasUpcomingShows, language, recentlyStreamed, hasRecordings, streamStatus, isGraduated, creatorAddress } interface BuyTokenOptions { tokenName: string; amount: string; type: 'native' | 'exact'; expectedAmount: string; slippageToleranceFactor?: number; } // Lock/Unlock options (Category 7) interface LockTokenEntry { tokenName?: string; // Token to lock (or tokenId) tokenId?: TokenId; amount: string; // Amount in standard decimal format lockAuthority?: string; // Address that can unlock (defaults to caller) expires?: number; // Optional expiration timestamp in ms name?: string; // Optional lock name for matching } interface LockTokensData { tokens: LockTokenEntry[]; uniqueKey?: string; privateKey?: string; } interface UnlockTokenEntry { tokenName?: string; // Token to unlock (or tokenId) tokenId?: TokenId; amount: string; // Amount to unlock name?: string; // Optional lock name to match } interface UnlockTokensData { tokens: UnlockTokenEntry[]; uniqueKey?: string; privateKey?: string; } // Error types class ValidationError extends Error { field?: string; code?: string; } class TransactionFailedError extends Error { readonly transactionId: string; readonly status: string; } ``` --- ## Error Handling Patterns ### Validation Errors ```typescript import { ValidationError } from '@gala-chain/launchpad-sdk'; try { await sdk.buy({ tokenName: 'invalid!name', // Invalid characters amount: 'not-a-number', // Invalid format type: 'native', expectedAmount: '...', slippageToleranceFactor: 0.05 }); } catch (error) { if (error instanceof ValidationError) { console.error(`Validation failed: ${error.field} - ${error.code}`); // Handle validation error } } ``` ### Transaction Errors ```typescript import { TransactionFailedError } from '@gala-chain/launchpad-sdk'; try { const result = await sdk.buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: '1' }); console.log(`Success: ${result.transactionId}`); } catch (error) { if (error instanceof TransactionFailedError) { console.error(`Transaction ${error.transactionId} failed: ${error.status}`); // Handle transaction failure } } ``` ### Network Errors ```typescript try { const pools = await sdk.fetchPools({ type: 'recent' }); } catch (error) { const code = (error as { code?: string }).code; if (code === 'ECONNREFUSED') { console.error('Backend unreachable'); } else if (code === 'ETIMEDOUT') { console.error('Request timeout'); } else { console.error('Unknown error:', error); } } ``` ### Setup Validation ```typescript const { sdk, validation } = await AgentConfig.quickSetup(); if (validation === undefined || !validation.ready) { console.error('Setup failed:'); validation?.issues.forEach(issue => console.error(`- ${issue}`)); process.exit(1); } if (validation.warnings.length > 0) { console.warn('Setup warnings:'); validation.warnings.forEach(warn => console.warn(`- ${warn}`)); } ``` --- ## Best Practices for Agent Implementation ### 1. Always Use AgentConfig ```typescript // ❌ Bad - manual setup import { LaunchpadSDK } from '@gala-chain/launchpad-sdk'; import { Wallet } from 'ethers'; const wallet = new Wallet(process.env.PRIVATE_KEY!); const manualSdk = new LaunchpadSDK({ wallet, baseUrl: 'https://lpad-backend-prod1.defi.gala.com' }); // ✅ Good - AgentConfig handles everything import { AgentConfig } from '@gala-chain/launchpad-sdk'; const { sdk } = await AgentConfig.quickSetup(); ``` ### 2. Validate Before Operating ```typescript const { sdk, validation } = await AgentConfig.quickSetup({ autoValidate: true }); // Check specific capabilities if (!validation?.capabilities.canTrade) { console.error('Insufficient balance for trading'); process.exit(1); } ``` ### 3. Always Calculate Before Trading ```typescript async function tradeCarefully(): Promise { // ❌ Bad - trading blindly await sdk.buy({ tokenName: 'dragnrkti', amount: '5', type: 'native', expectedAmount: '???', // What should this be? slippageToleranceFactor: 0.05 }); // ✅ Good - calculate first const quote = await sdk.calculateBuyAmount({ tokenName: 'dragnrkti', amount: '5', // 5 GALA type: 'native' }); // Check quote before executing: the quote has amount and fees, no price-impact field const totalFeesGala = Number(quote.transactionFee) + Number(quote.reverseBondingCurveFee) + Number(quote.gasFee); if (totalFeesGala > 0.1 * 5) { console.warn('Fees exceed 10% of the trade, skipping'); return; } await sdk.buy({ tokenName: 'dragnrkti', amount: '5', type: 'native', expectedAmount: quote.amount, slippageToleranceFactor: 0.05 }); } ``` ### 4. Use Slippage Protection ```text // ❌ Bad - no slippage protection slippageToleranceFactor: 0 // Will fail if price moves // ✅ Good - reasonable slippage slippageToleranceFactor: 0.05 // 5% tolerance for normal volatility slippageToleranceFactor: 0.10 // 10% for high volatility // ✅ Good - choose per trade size const slippage = Number(amount) < 100 ? 0.02 : 0.05; ``` ### 5. Handle Rate Limits ```typescript // Implement exponential backoff for rate limits async function retryWithBackoff( fn: () => Promise, maxRetries = 3, baseDelay = 1000 ): Promise { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { if ((error as { response?: { status?: number } }).response?.status === 429) { // Rate limited const delay = baseDelay * Math.pow(2, i); console.log(`Rate limited, retrying in ${delay}ms`); await new Promise(resolve => setTimeout(resolve, delay)); } else { throw error; } } } throw new Error('Max retries exceeded'); } // Usage const pools = await retryWithBackoff(() => sdk.fetchPools({ type: 'recent' }) ); ``` ### 6. Clean Up Resources ```typescript // Always cleanup before exiting process.on('SIGINT', () => { console.log('Shutting down agent...'); sdk.cleanup(); process.exit(0); }); process.on('SIGTERM', () => { sdk.cleanup(); process.exit(0); }); // Or use try/finally try { // Agent operations await sdk.fetchPools({ type: 'recent' }); } finally { sdk.cleanup(); } ``` ### 7. Environment-Specific Configuration ```typescript // Stage - longer timeouts, debug enabled const { sdk: devSdk } = await AgentConfig.quickSetup({ environment: 'stage', timeout: 60000, debug: true }); // Production - optimized settings const { sdk: prodSdk } = await AgentConfig.quickSetup({ environment: 'prod', timeout: 30000, debug: false, agentId: 'production-bot-v1' }); ``` ### 8. Secure Wallet Management ```typescript // ❌ Bad - hardcoded keys const { sdk: hardcoded } = await AgentConfig.quickSetup({ privateKey: '0x1234567890abcdef...' }); // ✅ Good - environment variables const { sdk: fromEnv } = await AgentConfig.quickSetup({ privateKey: process.env.PRIVATE_KEY! // From .env file }); // ✅ Good - multi-wallet with different permissions const sdks = await AgentConfig.multiWalletSetup({ trading: process.env.TRADING_WALLET!, // Low balance, frequent use creation: process.env.CREATION_WALLET!, // High balance, rare use monitoring: 'generate' // No balance needed }, 'prod'); ``` --- ## Example MCP Tool Schemas ### Tool 1: Fetch Pools ```json { "name": "gala_launchpad_fetch_pools", "description": "Fetch token pools from Gala Launchpad with filtering and pagination", "inputSchema": { "type": "object", "properties": { "type": { "type": "string", "enum": ["recent", "popular", "recordings", "seconds_streamed"], "description": "Type of pools to fetch" }, "search": { "type": "string", "description": "Fuzzy search filter (optional)" }, "cursor": { "type": "string", "description": "Cursor from the previous page's pageInfo.endCursor (omit for the first page)" }, "pageSize": { "type": "number", "minimum": 1, "description": "Results per page (default: 20)" } } } } ``` ### Tool 2: Calculate Buy Amount ```json { "name": "gala_launchpad_calculate_buy_amount", "description": "Calculate token amounts for buying with slippage and fee breakdown", "inputSchema": { "type": "object", "properties": { "tokenName": { "type": "string", "pattern": "^[a-z0-9_-]{2,20}$", "description": "Token name" }, "amount": { "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)?$", "description": "Decimal string in whole units (e.g., '1' for 1 GALA, '10.5')" }, "type": { "type": "string", "enum": ["native", "exact"], "description": "native = spending GALA, exact = buying exact tokens" } }, "required": ["tokenName", "amount", "type"] } } ``` ### Tool 3: Execute Buy ```json { "name": "gala_launchpad_buy", "description": "Execute token purchase on Gala Launchpad with slippage protection", "inputSchema": { "type": "object", "properties": { "tokenName": { "type": "string", "pattern": "^[a-z0-9_-]{2,20}$" }, "amount": { "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)?$" }, "type": { "type": "string", "enum": ["native", "exact"] }, "expectedAmount": { "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)?$", "description": "Expected output from calculateBuyAmount" }, "slippageToleranceFactor": { "type": "number", "minimum": 0, "maximum": 1, "description": "Decimal format (0.05 = 5% slippage)" } }, "required": ["tokenName", "amount", "type", "expectedAmount", "slippageToleranceFactor"] } } ``` ### Tool 4: Fetch Balance ```json { "name": "gala_launchpad_fetch_gala_balance", "description": "Get GALA balance for a wallet address", "inputSchema": { "type": "object", "properties": { "walletAddress": { "type": "string", "pattern": "^(0x[a-fA-F0-9]{40}|eth\\|[a-fA-F0-9]{40})$", "description": "Wallet address (optional, defaults to SDK wallet)" } } } } ``` ### Tool 5: Create Comment ```json { "name": "gala_launchpad_create_comment", "description": "Post a comment on a token pool", "inputSchema": { "type": "object", "properties": { "tokenName": { "type": "string", "pattern": "^[a-z0-9_-]{2,20}$" }, "content": { "type": "string", "maxLength": 2000, "description": "Comment content (max 2000 chars)" } }, "required": ["tokenName", "content"] } } ``` **The tool catalog is in the README of `@gala-chain/gala-mcp-server`.** --- ## Environment Configuration ### Stage Environment ```typescript const { sdk } = await AgentConfig.quickSetup({ environment: 'stage', debug: true, timeout: 60000 }); // The stage preset targets the Gala staging backends (launchpad, bundle and swap) // and the GalaChain testnet gateway: https://gateway-testnet.galachain.com ``` ### Production Environment ```typescript const { sdk } = await AgentConfig.quickSetup({ environment: 'prod', debug: false, timeout: 30000, privateKey: process.env.PRODUCTION_WALLET! }); // URLs used: // - Launchpad: https://lpad-backend-prod1.defi.gala.com // - GalaChain: https://gateway-mainnet.galachain.com // - Bundle: https://bundle-backend-prod1.defi.gala.com // - Swap backend: https://dex-backend-prod1.defi.gala.com ``` ### Custom Environment ```typescript const { sdk } = await AgentConfig.quickSetup({ environment: 'prod', baseUrl: 'https://custom-backend.example.com', timeout: 45000 }); ``` --- ## Testing and Validation ### Unit Test Example ```typescript import { AgentConfig } from '@gala-chain/launchpad-sdk'; describe('Trading Agent', () => { let sdk: Awaited>['sdk']; beforeAll(async () => { const result = await AgentConfig.quickSetup({ environment: 'stage', autoValidate: true }); sdk = result.sdk; }); afterAll(() => { sdk.cleanup(); }); test('should fetch pools', async () => { const result = await sdk.fetchPools({ type: 'recent', pageSize: 10 }); expect(result.items.length).toBeGreaterThan(0); expect(result.pageInfo.hasNextPage).toBeDefined(); }); test('should calculate buy amount', async () => { const quote = await sdk.calculateBuyAmount({ tokenName: 'testtoken', amount: '1', type: 'native' }); expect(quote.amount).toBeDefined(); expect(quote.transactionFee).toBeDefined(); expect(quote.gasFee).toBeDefined(); }); }); ``` ### Integration Test Example ```typescript test('complete trading flow', async () => { const { sdk, validation } = await AgentConfig.quickSetup({ environment: 'stage' }); // Verify setup expect(validation?.ready).toBe(true); expect(validation?.capabilities.canTrade).toBe(true); // Get quote const quote = await sdk.calculateBuyAmount({ tokenName: 'testtoken', amount: '1', // 1 GALA type: 'native' }); expect(quote.amount).toBeTruthy(); // Execute trade const result = await sdk.buy({ tokenName: 'testtoken', amount: '1', type: 'native', expectedAmount: quote.amount, slippageToleranceFactor: 0.05 }); expect(result.transactionId).toBeTruthy(); expect(result.type).toBe('buy'); expect(result.inputAmount).toBeTruthy(); sdk.cleanup(); }); ``` --- ## Next Steps 1. **Read the README of `@gala-chain/gala-mcp-server`** for the MCP tool catalog 2. **Explore `docs/agent-examples/`** in the package for working code samples --- ## Support & Resources - **SDK Documentation**: [README.md](/launchpad-sdk/next/overview.md) - **API Reference**: [API-REFERENCE.md](/launchpad-sdk/next/api-reference.md) - **Package**: [@gala-chain/launchpad-sdk](https://www.npmjs.com/package/@gala-chain/launchpad-sdk) --- **Built with ❤️ for AI agents and automation tools** *Verified against `launchpad-sdk` 9.0.0 (`src/LaunchpadSDK.ts`, `src/types`, `src/utils/agent-config.ts`).* --- # Gala Launchpad SDK - Complete API Reference **Version**: 9.0.0 **Status**: Launchpad-only reference, checked against `src/LaunchpadSDK.ts` and the services it delegates to. launchpad-sdk has no DEX client: the DEX is `@gala-chain/gswap-sdk`'s (see "The DEX is gswap-sdk's"). Removed members and their new homes are listed in `MIGRATING-TO-9.0.md`. **Conventions**: methods take one options object (the heading shows its fields). Lists are cursor-paginated: pass `cursor` and `pageSize`, and read `pageInfo` (the backend's `hasNextPage`, `endCursor`, `hasPreviousPage`, `startCursor`; `totalCount` only on `fetchAll...` results) from the result. A token name is letters and digits, and each method accepts the length its backend route accepts (1-25 where the name is a request field, such as `fetchPools`, `fetchVolumeData`, `getTrades`, `fetchMessages`; up to 255 where it is part of the path, such as `fetchToken` and the stream methods; see the `TOKEN_NAME_*_CONSTRAINT` exports). Amounts are decimal strings. A `privateKey` option, where a method has one, signs that one call with another key. --- ## Table of Contents - [Pool Management & Discovery](#pool-management--discovery) - [Trading & Calculations](#trading--calculations) - [The DEX is gswap-sdk's](#the-dex-is-gswap-sdks) - [Balance & Portfolio](#balance--portfolio) - [Token Creation & Management](#token-creation--management) - [Social & Comments](#social--comments) - [Transfers](#transfers) - [Locks](#locks) - [Bridgeable Token Discovery](#bridgeable-token-discovery) - [Price History](#price-history) - [Utility Methods](#utility-methods) - [Live Streaming](#live-streaming) - [Stream Chat](#stream-chat) - [Service Clients](#service-clients) - [Error Reference](#error-reference) --- ## Pool Management & Discovery ### fetchPools(options?) **Description**: Fetch one page of launchpad token pools with filtering. **Parameters**: - `options` (`FetchPoolsOptions`, optional; every value is checked against what `GET /v1/tokens` accepts, and one it does not accept is a `ValidationError`, never dropped): - `type`: `'RECENT'` | `'POPULAR'` | `'RECORDINGS'` | `'SECONDS_STREAMED'`, any case (`POOL_FETCH_TYPES`; backend default: RECENT) - `tokenName`: string (exact match; must be a valid token name) - `search`: string (fuzzy match, at most 255 characters) - `cursor`: string (the previous page's `pageInfo.endCursor`) - `pageSize`: integer 1 to 100 (`POOL_LIST_MAX_PAGE_SIZE`; default 10) - `hasUpcomingShows`: `true` for pools with a scheduled next stream (`false` sends nothing: the backend reads any value as true) - `language`: string (ISO 639-1 code, e.g. `'en'`, `'zh-CN'`) - `recentlyStreamed`: integer 1 to 720 (pools that streamed within the last N hours) - `hasRecordings`: `true` for pools with at least one recording (`false` sends nothing) - `streamStatus`: `'IDLE'` | `'ACTIVE'` | `'DISABLED'`, any case (`POOL_STREAM_STATUSES`) - `isGraduated`: boolean; `true` for graduated pools, `false` for pools still on the bonding curve (both values are sent, as `"true"` / `"false"`; leave it out for no filter) - `creatorAddress`: `eth|<40 hex>` or `client|<24 hex>` (pools that address created; an empty string or any other text is a `ValidationError`) **Returns**: `Promise` (`ListResult`) - `items`: array of `PoolData` (token name, symbol, vault address, prices, supply, graduation flags, stream stats such as `currentViewerCount` and `lastStreamedAt`) - `pageInfo`: the backend's `{ hasNextPage, endCursor, hasPreviousPage, startCursor }` (`endCursor` is `null` on the last page) **Example**: ```typescript const page = await sdk.fetchPools({ type: 'popular', pageSize: 20 }); page.items.forEach(pool => { console.log(`${pool.tokenName}: ${pool.bondingCurvePercentage}% of the curve`); }); // Next page const { endCursor } = page.pageInfo; if (page.pageInfo.hasNextPage && endCursor) { const next = await sdk.fetchPools({ type: 'popular', pageSize: 20, cursor: endCursor }); } // Stream filters const upcomingShows = await sdk.fetchPools({ hasUpcomingShows: true }); const recentlyLive = await sdk.fetchPools({ recentlyStreamed: 24 }); // last 24 hours ``` **Errors**: - `ValidationError`: an option the backend does not accept (`tokenName`, `type`, `streamStatus`, `pageSize`, `recentlyStreamed`, `language`, `search`) - `NetworkError`: the backend answered with an error or the request failed **MCP Tool**: `gala_launchpad_fetch_pools` **MCP Prompt**: `/galachain-launchpad:fetch-pools` **Demo**: `npm run demo:bonding:pool-discovery`, `npm run demo:bonding:pagination-variants` --- ### fetchAllPools(options?) **Description**: Fetch ALL launchpad pools matching a filter by walking the cursor pages (100 pools per request). **Parameters**: - `options` (optional): the filters of `fetchPools` (`type`, `tokenName`, `search`, `hasUpcomingShows`, `language`, `recentlyStreamed`, `hasRecordings`, `streamStatus`, `isGraduated`, `creatorAddress`), without `cursor` / `pageSize` **Returns**: `Promise` - `items`: every matching `PoolData` - `pageInfo`: `{ hasNextPage: false, totalCount: items.length }` **Example**: ```typescript // Every popular pool (walks the pages) const all = await sdk.fetchAllPools({ type: 'popular' }); console.log(`Total pools: ${all.items.length}`); // Find a pool by name const myPool = all.items.find(p => p.tokenName === 'anime'); if (myPool) { console.log(`Supply: ${myPool.circulatingSupply}`); } ``` **Errors**: - `ValidationError`: `tokenName` is not a valid token name - `NetworkError`: the backend answered with an error or the request failed **MCP Tool**: `gala_launchpad_fetch_all_pools` **MCP Prompt**: `/galachain-launchpad:fetch-all-pools` **Demo**: `npm run demo:bonding:pool-discovery` --- ### fetchTokenDistribution(tokenName) **Description**: Get the complete holder distribution of a launchpad token with ownership percentages (one request, not paginated). **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise` - `holders`: array of `{ address, balance, percentage }` in the order the backend returned them (`balance` is a decimal string; `percentage` is a number on a 0-100 scale) - `totalSupply`: string, the sum of the holders' balances - `totalHolders`: number of holders returned - `lastUpdated`: `Date`, when the SDK built the result **Example**: ```typescript const distribution = await sdk.fetchTokenDistribution('anime'); console.log(`Total holders: ${distribution.totalHolders}`); const top10 = [...distribution.holders] .sort((a, b) => b.percentage - a.percentage) .slice(0, 10) .reduce((sum, h) => sum + h.percentage, 0); console.log(`Top 10 holders own ${top10.toFixed(2)}%`); const whales = distribution.holders.filter(h => h.percentage > 5); console.log(`Whales (>5%): ${whales.length}`); ``` **Errors**: - `ValidationError`: `tokenName` is empty or not a valid token name - `NetworkError`: the backend answered with an error (an HTTP 500 is reported as "temporarily unavailable") or the request failed **Use Cases**: Whale analysis, distribution health metrics, concentration risk assessment. **MCP Tool**: `gala_launchpad_fetch_token_distribution` **MCP Prompt**: `/galachain-launchpad:fetch-token-distribution` **Demo**: `npm run demo:bonding:pool-analysis` --- ### fetchTokenPrice({ tokenName }) **Description**: Get the USD spot price of a launchpad token: from its bonding curve (priced against GALA's market price), or from the swap backend's market price once it has graduated. A token by class key (GALA, GUSDC, any DEX token) is not priced here: use gswap-sdk's `gSwap.market.getPrice(tokenId)`. Passing `tokenId` is refused with a `ValidationError`. **Parameters**: - `params` (`FetchTokenSpotPriceParams`): `{ tokenName: string }` (launchpad token name) **Returns**: `Promise` `{ symbol: string; price: number }` (USD price per token) **Example**: ```typescript const { symbol, price } = await sdk.fetchTokenPrice({ tokenName: 'anime' }); console.log(`${symbol}: $${price}/token`); // GALA or any DEX token: gswap-sdk's market reads const galaPrice = await gSwap.market.getPrice('GALA|Unit|none|none'); ``` **Errors**: - `ValidationError` (`INVALID_PARAMETERS`): `tokenId` was passed - `ValidationError` (`REQUIRED`): `tokenName` is missing or empty - `ValidationError` (`INVALID_RESPONSE`): a graduated token has no market price - `NetworkError`: the bonding-curve calculation or a price read failed **MCP Tool**: `gala_launchpad_fetch_token_spot_price` **MCP Prompt**: `/galachain-launchpad:fetch-token-spot-price` **Demo**: `npm run demo:read-only` --- ### fetchTokenDetails(tokenId) **Description**: Read a token class's metadata from GalaChain. **Parameters**: - `tokenId` (`TokenId`): a pipe-delimited class key string (e.g. `'GUSDC|Unit|none|eth:0x...'`) or a `{ collection, category, type, additionalKey }` object **Returns**: `Promise` (gala-core-sdk's type) - `collection`, `category`, `type`, `additionalKey`: the class key - `symbol`: token symbol - `name`: token name - `decimals`: decimal places - `image`: icon URL - `description`: string - `network`: string - `contractAddress?`: string **Example**: ```typescript const gala = await sdk.fetchTokenDetails('GALA|Unit|none|none'); console.log(`${gala.name} (${gala.symbol}), ${gala.decimals} decimals`); const sameToken = await sdk.fetchTokenDetails({ collection: 'GALA', category: 'Unit', type: 'none', additionalKey: 'none', }); ``` **Errors**: - `ValidationError`: `tokenId` cannot be parsed as a class key - `NetworkError`: the token class was not found (status 404) or the read failed **Use Cases**: Pre-trade verification, metadata enrichment. **MCP Tool**: `gala_launchpad_fetch_token_details` **MCP Prompt**: `/galachain-launchpad:fetch-token-details` **Demo**: `npm run demo:read-only` --- ### fetchLaunchTokenFee() **Description**: Get current GALA fee required to launch a new token on launchpad. **Returns**: `Promise` GALA amount required as launch fee **Example**: ```typescript const launchFee = await sdk.fetchLaunchTokenFee(); console.log(`Launch fee: ${launchFee} GALA`); // Check if the wallet has enough GALA (fetchGalaBalance returns null for a zero balance) const balance = await sdk.fetchGalaBalance(); const available = Number(balance?.quantity ?? '0'); if (available >= launchFee) { console.log('Sufficient balance to launch'); } else { console.log(`Need ${launchFee - available} more GALA`); } ``` **Errors**: - `NetworkError`: the backend answered with an error or the request failed **Note**: This fee may change - always fetch fresh before launching. **MCP Tool**: `gala_launchpad_fetch_launch_token_fee` **MCP Prompt**: `/galachain-launchpad:fetch-launch-token-fee` **Demo**: `npm run demo:read-only`, `npm run demo:authenticated` --- ### fetchTokenClassesWithSupply(tokenClasses) **Description**: Fetch the GalaChain token classes for a list of class keys, with their supply figures. **Parameters**: - `tokenClasses` (`GalaChainTokenClassKey[]`): `{ collection, category, type, additionalKey }` objects; must not be empty **Returns**: `Promise` (gala-core-sdk's type), each with the class key plus: - `symbol`, `name`, `description`, `image`, `decimals`, `network` - `totalSupply`, `maxSupply`, `maxCapacity`, `totalBurned`, `totalMintAllowance` (decimal strings; `"Infinity"` for an uncapped capacity) - `knownMintSupply?`, `knownMintAllowanceSupply?` **Example**: ```typescript const [gala] = await sdk.fetchTokenClassesWithSupply([ { collection: 'GALA', category: 'Unit', type: 'none', additionalKey: 'none' }, ]); if (gala === undefined) throw new Error('GALA token class not returned'); console.log(`GALA total supply: ${gala.totalSupply} (max ${gala.maxSupply})`); ``` **Errors**: - `ValidationError`: `tokenClasses` is empty - `NetworkError`: no supply data was found for the classes (status 404) or the read failed **MCP Tool**: `gala_launchpad_fetch_token_classes_with_supply` **Demo**: `npm run demo:token-supply` --- ### fetchPoolDetails(tokenName) **Description**: Get the sale (bonding curve pool) state of a launchpad token. **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise` - `tokenName`, `vaultAddress`, `saleOwner` - `saleStatus`: string; `isGraduated`: boolean (true when `saleStatus` is `'Finished'`); `saleStartTime?`: Unix seconds - `maxSupply`, `sellingTokenQuantity` (tokens left to buy), `currentSupply`, `nativeTokenQuantity` (GALA in the vault) - `basePrice`, `euler`, `exponentFactor`: bonding curve parameters - `reverseBondingCurveMinFeePortion`, `reverseBondingCurveMaxFeePortion`, `hasReverseBondingCurveFee` - `reverseBondingCurveMinFeeFactor?`, `reverseBondingCurveMaxFeeFactor?`, `reverseBondingCurveNetFeeFactor?`: numbers (0.5 = 50%) - `nativeToken`, `sellingToken`: class keys **Example**: ```typescript const details = await sdk.fetchPoolDetails('anime'); console.log(`Current: ${details.currentSupply} / Max: ${details.maxSupply}`); console.log(`Status: ${details.saleStatus}, graduated: ${details.isGraduated}`); ``` **Errors**: - `ValidationError`: `tokenName` is not a valid token name - `NetworkError`: the backend answered with an error or the request failed **MCP Tool**: `gala_launchpad_fetch_pool_details` **MCP Prompt**: `/galachain-launchpad:fetch-pool-details` **Demo**: `npm run demo:bonding:pool-analysis` --- ### fetchPoolDetailsForCalculation(tokenName) **Description**: The sale fields a local bonding curve calculation needs, with the fee factors normalized to numbers. **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise<{ currentSupply, remainingTokens, maxSupply, reverseBondingCurveMaxFeeFactor, reverseBondingCurveMinFeeFactor, reverseBondingCurveNetFeeFactor }>` - `currentSupply`, `remainingTokens`, `maxSupply`: decimal strings - `reverseBondingCurveMaxFeeFactor`, `reverseBondingCurveMinFeeFactor`, `reverseBondingCurveNetFeeFactor`: numbers (0.5 = 50%) **Example**: ```typescript // Read once, then quote locally without further requests const pool = await sdk.fetchPoolDetailsForCalculation('anime'); const quote = await sdk.calculateSellAmount({ tokenName: 'anime', amount: '1000', type: 'exact', mode: 'local', currentSupply: pool.currentSupply, maxSupply: pool.maxSupply, reverseBondingCurveMaxFeeFactor: pool.reverseBondingCurveMaxFeeFactor, reverseBondingCurveMinFeeFactor: pool.reverseBondingCurveMinFeeFactor, }); ``` **Errors**: - `NetworkError`: the backend answered with an error or the request failed **MCP Tool**: `gala_launchpad_fetch_pool_details_for_calculation` **MCP Prompt**: `/galachain-launchpad:fetch-pool-details-for-calculation` **Demo**: `npm run demo:cache`, `npm run demo:read-only` --- ### isTokenGraduated(tokenName) **Description**: Check whether a token has completed its bonding curve and graduated to DEX trading (the `isGraduated` flag of `fetchPoolDetails`). **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise` True if token has graduated, false if still in bonding curve **Example**: ```typescript const graduated = await sdk.isTokenGraduated('anime'); if (graduated) { // A graduated token trades on the DEX: quote it with gswap-sdk's GSwap client const classKey = await sdk.resolveTokenClassKey('anime'); const quote = await gSwap.quoting.quoteExactInput(classKey, 'GALA|Unit|none|none', '1'); } else { console.log('Still in bonding curve phase'); } ``` **Errors**: - `ValidationError`: `tokenName` is not a valid token name - `NetworkError`: the backend answered with an error or the request failed **MCP Tool**: `gala_launchpad_is_token_graduated` **MCP Prompt**: `/galachain-launchpad:is-token-graduated` **Demo**: `npm run demo:bonding:graduation`, `npm run demo:read-only` --- ## Trading & Calculations ### fetchVolumeData(options) **Description**: Fetch the chart data points of a launchpad token over a time range. **Parameters**: - `options` (`FetchVolumeDataOptions`): - `tokenName` (string): Token name - `from` (number): start, a Unix timestamp (at least 173000000) - `to` (number): end, a Unix timestamp (at least 173000000) - `resolution` (number): resolution in seconds (at least 1) `from`, `to` and `resolution` are typed optional, but the method rejects a call without all three (`MISSING_GRAPH_OPTIONS`). They are numbers, not `Date`s or strings. **Returns**: `Promise` - `dataPoints`: array of candles `{ startTime, openPrice, highPrice, lowPrice, closePrice, volume }` - `isPreviousData`: whether candles older than `from` exist - `nextTime?`: when the range had no candles but older ones exist, the start time of the nearest one **Example**: ```typescript const now = Math.floor(Date.now() / 1000); const { dataPoints } = await sdk.fetchVolumeData({ tokenName: 'anime', from: now - 7 * 24 * 60 * 60, to: now, resolution: 3600, }); dataPoints.forEach(point => { console.log(`${point.startTime}: ${point.closePrice} (volume ${point.volume})`); }); ``` **Errors**: - `ValidationError`: `options` is malformed, `from`/`to`/`resolution` is missing or out of range, or `tokenName` is not a valid token name - `NetworkError`: the backend answered with an error or the request failed **Use Cases**: Charting, activity monitoring. **MCP Tool**: `gala_launchpad_fetch_volume_data` **MCP Prompt**: `/galachain-launchpad:fetch-volume-data` **Demo**: `npm run demo:read-only` --- ### fetchTrades(options) **Description**: Get one page of a token's trade history. **Parameters**: - `options` (`FetchTradesOptions`): - `tokenName` (string): Token name (required) - `cursor` (string, optional): the previous page's `pageInfo.endCursor` - `pageSize` (number, optional): default 10, capped at 20 The options type also carries `tradeType`, `userAddress`, `startDate`, `endDate` and `sortOrder`, but this method sends only `tokenName`, `cursor` and `pageSize` to the backend. To filter by user or search, use `getTrades` (`GetTradesOptions`). **Returns**: `Promise` (`ListResult`) - `items`: array of `TradeInfo` (`id`, `userAddress`, `tradeType`, `tokenAmount`, `vaultAddress`, `createdAt`, `updatedAt`, plus other fields the backend adds) - `pageInfo`: the backend's `{ hasNextPage, endCursor, hasPreviousPage, startCursor }` (`endCursor` is `null` on the last page) **Example**: ```typescript const page = await sdk.fetchTrades({ tokenName: 'anime', pageSize: 20 }); page.items.forEach(trade => { console.log(`${trade.createdAt} ${trade.tradeType}: ${trade.tokenAmount} by ${trade.userAddress}`); }); ``` **Errors**: - `ValidationError`: `options` is malformed or `tokenName` is empty - `NetworkError`: the backend answered with an error or the request failed **MCP Tool**: `gala_launchpad_fetch_trades` **MCP Prompt**: `/galachain-launchpad:fetch-trades` **Demo**: `npm run demo:read-only` --- ### calculateBuyAmount(options) **Description**: Quote a bonding-curve buy with its fee breakdown: the tokens received for a GALA spend, or the GALA cost of an exact token amount. **Parameters**: - `options` (`CalculateBuyAmountOptions`): - `tokenName` (string): Token name - `amount` (string): Amount in decimal format (e.g. `'100'`) - `type` (`'native'` | `'exact'`): - `'native'`: `amount` is the GALA to spend; the result `amount` is the tokens received - `'exact'`: `amount` is the tokens to buy; the result `amount` is the GALA cost - `mode` (`'local'` | `'external'`, optional): per-call override. Defaults to the SDK's `calculateAmountMode` config, which defaults to `'local'`. `'local'` computes on the client; `'external'` asks the launchpad backend. - `currentSupply` (string, optional): supply for `'local'` mode; fetched from the pool when omitted **Returns**: `Promise` - `amount`: the calculated amount (tokens for `'native'`, GALA cost for `'exact'`) - `transactionFee`: launchpad transaction fee (GALA) - `gasFee`: fixed gas fee (`'1'` GALA) - `reverseBondingCurveFee`: reverse bonding curve fee (GALA; `'0'` for a local buy quote) **Example**: ```typescript // Spend 100 GALA, get how many tokens? const quote = await sdk.calculateBuyAmount({ tokenName: 'anime', amount: '100', type: 'native' }); console.log(`100 GALA → ${quote.amount} anime tokens`); console.log(`Transaction fee: ${quote.transactionFee} GALA`); // Buy exactly 1000 tokens, what does it cost? const exactQuote = await sdk.calculateBuyAmount({ tokenName: 'anime', amount: '1000', type: 'exact' }); console.log(`1000 tokens cost ${exactQuote.amount} GALA`); ``` **Critical Note**: `amount` in the result is the side you did not pass: tokens for `'native'`, GALA for `'exact'`. Pass it to `buy()` as `expectedAmount`. **Errors**: - `ValidationError`: `tokenName` or `amount` is empty, `type` or `mode` is not one of the listed values, or `currentSupply` is not a number - `NetworkError`: an `'external'` quote or the supply read failed (the backend answered with an error, or the request failed) **MCP Tool**: `gala_launchpad_calculate_buy_amount` **MCP Prompt**: `/galachain-launchpad:calculate-buy-amount` **Demo**: `npm run demo:bonding:price-impact` --- ### calculateSellAmount(options) **Description**: Quote a bonding-curve sell with its fee breakdown: the GALA received for an exact token amount, or the tokens needed to receive a GALA amount. **Parameters**: - `options` (`CalculateSellAmountOptions`): - `tokenName` (string): Token name - `amount` (string): Amount in decimal format - `type` (`'exact'` | `'native'`): - `'exact'`: `amount` is the tokens to sell; the result `amount` is the GALA received - `'native'`: `amount` is the GALA to receive; the result `amount` is the tokens needed - `mode` (`'local'` | `'external'`, optional): per-call override; defaults to the SDK's `calculateAmountMode` config (`'local'`) - `currentSupply`, `maxSupply` (strings), `reverseBondingCurveMaxFeeFactor`, `reverseBondingCurveMinFeeFactor` (numbers) (optional): the pool values for `'local'` mode; fetched when omitted (see `fetchPoolDetailsForCalculation`) **Returns**: `Promise` (same shape as `calculateBuyAmount`; `reverseBondingCurveFee` is the fee charged on the sale) **Example**: ```typescript // Sell 1000 tokens, receive how much GALA? const quote = await sdk.calculateSellAmount({ tokenName: 'anime', amount: '1000', type: 'exact' }); console.log(`1000 anime → ${quote.amount} GALA`); // Receive 100 GALA, how many tokens must be sold? const nativeQuote = await sdk.calculateSellAmount({ tokenName: 'anime', amount: '100', type: 'native' }); console.log(`Sell ${nativeQuote.amount} anime to get 100 GALA`); ``` **Errors**: - `ValidationError`: `tokenName` or `amount` is empty, `type` or `mode` is not one of the listed values, or `currentSupply` is not a number - `NetworkError`: an `'external'` quote or a pool read failed **MCP Tool**: `gala_launchpad_calculate_sell_amount` **MCP Prompt**: `/galachain-launchpad:calculate-sell-amount` **Demo**: `npm run demo:trades` --- ### calculateBuyAmountLocal(options) **Description**: Quote a buy with the client-side bonding curve formula. With `currentSupply` given it makes no network call; without it the supply is read from the pool first. **Parameters**: - `options` (`CalculateBuyAmountLocalOptions`): - `amount` (string): Amount to calculate - `type` (`'native'` | `'exact'`): `'native'` = GALA to spend, `'exact'` = tokens to buy - `currentSupply` (string, optional): current supply in circulation - `tokenName` (string, optional): required when `currentSupply` is omitted **Returns**: `Promise` (`reverseBondingCurveFee` is `'0'`) **Example**: ```typescript // Pure calculation, no request: supply supplied by the caller const quote = await sdk.calculateBuyAmountLocal({ amount: '100', type: 'native', currentSupply: '500000' }); console.log(`100 GALA → ${quote.amount} tokens`); // Supply read from the pool const fromPool = await sdk.calculateBuyAmountLocal({ tokenName: 'anime', amount: '1000', type: 'exact' }); ``` **Errors**: - `ValidationError`: `amount` is empty, `type` is invalid, `currentSupply` is not a number, or `tokenName` is missing while the supply must be fetched - `NetworkError`: the pool read failed **Use Cases**: UI previews and repeated calculations against a supply you already hold. **MCP Tool**: `gala_launchpad_calculate_buy_amount_local` **MCP Prompt**: `/galachain-launchpad:calculate-buy-amount-local` **Demo**: `npm run demo:trades`, `npm run demo:read-only` --- ### calculateSellAmountLocal(options) **Description**: Quote a sell with the client-side bonding curve formula. **Parameters**: - `options` (`CalculateSellAmountLocalOptions`): - `amount` (string): Amount to calculate - `type` (`'exact'` | `'native'`): `'exact'` = tokens to sell, `'native'` = GALA to receive - `currentSupply` (string, optional), `maxSupply` (string, optional) - `reverseBondingCurveMinFeeFactor`, `reverseBondingCurveMaxFeeFactor` (numbers, optional): 0.5 = 50% - `tokenName` (string, optional): required when any of the four pool values above is omitted (they are then fetched) **Returns**: `Promise` **Example**: ```typescript const pool = await sdk.fetchPoolDetailsForCalculation('anime'); const quote = await sdk.calculateSellAmountLocal({ amount: '1000', type: 'exact', currentSupply: pool.currentSupply, maxSupply: pool.maxSupply, reverseBondingCurveMinFeeFactor: pool.reverseBondingCurveMinFeeFactor, reverseBondingCurveMaxFeeFactor: pool.reverseBondingCurveMaxFeeFactor, }); ``` **Errors**: - `ValidationError`: `amount` is empty, `type` is invalid, `currentSupply` is not a number, or `tokenName` is missing while pool values must be fetched - `NetworkError`: a pool read failed **MCP Tool**: `gala_launchpad_calculate_sell_amount_local` **MCP Prompt**: `/galachain-launchpad:calculate-sell-amount-local` **Demo**: `npm run demo:trades`, `npm run demo:read-only` --- ### calculateBuyAmountExternal(options) **Description**: Quote a buy on the launchpad backend (always a network request, no local math). `getTradeQuote({ tokenName, amount, type: 'MEME' | 'NATIVE', method: 'IN' | 'OUT' })` returns the same quote with the backend's own parameters. **Parameters**: - `options`: `{ tokenName: string; amount: string; type: 'native' | 'exact' }` (same meaning as in `calculateBuyAmount`) **Returns**: `Promise` **Example**: ```typescript const quote = await sdk.calculateBuyAmountExternal({ tokenName: 'anime', amount: '100', type: 'native' }); console.log(`Backend quote: 100 GALA → ${quote.amount} anime`); ``` **Errors**: - `ValidationError`: `tokenName` or `amount` is empty - `NetworkError`: the backend answered with an error, a malformed quote, or the request failed **Use Cases**: Cross-checking a local quote against the backend before executing. **MCP Tool**: `gala_launchpad_calculate_buy_amount_external` **MCP Prompt**: `/galachain-launchpad:calculate-buy-amount-external` **Demo**: `npm run demo:trades` --- ### calculateSellAmountExternal(options) **Description**: Quote a sell on the launchpad backend (always a network request). **Parameters**: - `options`: `{ tokenName: string; amount: string; type: 'native' | 'exact' }` (same meaning as in `calculateSellAmount`: `'exact'` = tokens to sell, `'native'` = GALA to receive) **Returns**: `Promise` **Errors**: - `ValidationError`: `tokenName` or `amount` is empty - `NetworkError`: the backend answered with an error, a malformed quote, or the request failed **MCP Tool**: `gala_launchpad_calculate_sell_amount_external` **MCP Prompt**: `/galachain-launchpad:calculate-sell-amount-external` **Demo**: `npm run demo:trades` --- ### calculateBuyAmountForGraduation(tokenNameOrOptions) **Description**: Quote the cost of buying all the tokens remaining in a pool (the buy that graduates it). **Parameters**: - `tokenNameOrOptions` (`string | CalculateBuyAmountForGraduationOptions`): a token name, or: - `tokenName` (string): Token name - `currentSupply` (string, optional): supply for local mode (derived from the sale details when omitted) - `calculateAmountMode` (`'local'` | `'external'`, optional): per-call mode override **Returns**: `Promise` (an `AmountCalculationResult` plus): - `amount`: the GALA cost of the remaining tokens - `remainingTokens`: the token quantity that would be bought - `transactionFee`, `gasFee`, `reverseBondingCurveFee`: as in `calculateBuyAmount` **Example**: ```typescript const graduation = await sdk.calculateBuyAmountForGraduation('anime'); console.log(`Graduation cost: ${graduation.amount} GALA`); console.log(`Tokens bought: ${graduation.remainingTokens}`); // Graduate if the wallet can pay const balance = await sdk.fetchGalaBalance(); if (Number(balance?.quantity ?? '0') >= Number(graduation.amount)) { await sdk.graduateToken({ tokenName: 'anime' }); } ``` **Errors**: - `ValidationError`: `tokenName` is invalid, or the pool has no tokens remaining (already graduated) - `NetworkError`: a sale-details read or an `'external'` quote failed **MCP Tool**: `gala_launchpad_calculate_buy_amount_for_graduation` **MCP Prompt**: `/galachain-launchpad:calculate-graduation-cost` **Demo**: `npm run demo:bonding:graduation`, `npm run demo:read-only` --- ### graduateToken(options) **Description**: One-step graduation: quote the cost of the remaining tokens (`calculateBuyAmountForGraduation`) and execute the buy with `buy()`. Needs a wallet, and waits for the confirmation over the WebSocket like `buy()`. **Parameters**: - `options` (`GraduateTokenOptions`): - `tokenName` (string): Token name - `slippageToleranceFactor` (number, optional): e.g. `0.01` = 1%; defaults to the SDK setting - `maxAcceptableReverseBondingCurveFeeSlippageFactor` (number, optional) - `calculateAmountMode` (`'local'` | `'external'`, optional) - `currentSupply` (string, optional): supply for local mode - `privateKey` (string, optional): sign with this key instead **Returns**: `Promise` - `transactionId`, `timestamp`, `blockHash?`, `gasUsed?` - `type`, `method`, `tokenName`, `vaultAddress` - `inputAmount`, `outputAmount`, `totalFees`, `slippageTolerance?` **Example**: ```typescript try { const result = await sdk.graduateToken({ tokenName: 'anime', slippageToleranceFactor: 0.01 }); console.log(`Graduated, transaction: ${result.transactionId}`); } catch (error) { console.error(`Graduation failed: ${error instanceof Error ? error.message : error}`); } ``` **Preconditions**: - the wallet holds enough GALA - the token is not already graduated **Errors**: - `ValidationError`: no wallet is configured, `tokenName` is invalid, or the pool is already graduated - `TransactionError`: the submission returned no transaction id, or the bundler failed (`BUNDLE_FAILED`) - `TransactionFailedError` / `WebSocketError`: the chain rejected the transaction, or the WebSocket confirmation failed - `NetworkError`: a read or request failed **MCP Tool**: `gala_launchpad_graduate_token` **MCP Prompt**: `/galachain-launchpad:graduate-token` **Demo**: `npm run demo:bonding:graduation` --- ### calculateInitialBuyAmount(nativeTokenQuantity) **Description**: Quote the tokens received for a GALA amount at the start of the curve (supply 0): the pre-buy of a token launch. **Parameters**: - `nativeTokenQuantity` (string): GALA amount to spend **Returns**: `Promise` Tokens received for the initial pre-buy (`amount`) with the fee breakdown **Example**: ```typescript const initialQuote = await sdk.calculateInitialBuyAmount('1000'); console.log(`1000 GALA in pre-buy → ${initialQuote.amount} tokens`); ``` **Errors**: - `ValidationError`: `nativeTokenQuantity` is not valid pre-mint data - `NetworkError`: the backend answered with an error, a malformed quote, or the request failed **Notes**: Only relevant when launching a token with a `preBuyQuantity`. **MCP Tool**: `gala_launchpad_calculate_initial_buy` **MCP Prompt**: `/galachain-launchpad:calculate-initial-buy` **Demo**: `npm run demo:authenticated` --- ### buy(options) **Description**: Execute a token purchase on the bonding curve with slippage protection. Needs a wallet; submits the bundle, then waits for the confirmation over the WebSocket. **Parameters**: - `options` (`BuyTokenOptions`): - `tokenName` (string): Token name - `amount` (string): GALA to spend (`'native'`) or tokens to buy (`'exact'`) - `type` (`'native'` | `'exact'`) - `expectedAmount` (string): the quote's `amount` from `calculateBuyAmount` (required) - `slippageToleranceFactor` (number, optional): 0.05 = 5%; defaults to the SDK setting (0.15 unless configured) - `maxAcceptableReverseBondingCurveFee` (string, optional): the quote's `reverseBondingCurveFee` - `maxAcceptableReverseBondingCurveFeeSlippageFactor` (number, optional): slippage applied to that fee - `privateKey` (string, optional): sign with this key instead **Returns**: `Promise` - `transactionId`, `timestamp`, `blockHash?`, `gasUsed?` - `type`, `method`, `tokenName`, `vaultAddress` - `inputAmount`, `outputAmount`, `totalFees`, `slippageTolerance?` **Example**: ```typescript // Step 1: quote const quote = await sdk.calculateBuyAmount({ tokenName: 'anime', amount: '100', type: 'native' }); // Step 2: execute with the quote const result = await sdk.buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: quote.amount, // the quote, not the input amount slippageToleranceFactor: 0.01, // 1% maxAcceptableReverseBondingCurveFee: quote.reverseBondingCurveFee, }); console.log(`Bought ${result.outputAmount} anime`); console.log(`Transaction: ${result.transactionId}`); ``` **Errors**: - `ValidationError`: no wallet is configured, `expectedAmount` is missing (`EXPECTED_AMOUNT_REQUIRED`), or the token name does not resolve (`TOKEN_NOT_FOUND`) - `TransactionError`: the submission returned no transaction id, or the bundler failed (`BUNDLE_FAILED`) - `TransactionFailedError` / `WebSocketError`: the chain rejected the transaction (for example the price moved past the tolerance), or the WebSocket confirmation failed - `NetworkError`: a request failed If the WebSocket confirmation fails, check the outcome with `getBundlerTransactionResult(transactionId)`. **MCP Tool**: `gala_launchpad_buy` **MCP Prompt**: `/galachain-launchpad:buy-tokens` **Demo**: `npm run demo:trades` --- ### sell(options) **Description**: Execute a token sale on the bonding curve with slippage protection. Needs a wallet; waits for the confirmation like `buy()`. **Parameters**: - `options` (`SellTokenOptions`): the fields of `buy()`, with `type` (`'exact'` | `'native'`): - `'exact'`: `amount` is the tokens to sell; `expectedAmount` is the quoted GALA received - `'native'`: `amount` is the GALA to receive; `expectedAmount` is the quoted tokens to sell When `maxAcceptableReverseBondingCurveFee` is omitted, the SDK quotes the fee itself and adds the fee slippage factor. **Returns**: `Promise` **Example**: ```typescript // Step 1: sell quote const quote = await sdk.calculateSellAmount({ tokenName: 'anime', amount: '1000', type: 'exact' }); // Step 2: execute const result = await sdk.sell({ tokenName: 'anime', amount: '1000', type: 'exact', expectedAmount: quote.amount, slippageToleranceFactor: 0.01, maxAcceptableReverseBondingCurveFee: quote.reverseBondingCurveFee, }); console.log(`Sold ${result.inputAmount} anime for ${result.outputAmount} GALA`); ``` **Errors**: as `buy()`; also `ConfigurationError` when no fee ceiling is given and the SDK has no quote source to derive one. **MCP Tool**: `gala_launchpad_sell` **MCP Prompt**: `/galachain-launchpad:sell-tokens` **Demo**: `npm run demo:trades` --- ### getBundlerTransactionResult(transactionId) **Description**: Look up a bundler transaction over HTTP (useful when the WebSocket confirmation of `buy()`/`sell()` failed or timed out). It does not throw for a failed lookup: the failure is in the returned object. **Parameters**: - `transactionId` (string): the bundler transaction id **Returns**: `Promise` - `success`: boolean - `data`: the bundler's answer for that id, when `success` is true (its fields are the bundler's, not typed by the SDK) - `error`: string, when `success` is false (empty id, HTTP failure, no answer) **Example**: ```typescript // A trade whose WebSocket confirmation failed: look the transaction up over HTTP async function lookUp(transactionId: string): Promise { const answer = await sdk.getBundlerTransactionResult(transactionId); if (answer.success) { console.log('Bundler answer:', answer.data); } else { console.log(`Lookup failed: ${answer.error}`); } } ``` **MCP Tool**: `gala_launchpad_get_bundler_transaction_result` **MCP Prompt**: `/galachain-launchpad:get-bundler-transaction-result` --- ## The DEX is gswap-sdk's launchpad-sdk 9.0 has no DEX client: no quotes, swaps, pools, liquidity positions, fees, market prices or leaderboard. Those are `@gala-chain/gswap-sdk`'s `GSwap` client. Build it from the same key as the launchpad SDK: ```typescript import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(process.env.PRIVATE_KEY!), walletAddress: sdk.getAddress(), // the launchpad SDK built with the same key }); ``` `env` is `'stage'` or `'prod'`; without a `signer`, reads work and any write throws `NO_SIGNER`. The client's namespaces are `gSwap.quoting`, `gSwap.swaps`, `gSwap.pools`, `gSwap.positions`, `gSwap.assets`, `gSwap.market` and `gSwap.leaderboard` (plus `gSwap.symbols` and `gSwap.fees`). Every removed launchpad DEX method and the gswap-sdk call that replaces it is listed in [`MIGRATING-TO-9.0.md`](/launchpad-sdk/next/migrating-to-9.md). A launchpad token that has graduated trades on the DEX: `sdk.isTokenGraduated(tokenName)` tells you, and `sdk.resolveTokenClassKey(tokenName)` gives the class key to pass to `gSwap`. The MCP server's DEX tools (for example `gala_launchpad_get_swap_quote_exact_input` and `gala_launchpad_execute_swap`) run on gswap-sdk. **gswap-sdk documentation**: - [`packages/gswap-sdk/README.md`](/gswap-sdk/next/overview.md) - `packages/gswap-sdk/examples/demos/README.md`: runnable DEX demos --- ## Balance & Portfolio ### fetchGalaBalance(address?) **Description**: Get the GALA balance of a wallet from GalaChain. **Parameters**: - `address` (string, optional): `eth|...` or `0x...` address (defaults to the SDK wallet) **Returns**: `Promise` - `quantity`: decimal string, in whole GALA - `collection`, `category`, `tokenId`: the class (`GALA|Unit|none|none`) - `lockedHolds?`, `lockedQuantity?`, `inUseHolds?`, `inUseQuantity?`, `availableQuantity?`: present when part of the balance is locked or in use - `null` when the wallet has no GALA (a zero balance) or the gateway's answer is unusable **Example**: ```typescript const balance = await sdk.fetchGalaBalance('eth|1234...'); const gala = Number(balance?.quantity ?? '0'); console.log(`Balance: ${gala} GALA`); if (gala >= 100) { console.log('Sufficient GALA for the transaction'); } ``` **Errors**: - `ValidationError`: no address was given and no wallet is configured - `NetworkError`: the GalaChain read failed **MCP Tool**: `gala_launchpad_fetch_gala_balance` **MCP Prompt**: `/galachain-launchpad:fetch-gala-balance` **Demo**: `npm run demo:utilities:balance`, `npm run demo:read-only` --- ### fetchTokenBalance(options) **Description**: Get the balance of one token for a wallet. A token given by `tokenId` (or a known GalaChain token name such as `MUSIC`) is read from GalaChain with lock details; any other `tokenName` is a launchpad token, read from the launchpad backend without lock details. **Parameters**: - `options` (`FetchTokenBalanceOptions`): - `address` (string): `eth|...` or `0x...` wallet address (required) - `tokenId` (`TokenId`, optional): class key string or object - `tokenName` (string, optional): launchpad token name (e.g. `'anime'`) - `withExpired` (boolean, optional): include expired holds (default false) Pass `tokenId` or `tokenName`. **Returns**: `Promise`: the same shape as `fetchGalaBalance`; `null` when the wallet holds none of the token. **Example**: ```typescript const anime = await sdk.fetchTokenBalance({ address: 'eth|1234...', tokenName: 'anime' }); console.log(`You hold ${anime?.quantity ?? '0'} anime tokens`); const gusdc = await sdk.fetchTokenBalance({ address: 'eth|1234...', tokenId: 'GUSDC|Unit|none|eth:0x...' }); ``` **Errors**: - `ValidationError`: neither `tokenId` nor `tokenName` was given - `NetworkError`: the GalaChain or backend read failed **MCP Tool**: `gala_launchpad_fetch_token_balance` **MCP Prompt**: `/galachain-launchpad:fetch-token-balance` **Demo**: `npm run demo:utilities:balance`, `npm run demo:bonding:token-launch` --- ### fetchTokensHeld(options?) **Description**: Get one page of the launchpad tokens a wallet holds. **Parameters**: - `options` (`FetchTokensHeldOptions`, optional): - `address` (string): `eth|...` address (defaults to the SDK wallet) - `tokenName` (string): filter by exact token name - `search` (string): fuzzy search by name - `cursor` (string): the previous page's `pageInfo.endCursor` - `pageSize` (number): default 10, capped at 20 **Returns**: `Promise` - `tokens`: array of `UserTokenInfo` (`id`, `name`, `symbol`, `type`, `address`, `balance`, `decimals`, `metadata?`, `createdAt`, `updatedAt`, plus other fields the backend adds) - `pageInfo`: the backend's `{ hasNextPage, endCursor, hasPreviousPage, startCursor }` (`endCursor` is `null` on the last page) - `total?`: the `totalCount`, when the backend sent one **Example**: ```typescript const portfolio = await sdk.fetchTokensHeld({ address: 'eth|1234...', pageSize: 20 }); console.log(`Holdings on this page: ${portfolio.tokens.length}`); portfolio.tokens.forEach(token => { console.log(`${token.name}: ${token.balance}`); }); // One token by name (the smallest payload) const anime = await sdk.fetchTokensHeld({ address: 'eth|1234...', tokenName: 'anime', pageSize: 1 }); ``` **Errors**: - `ValidationError`: the address is not valid, or no address was given and no wallet is configured - `NetworkError`: the backend answered with an error or the request failed **MCP Tool**: `gala_launchpad_fetch_tokens_held` **MCP Prompt**: `/galachain-launchpad:tokens-held` **Demo**: `npm run demo:read-only`, `npm run demo:wallet-tracking:balance-monitoring` --- ### fetchTokensCreated(options?) **Description**: Get one page of the launchpad tokens a wallet created. **Parameters**: - `options` (`FetchTokensCreatedOptions`, optional): the fields of `fetchTokensHeld`, plus: - `status` (`'all'` | `'graduated'` | `'active'`): filter by graduation status (default all) An exact `tokenName` filter is applied locally, after a backend search for that name. **Returns**: `Promise` **Example**: ```typescript const created = await sdk.fetchTokensCreated({ address: 'eth|1234...', status: 'active' }); created.tokens.forEach(token => { console.log(`${token.name} (${token.symbol})`); }); ``` **Errors**: - `ValidationError`: no address was given and no wallet is configured - `NetworkError`: the backend answered with an error or the request failed **MCP Tool**: `gala_launchpad_fetch_tokens_created` **MCP Prompt**: `/galachain-launchpad:fetch-tokens-created` **Demo**: `npm run demo:read-only` --- ### fetchProfile(address?) **Description**: Get a user's profile from the launchpad backend by wallet address (a public read). **Parameters**: - `address` (string, optional): `eth|...`, `0x...` or `client|...` address (defaults to the SDK wallet's address) **Returns**: `Promise`: the backend's profile (the `data` of its envelope): `address`, nullable `fullName` / `profileImage` / `bio`, `stats` (`ProfileStats`), the `launchBadge` / `successBadge` / `volumeBadge` / `engagementBadge` ladders (`BadgeStatus[]`), `isLiveStreaming` and `liveStreamToken`. **Example**: ```typescript const profile = await sdk.fetchProfile('eth|1234...'); console.log(`Name: ${profile.fullName}`); console.log(`Image: ${profile.profileImage}`); console.log(`Tokens created: ${profile.stats.tokensCreated}`); ``` **Errors**: - `ValidationError`: no address was given and no wallet is configured, or the address is not valid - `NetworkError`: the backend answered with an error, the request failed, or the body is not a profile **MCP Tool**: `gala_launchpad_fetch_profile` **MCP Prompt**: `/galachain-launchpad:profile` **Demo**: `npm run demo:read-only` --- ### updateProfile(data) **Description**: Update the logged-in user's profile (name and avatar). Needs a session (`sdk.login()`). **Parameters**: - `data` (`UpdateProfileData`): - `fullName` (string): 1-100 letters: a first name and an optional last name separated by one space - `profileImage` (string): image URL, or an empty string to keep the current image - `address` (string): the profile's wallet address (`eth|...` or `0x...`) - `privateKey` (string, optional): sign with this key instead **Returns**: `Promise` **Example**: ```typescript await sdk.updateProfile({ fullName: 'Alice Crypto', profileImage: 'https://example.com/avatar.png', address: 'eth|1234...', }); ``` **Errors**: - `ValidationError`: `address` is not valid, or `fullName` is not 1-100 letters (first name and optional last name) - `ConfigurationError`: no login session - `NetworkError`: the backend answered with an error or the request failed **MCP Tool**: `gala_launchpad_update_profile` **MCP Prompt**: `/galachain-launchpad:update-profile` **Demo**: `npm run demo:privatekey-override` --- ## Token Creation & Management ### launchToken(data) **Description**: Create a new token on the launchpad. Needs a wallet; submits the sale, then waits for the confirmation over the WebSocket. **Parameters**: - `data` (`LaunchTokenData`): - `tokenName` (string): letters and digits, at least one (the rule the chain and the bundler apply) - `tokenSymbol` (string): 1-8 uppercase letters - `tokenDescription` (string): 1-500 characters - `tokenImage` (string): image URL; get one with `uploadTokenImage`. The type also admits `File`/`Buffer`, but the launch sends the value as given and does not upload it. - `websiteUrl`, `twitterUrl`, `telegramUrl`, `instagramUrl`, `facebookUrl`, `redditUrl`, `tiktokUrl` (string, optional): `http(s)` URLs - `preBuyQuantity` (string, optional): GALA to pre-buy, a non-negative decimal (default `'0'`) - `reverseBondingCurveConfiguration` (optional): `{ minFeePortion, maxFeePortion }` decimal strings - defaults: `{ minFeePortion: '0.1', maxFeePortion: '0.5' }` - when given, both are between 0.1 and 0.5 and `maxFeePortion >= minFeePortion` - `tokenCategory`, `tokenCollection` (string, optional): default `'Unit'` and `'Token'` - `saleStartTime` (number, optional): Unix timestamp in seconds for a delayed start (a positive integer; omitted = starts immediately) - `privateKey` (string, optional): sign with this key instead **Returns**: `Promise` - `transactionId`, `timestamp`, `blockHash?`, `gasUsed?` - `vaultAddress`, `tokenStringKey` - `tokenName`, `tokenSymbol`, `creatorAddress` - `tokenImage?`, `preBuyQuantity?` **Example**: ```typescript const result = await sdk.launchToken({ tokenName: 'mytoken', tokenSymbol: 'MYT', tokenDescription: 'My awesome token for testing', tokenImage: 'https://example.com/token-icon.png', websiteUrl: 'https://mytoken.example.com', twitterUrl: 'https://twitter.com/mytoken', telegramUrl: 'https://t.me/mytoken' }); console.log(`✅ Token created: ${result.tokenName}`); console.log(`Transaction: ${result.transactionId}`); ``` **Example with Custom Bonding Curve**: ```typescript const result = await sdk.launchToken({ tokenName: 'customfee', tokenSymbol: 'CFT', tokenDescription: 'Token with custom fee structure', tokenImage: 'https://example.com/token-icon.png', websiteUrl: 'https://customfee.example.com', reverseBondingCurveConfiguration: { minFeePortion: '0.2', // 20% minimum fee maxFeePortion: '0.3' // 30% maximum fee } }); // If omitted, defaults to { minFeePortion: "0.1", maxFeePortion: "0.5" } ``` **Requirements**: - the token name and symbol are not taken (check with `validateToken`, `isTokenNameAvailable` or `isTokenSymbolAvailable`) - the wallet holds enough GALA for the launch fee (`fetchLaunchTokenFee`) plus any pre-buy **Errors**: - `ValidationError`: no wallet is configured, or a field breaks the rules above (name, symbol, description, URLs, `preBuyQuantity`, fee portions, `saleStartTime`) - `LaunchpadSDKError`: signing or the bundler rejected the sale; read its `code` (`WALLET_ACCOUNT_CHANGED` the wallet's selected account is not the signer's key, `WALLET_USER_REJECTED` the person declined in the wallet, `LAUNCHPAD_SIGNING_FAILED` any other signing failure, `BUNDLE_FAILED`, `BUNDLE_REQUEST_FAILED`, `INVALID_BUNDLE_RESPONSE`) - `TransactionFailedError` / `WebSocketError`: the chain rejected the transaction, or the WebSocket confirmation failed **MCP Tool**: `gala_launchpad_launch_token` **MCP Prompt**: `/galachain-launchpad:launch-token` **Demo**: `npm run demo:bonding:token-launch` --- ### uploadTokenImage(options) **Description**: Upload a token image and get its URL. The image is a `File` (browser) or a `Buffer` (Node.js), not a path. Needs a login session (`sdk.login()`, or an app `session`), not a wallet: an SDK built from a signer and a wallet address uploads too. **Parameters**: - `options` (`UploadImageByTokenNameOptions`): - `tokenName` (string): Token name (letters and digits; the route takes the name from the path) - `options` (object): `{ file: File | Buffer }` - `privateKey` (string, optional): sign in as this key's wallet instead **Returns**: `Promise`: the uploaded image's URL **Example**: ```typescript import { readFile } from 'node:fs/promises'; const file = await readFile('/path/to/icon.png'); const url = await sdk.uploadTokenImage({ tokenName: 'mytoken', options: { file } }); console.log(`Image uploaded: ${url}`); // Use it in the launch await sdk.launchToken({ tokenName: 'mytoken', tokenSymbol: 'MYT', tokenDescription: 'My token', tokenImage: url, websiteUrl: 'https://mytoken.example.com', }); ``` **Limits**: 1 byte to 10 MB. A `File` must be PNG, JPG/JPEG, GIF, WebP or SVG. A `Buffer` is size-checked and sent as `.png`. **Errors**: - `ValidationError`: `tokenName` is not letters and digits - `FileValidationError`: the file is empty, over 10 MB, or not an allowed type - `ConfigurationError`: `FormData` is not available in this environment - `NetworkError`: the upload was rejected or returned no URL **MCP Tool**: `gala_launchpad_upload_token_image` **MCP Prompt**: `/galachain-launchpad:upload-token-image` **Demo**: `npm run demo:core:image-uploads` prints the upload pattern; it does not upload a file --- ### uploadProfileImage(options) **Description**: Upload a profile image and get its URL. The image is a `File` or a `Buffer`, not a path. Needs a login session (`sdk.login()`). **Parameters**: - `options` (`UploadProfileImageOptions`): - `file` (`File | Buffer`): the image - `address` (string, optional): validated and left out of the request (the backend uploads for the user of the session); none is invented - `privateKey` (string, optional): sign in as this key's wallet instead **Returns**: `Promise`: the uploaded image's URL (an empty string if the backend returned none) **Example**: ```typescript import { readFile } from 'node:fs/promises'; const url = await sdk.uploadProfileImage({ file: await readFile('/path/to/avatar.png') }); await sdk.updateProfile({ fullName: 'Alice Crypto', profileImage: url, address: sdk.getAddress(), }); ``` **Errors**: - `ValidationError`: `address` is not valid, or the upload failed (`UPLOAD_FAILED`) - `ConfigurationError`: no login session **MCP Tool**: `gala_launchpad_upload_profile_image` **MCP Prompt**: `/galachain-launchpad:upload-profile-image` --- ### fetchToken(tokenName) **Description**: Fetch one token's pool data, with its streaming state, as a `PoolData`. This is how a token's stream status is read (there is no separate stream-info method). **Parameters**: - `tokenName` (string): Token name (required) **Returns**: `Promise` - identity: `tokenName`, `symbol`, `description`, `image`, `vaultAddress`, `creatorAddress`, `createdAt`, and the social URLs - trading: `usdPrice`, `galaPrice`, `marketCapUsd`, `marketCapGala`, `volume`, `volume1h`, `galaInPool` - supply and status: `circulatingSupply`, `bondingCurvePercentage`, `isGraduated`, `isFinalized` - streaming: `muxPlaybackId?`, `muxStreamAspectRatio?`, `muxStreamStatus?` (`'IDLE'` | `'ACTIVE'` | `'DISABLED'`), `nextLiveStreamAt?`, `streamLanguage?` - stream stats: `currentViewerCount?`, `peakViewerCount?`, `streamStartedAt?`, `lastStreamedAt?`, `recordingsCount?`, `totalSecondsStreamed?` **Example**: ```typescript const pool = await sdk.fetchToken('mytoken'); console.log(`Name: ${pool.tokenName}, Symbol: ${pool.symbol}`); console.log(`Price: $${pool.usdPrice}`); if (pool.muxStreamStatus === 'ACTIVE') { console.log(`Live now: ${pool.currentViewerCount} viewers, playback ID ${pool.playbackId}`); } console.log(`Streaming enabled: ${pool.streamEnabled}`); ``` **Errors**: - `Error` ("Token not found"): no such token (the backend answered 404 or no pool) - `ValidationError`: `tokenName` is not a valid token name - `NetworkError`: the request failed **MCP Tool**: none for a single token (`gala_launchpad_fetch_pools` returns `PoolData` in lists) **Demo**: `npm run demo:streaming` --- ### validateToken(options) **Description**: Validate token name and/or symbol availability for creation or form validation. **Parameters**: - `options` (object, at least one field required): - `tokenName` (string, optional): Token name to validate (1-50 characters, any text: the availability route takes what the form types; sent lowercased) - `symbol` (string, optional): Token symbol to validate (sent uppercased; not validated locally) **Returns**: `Promise` - `nameAvailable` (boolean): Whether token name is available - `symbolAvailable` (boolean): Whether token symbol is available - `nameBlocklisted` (boolean): Whether name is on blocklist - `symbolBlocklisted` (boolean): Whether symbol is on blocklist - `errors` (string[]): Validation error messages **Example (Form Validation)**: ```typescript // Validate single field const nameCheck = await sdk.validateToken({ tokenName: 'mytoken' }); if (nameCheck.nameAvailable && !nameCheck.nameBlocklisted) { console.log('✅ Name is valid and available!'); } else if (nameCheck.nameBlocklisted) { console.log('❌ Name is blocklisted'); } else { console.log('❌ Name already taken'); } // Validate both fields const tokenCheck = await sdk.validateToken({ tokenName: 'mytoken', symbol: 'MYT' }); if (tokenCheck.errors.length > 0) { console.log(`Validation errors: ${tokenCheck.errors.join(', ')}`); } if (tokenCheck.nameAvailable && tokenCheck.symbolAvailable) { console.log('✅ Ready to launch!'); } ``` **Example (Real-time Form Input)**: ```typescript // Validate as the user types (call this from your input handler) async function checkName(name: string): Promise<'available' | 'taken' | 'blocklisted' | 'too short'> { if (name.length < 3) return 'too short'; const result = await sdk.validateToken({ tokenName: name }); if (result.nameBlocklisted) return 'blocklisted'; return result.nameAvailable ? 'available' : 'taken'; } ``` **Validation Rules**: - Token name: 1-50 characters, unique, not blocklisted (the launch itself requires letters and digits) - Symbol: unique, not blocklisted (the launch itself requires 1-8 uppercase letters) - At least one field must be provided - The backend's validation messages are returned in `errors` **Errors**: - `Error`: neither `tokenName` nor `symbol` was given, or one is an empty string - `ValidationError`: `tokenName` is not 1-50 characters - `NetworkError`: the request failed **Use Cases**: - Real-time form validation during token creation - Pre-launch availability checks **MCP Tool**: `gala_launchpad_validate_token` **Demo**: Not currently available --- ### isTokenNameAvailable(tokenName) **Description**: Check if token name is available for creation. **Parameters**: - `tokenName` (string): Token name to check **Returns**: `Promise` True if available, false if taken. It also returns false when the check itself fails (an invalid name or a request error): it never throws. Use `validateToken` to tell the cases apart. **Example**: ```typescript const available = await sdk.isTokenNameAvailable('mytoken'); if (available) { console.log('✅ Name is available!'); } else { console.log('❌ Name already taken'); const alt = await sdk.isTokenNameAvailable('mytoken2'); } ``` **MCP Tool**: `gala_launchpad_check_token_name` **MCP Prompt**: `/galachain-launchpad:check-token-name` **Demo**: `npm run demo:bonding:token-launch`, `npm run demo:read-only` --- ### isTokenSymbolAvailable(symbol) **Description**: Check if token symbol is available. **Parameters**: - `symbol` (string): Token symbol (a launch needs 1-8 uppercase letters) **Returns**: `Promise` True if available, false if taken or if the check itself failed: it never throws. **Example**: ```typescript const available = await sdk.isTokenSymbolAvailable('MYT'); if (!available) { console.log('Try another symbol'); } ``` **MCP Tool**: `gala_launchpad_check_token_symbol` **MCP Prompt**: `/galachain-launchpad:check-token-symbol` **Demo**: `npm run demo:bonding:token-launch`, `npm run demo:read-only` --- ### resolveTokenClassKey(tokenName) **Description**: Resolve a launchpad token name to its GalaChain class key (parsed from the token's vault address). Never build the key from the name: the `type` is the token's symbol on chain and `additionalKey` is the creator's address. **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise` (the type is `@gala-chain/gala-core-sdk`'s) - `collection`: `'Token'` for launchpad tokens - `category`: `'Unit'` - `type`: the token's symbol on chain - `additionalKey`: `eth:0x...`, the creator's address **Example**: ```typescript const classKey = await sdk.resolveTokenClassKey('anime'); // { collection: 'Token', category: 'Unit', type: 'ANM', additionalKey: 'eth:0x...' } // Use it with gswap-sdk's GSwap client (see "The DEX is gswap-sdk's") const quote = await gSwap.quoting.quoteExactInput(classKey, 'GALA|Unit|none|none', '100'); ``` **Errors**: - `TransferError` (`TOKEN_NOT_FOUND`): the name is empty, unknown, or its vault address could not be read **Use Cases**: Converting a token name to a class key for DEX and balance calls. **MCP Tool**: `gala_launchpad_resolve_token_class_key` **MCP Prompt**: `/galachain-launchpad:resolve-token-class-key` **Demo**: `npm run demo:token-info:token-name-resolution`, `npm run demo:read-only` --- ### resolveVaultAddress(tokenName) **Description**: Get the GalaChain vault address of a launchpad token (the address that holds its bonding curve pool). **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise` The vault address, or `null` when no pool matches the name **Example**: ```typescript const vaultAddr = await sdk.resolveVaultAddress('anime'); console.log(`Vault: ${vaultAddr ?? 'not found'}`); ``` **Errors**: - `ValidationError`: `tokenName` is empty - `NetworkError`: the pool lookup failed **Use Cases**: Advanced/debugging operations, direct GalaChain interactions. **MCP Tool**: `gala_launchpad_resolve_vault_address` **MCP Prompt**: `/galachain-launchpad:resolve-vault-address` **Demo**: `npm run demo:read-only` --- ## Social & Comments ### createComment(options) **Description**: Post a comment on a token's pool discussion. Needs a login session (`sdk.login()`). **Parameters**: - `options` (`CreateCommentOptions`): - `tokenName` (string): Token name (1-25 letters and digits) - `content` (string): Comment text, 1-2000 characters (trimmed) **Returns**: `Promise` - `comment`: the created `WrittenComment`, as the backend answers a write (`id` is the NUMERIC database id; `messageId` is the message id string every other route takes; `content`, `userAddress`, `createdAt`, `updatedAt`, `user?`; no `tokenName`) **Example**: ```typescript const { comment } = await sdk.createComment({ tokenName: 'anime', content: 'Great project!' }); console.log(`Comment posted: ${comment.id}`); ``` **Errors**: - `ValidationError`: `tokenName` is not valid, or `content` is empty or longer than 2000 characters - `ConfigurationError`: no login session - `NetworkError`: the request failed **MCP Tool**: `gala_launchpad_create_comment` **MCP Prompt**: `/galachain-launchpad:create-comment` **Demo**: `npm run demo:comments` --- ### getComments(options) **Description**: Get one page of comments, by token or by author. A public read. **Parameters**: - `options` (`GetCommentsOptions`): - `tokenName` (string, optional): filter by token - `userAddress` (string, optional): filter by author (`eth|...` or `0x...`) - `cursor` (string, optional): the previous page's `pageInfo.endCursor` - `pageSize` (number, optional): default 10, at most 50 The options type documents that at least one of `tokenName` and `userAddress` is expected; the SDK does not check it before sending. **Returns**: `Promise` - `messages`: array of `Message` (`id` and `messageId` (the same string), `tokenName`, `tokenImage`, `userAddress`, `user` and `userProfile` (the same `{ fullName, profileImage }`), `content`, `createdAt`, `updatedAt` (null when never edited), `deletedAt`, `flagCount`, `reactions: { counts, userReacted? }`) - `pageInfo`: the backend's `{ hasNextPage, endCursor, hasPreviousPage, startCursor }` (`endCursor` is `null` on the last page) **Example**: ```typescript const page = await sdk.getComments({ tokenName: 'anime', pageSize: 20 }); page.messages.forEach(comment => { console.log(`${comment.userAddress}: ${comment.content}`); console.log(`Posted: ${comment.createdAt}`); }); ``` **Errors**: - `ValidationError`: `tokenName` is not valid - `NetworkError`: the request failed **MCP Tool**: `gala_launchpad_get_comments` **MCP Prompt**: `/galachain-launchpad:get-comments` **Demo**: `npm run demo:comments` --- ## Transfers ### transferGala(data) **Description**: Transfer GALA to another wallet. Needs a wallet. **Parameters**: - `data` (`TransferGalaData`): - `recipientAddress` (string): `eth|...` or `0x...` address - `amount` (string): GALA amount as a decimal string (e.g. `'100.5'`) - `uniqueKey` (string, optional): idempotency key - `privateKey` (string, optional): sign with this key instead **Returns**: `Promise` - `transactionId`: the chain transaction hash (the gateway's `x-transaction-id` header) - `blockNumber?`: the block number, when the gateway sent one The gateway does not echo `uniqueKey`: keep it yourself if you need it for correlation. **Example**: ```typescript const receipt = await sdk.transferGala({ recipientAddress: 'eth|742d35Cc6634C0532925a3b8D0Ea2c76f94C31C0', amount: '100.5', uniqueKey: 'unique-key-12345', }); console.log(`Transaction: ${receipt.transactionId}`); ``` **Idempotency**: Use `uniqueKey` to avoid a duplicate transfer when you retry. **Errors**: - `ValidationError`: `data` is missing required fields - `TransferError`: the recipient address or amount is invalid, no wallet is configured (`WALLET_REQUIRED`), the balance is insufficient (`INSUFFICIENT_BALANCE`), or the gateway rejected the transfer; read its `type` (`TransferErrorType`) **MCP Tool**: `gala_launchpad_transfer_gala` **MCP Prompt**: `/galachain-launchpad:transfer-gala` **Demo**: `npm run demo:privatekey-override` --- ### transferToken(data) **Description**: Transfer a token (by class key or launchpad token name) to another wallet. Needs a wallet. **Parameters**: - `data` (`TransferTokenData`): - `to` (string): recipient `eth|...` or `0x...` address - `amount` (string): decimal amount - `tokenId` (`TokenId`, optional): class key string or object - `tokenName` (string, optional): launchpad token name, used when `tokenId` is not given - `uniqueKey` (string, optional): idempotency key (generated when omitted) - `privateKey` (string, optional): sign with this key instead Pass `tokenId` or `tokenName`. **Returns**: `Promise` (`transactionId`, `blockNumber?`) **Example**: ```typescript const receipt = await sdk.transferToken({ tokenName: 'anime', to: 'eth|742d35Cc6634C0532925a3b8D0Ea2c76f94C31C0', amount: '1000', uniqueKey: 'anime-tx-001', }); console.log(`Sent 1000 anime: ${receipt.transactionId}`); ``` **Errors**: - `ValidationError`: `data` is missing required fields (`to`, `amount`, and `tokenId` or `tokenName`) - `TransferError`: invalid recipient or amount, no wallet (`WALLET_REQUIRED`), the token is not found (`TOKEN_NOT_FOUND`), the balance is insufficient, or the gateway rejected the transfer **MCP Tool**: `gala_launchpad_transfer_token` **MCP Prompt**: `/galachain-launchpad:transfer-token` **Demo**: `npm run demo:utilities:transfers` --- ## Locks ### lockTokens(data) **Description**: Lock tokens on GalaChain, one or several token types in a single transaction (all or none). Locked tokens cannot be transferred until unlocked by the lock authority. Useful for staking, escrow, and vesting mechanisms. Needs a wallet. **Parameters**: - `data` (`LockTokensData`): - `tokens` (`LockTokenEntry[]`, 1 to 100): each entry: - `tokenId` (`TokenId`) or `tokenName` (string): the token - `amount` (string): decimal amount to lock - `lockAuthority` (string, optional): address that can unlock (defaults to the caller) - `expires` (number, optional): expiration timestamp in epoch milliseconds - `name` (string, optional): lock name, to match at unlock - `uniqueKey` (string, optional): idempotency key - `privateKey` (string, optional): sign with this key instead One transaction carries one `lockAuthority`, one `expires` and one `name`: the first entry that sets each one applies to the whole batch. **Returns**: `Promise` - `transactionId?`: string - `blockNumber?`: number - `locked`: array of `{ tokenClassKey, quantity, lockAuthority }` **Example**: ```typescript // Basic lock: the caller is the lock authority await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '1000' }] }); // Lock with another authority and an expiry const result = await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '5000', lockAuthority: 'eth|742d35Cc6634C0532925a3b8D0Ea2c76f94C31C0', expires: Date.now() + 7 * 24 * 60 * 60 * 1000, // 1 week name: 'escrow-deal-123', }], }); console.log(`Locked ${result.locked.length} token(s): ${result.transactionId}`); ``` **Errors**: - `LockError`: invalid input, no wallet (`WALLET_REQUIRED`), the token is not found, the balance is insufficient, or the gateway rejected the lock; read its `type` (`LockErrorType`) **Use Cases**: - **Staking**: Lock tokens for reward programs - **Escrow**: Third-party holds tokens until conditions met - **Vesting**: Time-locked token releases **MCP Tool**: `gala_launchpad_lock_tokens` **MCP Prompt**: `/galachain-launchpad:lock-token` **Demo**: `npm run demo:locks` --- ### unlockTokens(data) **Description**: Unlock previously locked tokens on GalaChain, one or several token types in a single transaction. Must be signed by the lock authority. Needs a wallet. **Parameters**: - `data` (`UnlockTokensData`): - `tokens` (`UnlockTokenEntry[]`, 1 to 100): each entry: - `tokenId` (`TokenId`) or `tokenName` (string): the token - `amount` (string): decimal amount to unlock - `name` (string, optional): match a specific lock by name - `uniqueKey` (string, optional): idempotency key - `privateKey` (string, optional): sign with this key instead **Returns**: `Promise` - `transactionId?`: string - `blockNumber?`: number - `unlocked`: array of `{ tokenClassKey, quantity }` **Example**: ```typescript // Basic unlock: must be the lock authority await sdk.unlockTokens({ tokens: [{ tokenName: 'anime', amount: '1000' }] }); // Unlock a specific named lock await sdk.unlockTokens({ tokens: [{ tokenName: 'anime', amount: '5000', name: 'escrow-deal-123' }], }); ``` **Authorization**: Only the lock authority (set at lock time, or the locker if none was set) can unlock. **Errors**: - `LockError`: invalid input, no wallet (`WALLET_REQUIRED`), no matching lock (`LOCK_NOT_FOUND`), the caller is not the authority (`NOT_LOCK_AUTHORITY`), or the gateway rejected the unlock; read its `type` (`LockErrorType`) **MCP Tool**: `gala_launchpad_unlock_tokens` **MCP Prompt**: `/galachain-launchpad:unlock-token` **Demo**: `npm run demo:locks` --- ## Bridgeable Token Discovery These methods read the DEX API's token list (`canBridgeTo`) through gala-core-sdk's bridge module, which the app hands to the SDK and the SDK loads on the first bridge call: `new LaunchpadSDK({ ..., bridge: () => import('@gala-chain/gala-core-sdk/bridge') })` (it needs `ethers`, `@solana/web3.js` and `@solana/spl-token` installed). Without that loader every bridge, wrap and bridgeable-token method throws a `ConfigurationError` (`field: 'bridge'`) naming it. `fetchAll...` results and the per-token checks are cached per network for the SDK's lifetime after the first fetch. **Errors** (all seven): failures reading the token list surface as gala-core-sdk's `GalaSDKError` (import it from `@gala-chain/gala-core-sdk`): `TRANSPORT_ERROR` (no answer), `GALACONNECT_HTTP_ERROR` (HTTP error status), `BRIDGE_READ_RESPONSE_INVALID` (not a token list) or `PAGINATION_LIMIT_EXCEEDED`. The `isTokenBridgeable...` checks refuse a `tokenId` that is not a class key before any read. ### fetchBridgeableTokensByNetwork(options) **Description**: Fetch one page of the tokens bridgeable to a network. **Parameters**: - `options` (`FetchBridgeableTokensOptions`): - `network` (`'ETHEREUM'` | `'SOLANA'`): Target network - `offset` (number, optional): Pagination offset (default 0) - `limit` (number, optional): Results per page (default and maximum 1000) **Returns**: `Promise` - `tokens`: array of `BridgeableToken` (`symbol`, `name`, `decimals`, `galaChainDescriptor`, `stringifiedTokenClassKey`, `verified`, `supportedChains`, `ethereumContractAddress?`, `solanaContractAddress?`, `image?`, `description?`) - `network`: the queried network - `tokenCount`: tokens in this result - `fetchedAt`: timestamp (ms) of the fetch **Example**: ```typescript const result = await sdk.fetchBridgeableTokensByNetwork({ network: 'ETHEREUM', limit: 50, offset: 0 }); console.log(`Found ${result.tokenCount} Ethereum bridgeable tokens`); result.tokens.forEach(token => { console.log(`${token.symbol}: ${token.ethereumContractAddress}`); }); ``` **MCP Tool**: `gala_launchpad_fetch_bridgeable_tokens_by_network` **Demo**: `npm run demo:bridge:bridgeable` --- ### fetchAllBridgeableTokensByNetwork(network) **Description**: Fetch ALL bridgeable tokens for a network, walking the pages (1000 per request). The result is cached per network. **Parameters**: - `network` (`'ETHEREUM'` | `'SOLANA'`): Target network **Returns**: `Promise` All bridgeable tokens for the network **Example**: ```typescript // Fetch all Ethereum bridgeable tokens const result = await sdk.fetchAllBridgeableTokensByNetwork('ETHEREUM'); console.log(`Total Ethereum tokens: ${result.tokenCount}`); // Find GALA token const gala = result.tokens.find(t => t.symbol === 'GALA'); console.log(`GALA contract: ${gala?.ethereumContractAddress}`); ``` **MCP Tool**: `gala_launchpad_fetch_all_bridgeable_tokens_by_network` **Demo**: `npm run demo:bridge:bridgeable` --- ### fetchAllTokensBridgeableToEthereum() **Description**: Convenience method to fetch all Ethereum bridgeable tokens. **Returns**: `Promise` Equivalent to `fetchAllBridgeableTokensByNetwork('ETHEREUM')` **Example**: ```typescript const result = await sdk.fetchAllTokensBridgeableToEthereum(); console.log(`${result.tokenCount} tokens can bridge to Ethereum`); // List tokens with contract addresses result.tokens.forEach(token => { console.log(`${token.symbol}: ${token.ethereumContractAddress}`); }); ``` **MCP Tool**: `gala_launchpad_fetch_all_tokens_bridgeable_to_ethereum` --- ### fetchAllTokensBridgeableToSolana() **Description**: Convenience method to fetch all Solana bridgeable tokens. **Returns**: `Promise` Equivalent to `fetchAllBridgeableTokensByNetwork('SOLANA')` **Example**: ```typescript const result = await sdk.fetchAllTokensBridgeableToSolana(); console.log(`${result.tokenCount} tokens can bridge to Solana`); // List tokens with mint addresses result.tokens.forEach(token => { console.log(`${token.symbol}: ${token.solanaContractAddress}`); }); ``` **MCP Tool**: `gala_launchpad_fetch_all_tokens_bridgeable_to_solana` --- ### isTokenBridgeableToNetwork(options) **Description**: Check if a token can be bridged to a specific network. The token is given by class key, not by symbol. **Parameters**: - `options` (`IsTokenBridgeableOptions`): - `tokenId` (`TokenId`): class key string (e.g. `'GALA|Unit|none|none'`) or `{ collection, category, type, additionalKey }` - `network` (`'ETHEREUM'` | `'SOLANA'`): Target network **Returns**: `Promise` - `isBridgeable`: boolean - `network`: the checked network - `tokenSymbol?`: the token's symbol, only when the token is in the bridgeable list - `contractAddress?`: the token's contract (Ethereum) or mint (Solana) address, when bridgeable **Example**: ```typescript const result = await sdk.isTokenBridgeableToNetwork({ tokenId: 'GALA|Unit|none|none', network: 'ETHEREUM' }); if (result.isBridgeable) { console.log(`${result.tokenSymbol} can bridge to Ethereum`); console.log(`Contract: ${result.contractAddress}`); } else { console.log('Not bridgeable to Ethereum'); } ``` **MCP Tool**: `gala_launchpad_is_token_bridgeable_to_network` **Demo**: `npm run demo:bridge:bridgeable` --- ### isTokenBridgeableToEthereum(tokenId) **Description**: Convenience method to check Ethereum bridgeability. **Parameters**: - `tokenId` (`TokenId`): class key string or object **Returns**: `Promise` Equivalent to `isTokenBridgeableToNetwork({ tokenId, network: 'ETHEREUM' })` **Example**: ```typescript const result = await sdk.isTokenBridgeableToEthereum('GALA|Unit|none|none'); if (result.isBridgeable) { console.log(`GALA Ethereum contract: ${result.contractAddress}`); } ``` **MCP Tool**: `gala_launchpad_is_token_bridgeable_to_ethereum` **Demo**: `npm run demo:bridge:bridgeable` --- ### isTokenBridgeableToSolana(tokenId) **Description**: Convenience method to check Solana bridgeability. **Parameters**: - `tokenId` (`TokenId`): class key string or object **Returns**: `Promise` Equivalent to `isTokenBridgeableToNetwork({ tokenId, network: 'SOLANA' })` **Example**: ```typescript const result = await sdk.isTokenBridgeableToSolana('GALA|Unit|none|none'); if (result.isBridgeable) { console.log(`GALA Solana mint: ${result.contractAddress}`); } ``` **MCP Tool**: `gala_launchpad_is_token_bridgeable_to_solana` **Demo**: `npm run demo:bridge:bridgeable` --- ## Price History `fetchPriceHistory`, `fetchAllPriceHistory` and `fetchGalaPrice` are not LaunchpadSDK methods any more. Price series and DEX prices are gswap-sdk's market reads: ```typescript const key = await sdk.resolveTokenClassKey('anime'); // a launchpad token's class key const series = await gSwap.market.getPriceSeries(key, '1W'); // '1D' | '1W' | '1M' | '1Y' | 'ALL'; one read answers the whole series const gala = await gSwap.market.getPrice('GALA|Unit|none|none'); // MarketPrice | undefined ``` The MCP tools `gala_launchpad_fetch_price_history`, `gala_launchpad_fetch_all_price_history` and `gala_launchpad_fetch_gala_spot_price` still work (they call gswap-sdk). See `MIGRATING-TO-9.0.md`. --- ## Utility Methods ### cleanup() **Description**: Release the SDK's resources: flushes the event batcher (waiting up to 5 seconds), cleans up the HTTP interceptors and disconnects the WebSocket connections. Call it on application shutdown. It is best-effort: a failure inside it is logged, not thrown. **Returns**: `Promise` **Example**: ```typescript const sdk = createLaunchpadSDK({ wallet: process.env.PRIVATE_KEY! }); try { // Use the SDK... } finally { await sdk.cleanup(); } ``` `LaunchpadSDK.cleanupAll()` is the static form that cleans up the shared WebSocket service across instances. **MCP Tool**: `gala_launchpad_cleanup` **MCP Prompt**: `/galachain-launchpad:cleanup` **Demo**: most demos end with `sdk.cleanup()` (for example `npm run demo:comments`) --- ## Live Streaming A token's stream state (status, playback ID, viewers, next scheduled show) is read from `fetchToken(tokenName)`: there is no separate stream-info method. **Authentication**: `startStream`, `resetStreamKey`, `getRecordingDownload`, `deleteRecording`, `addSimulcastTarget` and `removeSimulcastTarget` use the logged-in session (`sdk.login()`), and throw a `ConfigurationError` without one. `enableStream` and `disableStream` use the `streamAdminApiKey` config when one is set and otherwise the session. `setGlobalStreamingEnabled` needs `streamAdminApiKey` (`ConfigurationError` without it). `getSimulcastTargets` uses the session too (owner-only). `getStreamRecordings` and `getGlobalStreamingStatus` are public reads. Every method taking a `tokenName` throws a `ValidationError` for a name that is not 1-255 letters and digits (the stream routes take the name from the path and check no format), and a `NetworkError` when the request fails. ### startStream(tokenName) **Description**: Start or initialize a stream for a token pool and get its ingest credentials. **Parameters**: - `tokenName` (string): Token name (required) **Returns**: `Promise` - `tokenName`, `createdAt`: ISO 8601 timestamp - `playbackUrl`: HLS playback URL - `playbackId`: string - `status`: `'IDLE'` | `'ACTIVE'` | `'DISABLED'` (as a string) - `streamKey`: string (for OBS or another encoder) - `rtmpsUrl`: RTMPS ingest URL - `srtUrl`, `srtPassphrase`: SRT ingest URL and passphrase **Example**: ```typescript const stream = await sdk.startStream('mytoken'); console.log(`RTMPS URL: ${stream.rtmpsUrl}`); console.log(`Stream Key: ${stream.streamKey}`); console.log(`Playback: ${stream.playbackUrl}`); ``` **MCP Tool**: `gala_launchpad_start_stream` **MCP Prompt**: `/galachain-launchpad:start-stream` **Demo**: `npm run demo:streaming`, `npm run demo:streaming:lifecycle` --- ### resetStreamKey(tokenName) **Description**: Generate a new stream key (invalidates the old key). **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise`: the stream credentials (`streamKey`, `rtmpsUrl`, `srtUrl`, `srtPassphrase`, `playbackId`, `status`) plus `tokenName` and `resetAt` (ISO 8601) **MCP Tool**: `gala_launchpad_reset_stream_key` **MCP Prompt**: `/galachain-launchpad:reset-stream-key` **Demo**: `npm run demo:streaming:key-management`, `npm run demo:streaming:lifecycle` --- ### getStreamRecordings(options) **Description**: List the recordings of a token's streams. **Parameters**: - `options` (`FetchRecordingsOptions`): - `tokenName` (string): Token name The route takes no paging: the backend lists every recording of the token. **Returns**: `Promise` - `recordings`: array of `StreamRecording` (`id` (the Mux asset ID), `playbackId`, `status`, `duration` seconds, `createdAt`, `masterAccess`, `aspectRatio?`, `assets?`) - `tokenName` **Errors**: a `NetworkError` with `statusCode` 404 for a token that does not exist. **Example**: ```typescript const { recordings } = await sdk.getStreamRecordings({ tokenName: 'mytoken' }); console.log(`${recordings.length} recordings`); recordings.forEach(r => console.log(`${r.id}: ${r.duration}s (${r.status})`)); ``` **MCP Tool**: `gala_launchpad_get_stream_recordings` **MCP Prompt**: `/galachain-launchpad:get-stream-recordings` **Demo**: `npm run demo:streaming:recordings`, `npm run demo:streaming:recordings-management` --- ### getRecordingDownload(tokenName, assetId) **Description**: Get the download state and URL of a recording's master file. **Parameters**: - `tokenName` (string): Token name - `assetId` (string): the recording's `id`, exactly as listed (Mux asset IDs are case-sensitive) **Returns**: `Promise`: `{ status: 'none' | 'preparing' | 'ready' | 'errored', url?: string }` (`url` only when `ready`) **Errors**: also `ValidationError` for an empty `assetId`. **MCP Tool**: `gala_launchpad_get_recording_download` **MCP Prompt**: `/galachain-launchpad:get-recording-download` **Demo**: `npm run demo:streaming:recordings` --- ### deleteRecording(tokenName, assetId) **Description**: Delete a recording permanently. **Parameters**: - `tokenName` (string): Token name - `assetId` (string): the recording's `id`, exactly as listed **Returns**: `Promise` **Errors**: also `ValidationError` for an empty `assetId`. **MCP Tool**: `gala_launchpad_delete_recording` **MCP Prompt**: `/galachain-launchpad:delete-recording` **Demo**: `npm run demo:streaming:recordings` --- ### getSimulcastTargets(tokenName) **Description**: List the configured simulcast targets. **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise`: `{ targets: SimulcastTarget[], tokenName }`. A target is `{ id, url, status, passthrough? }` (`passthrough` is the platform unless one was given). Owner-only: uses the logged-in session. **MCP Tool**: `gala_launchpad_get_simulcast_targets` **MCP Prompt**: `/galachain-launchpad:get-simulcast-targets` **Demo**: `npm run demo:streaming:simulcast` --- ### addSimulcastTarget(options) **Description**: Add a simulcast destination (YouTube, Twitch, Facebook or a custom RTMP endpoint). **Parameters**: - `options` (`AddSimulcastTargetOptions`): - `tokenName` (string): Token name - `platform` (`'youtube'` | `'twitch'` | `'facebook'` | `'custom'`, lowercase) - `url` (string): the target's RTMP or RTMPS URL, at most 2048 characters (a `ValidationError` for any other, SRT included) - `streamKey` (string): the target's stream key, at most 255 characters - `passthrough` (string, optional): free text kept with the target, at most 255 characters **Returns**: `Promise`: `{ target: SimulcastTarget, tokenName }` **MCP Tool**: `gala_launchpad_add_simulcast_target` **MCP Prompt**: `/galachain-launchpad:add-simulcast-target` **Demo**: `npm run demo:streaming:simulcast`, `npm run demo:streaming:simulcast-multi-platform` --- ### removeSimulcastTarget(tokenName, targetId) **Description**: Remove a simulcast target. **Parameters**: - `tokenName` (string): Token name - `targetId` (string): the target's `id`, exactly as listed **Returns**: `Promise` **MCP Tool**: `gala_launchpad_remove_simulcast_target` **MCP Prompt**: `/galachain-launchpad:remove-simulcast-target` **Demo**: `npm run demo:streaming:simulcast` --- ### disableStream(tokenName) **Description**: Disable streaming for a token (admin API key, or the token owner's session). **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise<{ enabled: boolean; tokenName: string }>` **MCP Tool**: `gala_launchpad_set_stream_enabled` (with `enabled: false`) **MCP Prompt**: `/galachain-launchpad:disable-stream` --- ### enableStream(tokenName) **Description**: Enable streaming for a token (admin API key, or the token owner's session). **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise<{ enabled: boolean; tokenName: string }>` **MCP Tool**: `gala_launchpad_set_stream_enabled` (with `enabled: true`) **MCP Prompt**: `/galachain-launchpad:enable-stream` --- ### getGlobalStreamingStatus() **Description**: Get the platform-wide streaming status. **Returns**: `Promise`: `{ enabled: boolean, updatedAt?: string, updatedBy?: string }` **MCP Tool**: `gala_launchpad_get_global_streaming_status` **Demo**: `npm run demo:streaming`, `npm run demo:streaming:admin` --- ### setGlobalStreamingEnabled(enabled) **Description**: Enable or disable streaming platform-wide (needs the `streamAdminApiKey` config). **Parameters**: - `enabled` (boolean) **Returns**: `Promise` **MCP Tool**: `gala_launchpad_set_global_streaming_enabled` **Demo**: `npm run demo:streaming:admin` --- ## Stream Chat There is no platform-wide chat switch in the SDK: chat is enabled or disabled per token. ### getChatMessages(options) **Description**: Get one page of chat messages, by token or by author. A public read. **Parameters**: - `options` (`GetChatMessagesOptions`): - `tokenName` (string, optional): filter by token - `userAddress` (string, optional): filter by author - `cursor` (string, optional): the previous page's `pageInfo.endCursor` - `pageSize` (number, optional): default 10, at most 50 **Returns**: `Promise` - `messages`: array of `Message` (`id` and `messageId` (the same string), `tokenName`, `userAddress`, `user`, `content`, `createdAt`, `updatedAt`, `deletedAt`, `flagCount`, `reactions: { counts, userReacted? }`; a list item has no `holderTier`) - `pageInfo`: the backend's `{ hasNextPage, endCursor, hasPreviousPage, startCursor }` (`endCursor` is `null` on the last page) **Example**: ```typescript const chat = await sdk.getChatMessages({ tokenName: 'mytoken', pageSize: 20 }); chat.messages.forEach(msg => console.log(`${msg.userAddress}: ${msg.content}`)); ``` **Errors**: - `ValidationError`: `tokenName` is not valid - `NetworkError`: the request failed **MCP Tool**: `gala_launchpad_get_chat_messages` **MCP Prompt**: `/galachain-launchpad:get-chat-messages` **Demo**: `npm run demo:chat` --- ### sendChatMessage(options) **Description**: Send a chat message through the REST API. Needs a login session (`sdk.login()`). **Parameters**: - `options` (`CreateChatMessageOptions`): - `tokenName` (string): Token name (required) - `content` (string): message content, 1-500 characters **Returns**: `Promise`: `{ message: SentChatMessage }` (`messageId`, `tokenName`, `content`, `userAddress`, `createdAt`, `user?`, `holderTier?`; a send carries no database `id`) **Errors**: - `ValidationError`: `tokenName` is not valid, or `content` is empty or over 500 characters - `ConfigurationError`: no login session - `NetworkError`: the request failed **MCP Tool**: `gala_launchpad_send_chat_message` **MCP Prompt**: `/galachain-launchpad:send-chat-message` **Demo**: `npm run demo:chat` --- ### getTokenConfig(tokenName) **Description**: Read a token's chat and comments switches. There is no standalone chat-status method: `chatEnabled` and `commentsEnabled` of the token configuration are the chat status. A public read. **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise`: `{ chatEnabled?: boolean, commentsEnabled?: boolean, ...other configuration fields }` **Example**: ```typescript const config = await sdk.getTokenConfig('mytoken'); console.log(`Chat enabled: ${config.chatEnabled}`); ``` **Errors**: - `ValidationError`: `tokenName` is empty or not valid - `Error`: the backend returned no configuration data - `NetworkError`: the request failed **MCP Tool**: `gala_launchpad_get_chat_status` (reads this configuration) **MCP Prompt**: `/galachain-launchpad:get-chat-status` **Demo**: `npm run demo:chat` --- ### disableChat(tokenName) / enableChat(tokenName) **Description**: Turn chat off or on for a token. Uses the `streamAdminApiKey` config when set, otherwise the token owner's session. An admin disable locks the owner out of re-enabling. **Parameters**: - `tokenName` (string): Token name **Returns**: `Promise<{ enabled: boolean; tokenName: string; status?: string }>` **Errors**: - `ValidationError`: `tokenName` is empty or not valid - `ConfigurationError`: neither an admin API key nor a login session is available - `NetworkError`: the request failed (for example the owner enabling an admin-disabled chat) **MCP Tool**: `gala_launchpad_set_chat_enabled` **MCP Prompt**: `/galachain-launchpad:disable-chat`, `/galachain-launchpad:enable-chat` **Demo**: `npm run demo:chat` --- ### connectStreamWebSocket(callbacks?) **Description**: Connect to the stream WebSocket server. **Parameters**: - `callbacks` (`StreamEventCallbacks`, optional): global handlers, such as `onStreamStatus`, `onViewerCount`, `onChatMessage`, `onChatStatus` **Returns**: `Promise` **Example**: ```typescript await sdk.connectStreamWebSocket({ onChatMessage: event => console.log('chat:', event), }); console.log(`Connected: ${sdk.isStreamWebSocketConnected()}`); ``` Sending chat over the socket also needs `await sdk.authenticateStreamWebSocket()`. **MCP Tool**: `gala_launchpad_connect_stream_websocket` **MCP Prompt**: `/galachain-launchpad:connect-stream-websocket` **Demo**: `npm run demo:chat:websocket` --- ### subscribeToStream(tokenName, callbacks?) **Description**: Subscribe to a token's real-time stream events. **Parameters**: - `tokenName` (string): Token name - `callbacks` (`StreamEventCallbacks`, optional): handlers for this token (`onStreamStatus`, `onViewerCount`, `onChatMessage`, `onChatStatus`, ...) **Returns**: `Promise`: `{ room, tokenName }` **MCP Tool**: `gala_launchpad_subscribe_to_stream` **MCP Prompt**: `/galachain-launchpad:subscribe-to-stream` **Demo**: `npm run demo:chat:websocket` --- ### sendStreamChatViaWebSocket(tokenName, content) **Description**: Send a chat message over the WebSocket (lower latency). Returns immediately; the socket's `onChatSent` and `onChatError` callbacks report the outcome. **Parameters**: - `tokenName` (string): Token name - `content` (string): message content **Returns**: `void` **Errors**: - `ValidationError`: `tokenName` or `content` is empty, the WebSocket is not connected (`NOT_CONNECTED`), or it is not authenticated (`NOT_AUTHENTICATED`; call `authenticateStreamWebSocket()`) **MCP Tool**: `gala_launchpad_send_stream_chat_via_web_socket` **MCP Prompt**: `/galachain-launchpad:send-stream-chat-websocket` **Demo**: `npm run demo:chat:websocket` --- ### unsubscribeFromStream(tokenName) **Description**: Unsubscribe from a token's stream events. **Parameters**: - `tokenName` (string): Token name **Returns**: `void` **MCP Tool**: none **Demo**: `npm run demo:chat:websocket` --- ### disconnectStreamWebSocket() **Description**: Disconnect from the stream WebSocket server. **Returns**: `void` **MCP Tool**: none **Demo**: `npm run demo:chat:websocket` --- ## Service Clients **Note**: `LaunchpadSDK` has two public members beyond its methods: `sdk.events` and `sdk.launchpad`. It has no DEX client (the former `sdk.dex` is gone: build gswap-sdk's `GSwap` yourself, see "The DEX is gswap-sdk's"), and no `sdk.dexBackendClient` or `sdk.galaChainGatewayClient` accessor; the SDK's internal HTTP clients are private and have no supported direct-access path. ### sdk.events **Description**: The SDK's `EventsBatcherService`: it batches client events and sends them to the launchpad backend (lazy: created on first access). **Methods**: - `track(eventType, payload, options?)`: queue an event; `options` is `{ userAddress?, tokenName?, sessionId?, immediate? }` - `flush()`: send the queue now - `getStats()`: `{ bufferedCount, totalQueued, totalFlushed, totalDropped, ... }` - `configure(options)`: change the batching settings - `shutdown(timeoutMs = 5000)`: flush and stop **Example**: ```typescript sdk.events.track('page_view', { path: '/tokens/anime' }, { tokenName: 'anime' }); await sdk.events.flush(); ``` ### sdk.launchpad **Description**: `LaunchpadWrites`, the SDK's write surface that returns a `BundleSubmission` (call `.wait()` on it for the result) instead of waiting for the WebSocket confirmation as `launchToken`, `buy` and `sell` do. **Methods**: - `createSale(input)`: create a token sale (`CreateSaleInput`: the `launchToken` fields with `tokenImage` as a URL) - `buyWithNative(input)`, `buyExactToken(input)`, `sellWithNative(input)`, `sellExactToken(input)`: `LaunchpadTradeInput` is `{ vaultAddress, quantity, expectedAmount, extraFees?, tokenName?, uniqueKey? }` **Example**: ```typescript const submission = await sdk.launchpad.buyWithNative({ vaultAddress: 'client|example-token', quantity: '100', expectedAmount: '1' }); await submission.wait(); ``` --- ## Error Reference ### Common Error Types The classes below are exported from the package (defined in `src/utils/errors.ts`) and are thrown by the SDK. **NetworkError** (`statusCode?`, `originalError?`, and the backend's answer: `serverMessage?`, `serverError?`, `details?`, `body?`): a request failed, or the backend answered with an error - `serverMessage`: the body's `message`, the text the launchpad backend means the user to read (its error bodies are `{ status, error: true, message }` and `{ statusCode, message }`); an array of validation messages is joined with `,` - `serverError`: the body's `error` when it is a string (the launchpad backend's `error: true` is not one) - `details`, `body`: the body's `details`, and the whole body (parsed JSON, or the text of a non-JSON answer) - A NetworkError a service builds from the HTTP client's (`"Failed to ...: HTTP GET ..."`) keeps the answer (and, through the services' `withErrorHandling` wrap, the status). ```typescript import { NetworkError } from '@gala-chain/launchpad-sdk'; try { const result = await sdk.fetchPools(); } catch (error) { if (error instanceof NetworkError) { console.log(`Request failed (status ${error.statusCode}): ${error.serverMessage ?? error.message}`); } } ``` **ValidationError** (`field?`, `code?`): an input was rejected before or after a request ```typescript await sdk.fetchPools({ tokenName: 'x' }); // → ValidationError, field 'tokenName': not a valid token name ``` **ConfigurationError** (`field?`): the SDK is missing something it needs (a login session, an admin key, a client) ```typescript await sdk.startStream('mytoken'); // no sdk.login() yet // → ConfigurationError: JWT authentication required. Call sdk.login() first. ``` **TransactionError** (`transactionId?`, `code?`): a trade or launch submission produced no transaction ```typescript await sdk.buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: '1' }); // → TransactionError: No transaction ID returned from buy operation ``` `TokenRestrictedError` (a `ValidationError` subclass) and the `ERROR_CODES` constants are exported too, but nothing in the SDK throws `TokenRestrictedError` at present. **Errors of specific operations** (exported from the package; read their `type` or `code`): | Class | Thrown by | |---|---| | `TransferError` (`TransferErrorType`) | `transferGala`, `transferToken`, `resolveTokenClassKey` | | `LockError` (`LockErrorType`) | `lockTokens`, `unlockTokens` | | `LaunchpadSDKError` (`code`, `status?`) | `launchToken` (signing and bundler failures) | | `TransactionFailedError`, `WebSocketError` | the WebSocket confirmation of `buy`, `sell`, `graduateToken`, `launchToken` | | `FileValidationError` | `uploadTokenImage` | | `GalaSDKError` (from `@gala-chain/gala-core-sdk`) | the bridgeable-token reads | --- ## Version History - **v9.0.0** (current): launchpad-only: no `sdk.dex`, no `GSwap` re-export, no DEX price reads; gateway-generic pieces come from `@gala-chain/gala-core-sdk` (see `MIGRATING-TO-9.0.md`) - **v6.0.0**: `getStreamInfo()` removed; streaming fields are part of `fetchToken()`'s `PoolData` - **v4.0.0**: `fetchLaunchpadTokenSpotPrice()` deprecated in favour of `fetchTokenPrice()` - **v3.33.0**: token identifiers accepted only in delimited format (the swap methods this applied to are gswap-sdk's now) - **v3.25.0**: GalaSwap liquidity position management (gswap-sdk's now) - **v3.12.0**: CommonJS build support The full history is in `CHANGELOG.md` in the package root. --- ## Quick Reference by Category | Category | Key Methods | Common Flow | |----------|------------|-------------| | **Pool Discovery** | fetchPools, fetchAllPools, fetchPoolDetails, fetchToken | Discovery → Details → Action | | **Bonding Curve Trading** | calculateBuyAmount, buy, calculateSellAmount, sell, graduateToken | Quote → Execute → Verify | | **Balance Checking** | fetchGalaBalance, fetchTokenBalance, fetchTokensHeld | Check balance → Act | | **Token Creation** | validateToken, uploadTokenImage, launchToken | Validate → Upload → Launch | | **Price Data** | fetchTokenPrice (launchpad tokens); gSwap.market.getPrice, gSwap.market.getPriceSeries (gswap-sdk) | Get price → Analyze → Trade | | **DEX (gswap-sdk)** | gSwap.quoting, gSwap.swaps, gSwap.pools, gSwap.positions | see "The DEX is gswap-sdk's" | --- ## Next Steps - [Full Examples](/launchpad-sdk/next/examples.md) - [Migrating to 9.0](/launchpad-sdk/next/migrating-to-9.md) --- # WebSocket and real-time updates The SDK streams Launchpad events over one socket.io connection, owned by `StreamWebSocketService` (`sdk.realtime` on a `LaunchpadSDK`, or `new StreamWebSocketService({ url })` on its own). Every `subscribe*` call returns its own unsubscribe; a room is joined once, on its first subscriber, and left on its last. ## Where to start - [Quick start](/launchpad-sdk/next/websocket/quickstart.md): subscribe to the global feed and one token's room in a few lines. - [Global feed](/launchpad-sdk/next/websocket/global-feed.md): one subscription that carries a summary of every token and the site-wide switches. - [Authentication](/launchpad-sdk/next/websocket/authentication.md): authenticating the socket (user and overseer events, chat), token refresh and reconnects. ## Event groups Each event has a callback key (`onX`, in the callback objects `subscribeToGlobalFeed` and `connectStreamWebSocket` take) and a typed method form (`sdk.onX` or `service.subscribe*`). Global feed, token events (a summary of every token, no room to join): ```text onStreamStatus, onTradeExecuted, onHolderCountUpdated, onPoolBadgeAssigned, onViewerCount, onTokenConfigUpdated, onStatsUpdated, onPoolCreated ``` Global feed, site configuration events (platform-wide switches): ```text onSiteConfigChanged, onStreamGlobalStatus, onChatGlobalStatus, onCommentsGlobalStatus, onWebhooksGlobalStatus, onAIModerationGlobalStatus ``` A token's room (detail for one token; joined by `subscribeToStream(tokenName)` or `service.joinTokenRoom(tokenName)`): ```text onChatMessage, onChatUpdated, onChatDeleted, onChatPinned, onChatUnpinned, onTypingIndicator, onReaction, onContentReactionAdded, onContentReactionRemoved, onViewerCount, onStreamStatus, onRecordingStatus, onSimulcastStatus, onEngagementStatsUpdated, onTradeExecuted, onBalanceUpdated ``` The complete, typed list is `RealtimeEventPayloads` (every event name and its payload) and `StreamEventCallbacks` / `GlobalFeedEventCallbacks` (every callback key), both exported by the SDK. ## Example ```typescript import { StreamWebSocketService } from '@gala-chain/launchpad-sdk'; const service = new StreamWebSocketService({ url: 'wss://stream.example.com' }); // Joins the global feed once the socket is up; returns this subscription's own unsubscribe. const unsubscribe = service.subscribeToGlobalFeed({ onStreamGlobalStatus: (event) => { console.log(`Streaming ${event.enabled ? 'enabled' : 'disabled'}`); }, }); // Later: leave the feed (the room is left when the last subscriber is released). unsubscribe(); service.disconnect(); ``` ## FAQ **What is the difference between the global feed and a token room?** The global feed broadcasts summary events for every token and the site configuration to every client. A token room carries the detailed events of one token (chat, reactions, moderation). **Can I filter events on the server?** No. Subscribe to the global feed and filter in your callback. **Do I unsubscribe manually?** Every `subscribe*` call returns its own unsubscribe; call it (in React, return it from the effect). `service.disconnect()` releases everything. **Can several components subscribe?** Yes, to the same event, token or room: each is its own subscriber, a room is joined once on the first subscriber and left on the last, and one subscriber that throws never stops the others. **How do I refresh an expired token?** See [Authentication](/launchpad-sdk/next/websocket/authentication.md): pass a `tokenProvider` that answers with the token current at that moment. --- # WebSocket quick start Real-time updates from Launchpad in a few lines. The SDK owns one socket.io connection (`StreamWebSocketService`); the global feed is public, so it needs no authentication. ## Installation ```bash npm install @gala-chain/launchpad-sdk@next @gala-chain/gala-core-sdk@next ``` ## 1. Subscribe to the global feed ```typescript import { StreamWebSocketService } from '@gala-chain/launchpad-sdk'; const service = new StreamWebSocketService({ url: 'wss://stream.example.com' }); // Opens the socket, joins the feed once connected, and returns this subscription's own unsubscribe. const unsubscribe = service.subscribeToGlobalFeed({ onTradeExecuted: (event) => { console.log(`Trade on ${event.tokenName}: ${event.tradeType}`); }, onStreamGlobalStatus: (event) => { console.log(`Streaming ${event.enabled ? 'enabled' : 'disabled'}`); }, }); ``` The same service is `sdk.realtime` on a `LaunchpadSDK` built with a `streamWebSocketUrl`. ## 2. One callback for every token event ```typescript continue const stop = service.subscribeFeedTokenEvents((feedEvent) => { // `feedEvent.event` names the event; `feedEvent.data` is its payload. console.log(feedEvent.event, feedEvent.data.tokenName); }); ``` ## 3. Filter on the client The server filters nothing: subscribe to the feed and filter in your callback. ```typescript continue const watched = new Set(['anime', 'dragnrkti']); const unsubscribeFiltered = service.subscribeToGlobalFeed({ onTradeExecuted: (event) => { if (watched.has(event.tokenName)) console.log(`Trade on watched token ${event.tokenName}`); }, }); ``` ## 4. A token's room ```typescript continue // Detailed events of one token: chat, reactions, viewers, status. const leave = service.subscribeToken('STREAM_CHAT_MESSAGE', 'anime', (event) => { console.log(`[${event.user?.fullName ?? event.userAddress}]: ${event.content}`); }); ``` ## 5. Authenticate for user events and chat ```typescript continue const authenticated = new StreamWebSocketService({ url: 'wss://stream.example.com', // Asked at every authentication and every reconnect: answer with the token current at that moment. tokenProvider: async () => process.env.APP_JWT ?? null, }); const ok = await authenticated.authenticate(); console.log(ok ? 'authenticated' : 'not authenticated'); ``` See [Authentication](/launchpad-sdk/next/websocket/authentication.md) for refresh and reconnect behavior. ## 6. React to reconnects and disconnects ```typescript continue const stopReconnect = service.onReconnect(() => { console.log('Reconnected: refetch what you rendered from the feed'); }); const stopState = service.onConnectionStateChange((connected) => { console.log(connected ? 'online' : 'offline'); }); ``` ## 7. Clean up ```typescript continue unsubscribe(); unsubscribeFiltered(); stop(); leave(); stopReconnect(); stopState(); service.disconnect(); authenticated.disconnect(); ``` ## Troubleshooting - **No events**: confirm `service.isConnected()`; the socket opens when the first subscription is registered (`autoConnect`, default `true`). - **Too many events**: filter in the callback, or subscribe to the one event you need (`service.subscribeFeed('TRADE_EXECUTED', listener)`). - **Memory**: every `subscribe*` call returns an unsubscribe; call it when the consumer goes away. ## Next steps - [Global feed](/launchpad-sdk/next/websocket/global-feed.md) - [Authentication](/launchpad-sdk/next/websocket/authentication.md) - [Overview](/launchpad-sdk/next/websocket/overview.md) --- # Global Feed WebSocket Guide The global feed (room `global:feed`) is one subscription that delivers a summary of every token and the site-wide switches, without joining each token's own room. It is what a homepage or a listing uses. ## What it carries Token events (the same payloads as in the token room; see `RealtimeEventPayloads`): | Event | Callback key | Payload type | |---|---|---| | `STREAM_STATUS` | `onStreamStatus` | `StreamStatusEvent` | | `TRADE_EXECUTED` | `onTradeExecuted` | `TradeExecutedEvent` (`tradeType` is `BUY`/`SELL`, `inputAmount`, `outputAmount`, `symbol?`, `icon?`) | | `HOLDER_COUNT_UPDATED` | `onHolderCountUpdated` | `HolderCountUpdatedEvent` | | `POOL_BADGE_ASSIGNED` | `onPoolBadgeAssigned` | `PoolBadgeAssignedEvent` (`badge` is a string) | | `VIEWER_COUNT` | `onViewerCount` | `ViewerCountEvent` | | `TOKEN_CONFIG_UPDATED` | `onTokenConfigUpdated` | `TokenConfigUpdatedEvent` (only the changed fields) | | `STATS_UPDATED` | `onStatsUpdated` | `StatsUpdatedEvent` | | `POOL_CREATED` | `onPoolCreated` | `PoolCreatedEvent` | Site-wide switches: `SITE_CONFIG_CHANGED` (`onSiteConfigChanged`, `{ key, value }`) and the feature switches `STREAM_GLOBAL_STATUS`, `STREAM_CHAT_GLOBAL_STATUS`, `COMMENTS_GLOBAL_STATUS`, `WEBHOOKS_GLOBAL_STATUS`, `AI_MODERATION_GLOBAL_STATUS` (`onStreamGlobalStatus`, `onStreamChatGlobalStatus`, `onCommentsGlobalStatus`, `onWebhooksGlobalStatus`, `onAIModerationGlobalStatus`, each `{ enabled }`). `getSiteConfigState()` returns the latest value of each switch since the feed was joined. The feed has no filters: filter by `tokenName` in the callback. ## Subscribing ```typescript import { StreamWebSocketService, getEnvironmentConfig } from '@gala-chain/launchpad-sdk'; const service = new StreamWebSocketService({ url: getEnvironmentConfig('prod').launchpadBaseUrl }); // Registers, opens the socket, joins the feed once connected. Returns THIS subscription's unsubscribe. const unsubscribe = service.subscribeToGlobalFeed({ onStreamStatus: (event) => console.log(`${event.tokenName}: ${event.status}`), onTradeExecuted: (event) => console.log(`${event.tradeType} ${event.inputAmount} ${event.tokenName}`), onStreamGlobalStatus: (event) => console.log(`streaming ${event.enabled ? 'on' : 'off'}`), }); // later unsubscribe(); service.disconnect(); ``` With a `LaunchpadSDK`, use `sdk.realtime` (the same service, built with your URL, your reconnect settings and your session's token). Other ways to subscribe to the feed, all sharing the one room: - one event: `subscribeStatsUpdated`, `subscribePoolCreated`, `subscribeStreamGlobalStatus`, `subscribeChatGlobalStatus`, `subscribeCommentsGlobalStatus`, `subscribeWebhooksGlobalStatus`, `subscribeAIModerationGlobalStatus`, `subscribeSiteConfigChanged`, or `subscribeFeed(event, listener)`; - every token event through one callback: `subscribeFeedTokenEvents((feedEvent) => ...)`, where `feedEvent` is `{ event: 'TRADE_EXECUTED', data: TradeExecutedEvent }` or one of the other seven (tell them apart by `event`, not by the shape of `data`). ## Rules the service keeps - **Any number of subscribers.** Each call is its own subscriber; none replaces another. The feed room is joined on the first and left on the last, never twice. - **Feed subscribers are served whether or not the token's room is joined.** The server sends one copy of an event to a client that is in both rooms; the service delivers it to the token subscribers and to the feed subscribers. - **A subscriber that throws** (or returns a rejecting promise) is logged and skipped; the others are served. - **Reconnects.** After a reconnect the service re-authenticates (if it was authenticated), re-joins the feed, then calls `onReconnect` listeners; refetch there what you missed. - **POOL_CREATED** reaches the feed and the overseer room: an overseer in both gets it once. ## See also - [Authentication](/launchpad-sdk/next/websocket/authentication.md) - [Quick start](/launchpad-sdk/next/websocket/quickstart.md) - `examples/global-feed-demo.ts`, `examples/global-feed-filtering-demo.ts`, `examples/site-config-demo.ts` --- # WebSocket Authentication Guide The stream socket is public until you authenticate it. Authenticating joins the connection to its user room and (for overseers) the overseer room, which is what delivers `BALANCE_UPDATED`, `API_KEY_*`, `USER_PROFILE_UPDATED`, `DOWNLOAD_READY`, `OVERSEER_*` and the moderation events, and what lets the connection send chat messages, reactions and typing events and join the overseers' events firehose. There is no token in the handshake: a static handshake token would be presented, expired, on every reconnect. The service sends an `authenticate` message instead, with the token current at that moment. ## With a `LaunchpadSDK` ```typescript // `wallet` as here, or an app `session` (see below) const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.PRIVATE_KEY! }); const freshJwt = process.env.APP_JWT ?? ''; await sdk.authenticateStreamWebSocket(); // the session's current token await sdk.authenticateStreamWebSocket(freshJwt); // right after the app refreshed its JWT sdk.deauthenticateStreamWebSocket(); // when the wallet disconnects ``` - With an app `session` the token is `session.accessToken()`; otherwise it is the SDK's own session token (`ensureValidToken()`, refreshed when near expiry). - `authenticateStreamWebSocket()` opens the connection if it is not open and resolves a **boolean**: `true` once the server confirms; `false` when the server rejects the token (`exception` or `stream_chat_auth_error`), does not answer within 10 seconds, the connection drops meanwhile, there is no token, or a newer `authenticateStreamWebSocket` / `deauthenticateStreamWebSocket` call replaced it. - The same token on the same connection is not sent twice. A different token replaces a pending one (that call resolves `false`) and is sent after the server answered the one in flight, so the server's final identity is always the newest token. - Changing the SDK's wallet (`setWallet`, `setWalletProvider`) deauthenticates the socket. ## Reconnects socket.io reconnects by itself. After every reconnect of a socket that was authenticated, the service asks for the token **current at that moment** (the `session`, never a remembered one), authenticates **first**, then re-joins every room that still has a subscriber, then calls the `onReconnect` listeners (refetch there what you missed). A socket that was never authenticated, or was deauthenticated, is not re-authenticated. ```typescript const stop = sdk.realtime.onReconnect(() => { console.log('Reconnected: refetch what the screen shows'); }); ``` ## `deauthenticate()` closes and reopens the connection The server has no message that drops a connection's identity (its user room and the overseer room stay joined until the connection closes). So `deauthenticate()` on an authenticated socket closes it and opens it again: subscriptions stay registered, the public rooms are joined again on the new connection, and `onReconnect` listeners fire. ## With a bare `StreamWebSocketService` ```typescript import { StreamWebSocketService, getEnvironmentConfig } from '@gala-chain/launchpad-sdk'; const service = new StreamWebSocketService({ url: getEnvironmentConfig('prod').launchpadBaseUrl, tokenProvider: async () => process.env.APP_JWT ?? null, // asked at every authentication and every reconnect }); const ok = await service.authenticate(); // the provider's token const ok2 = await service.authenticate(process.env.APP_JWT); // an explicit token ``` ## The overseers' firehose needs an authenticated overseer socket `subscribeEventsFirehose(listener, filters?)` registers the subscriber at once, but the server only admits an authenticated overseer to the room: the service joins it after `authenticate()` resolves `true` (and again after every re-authentication), once for all subscribers. The server applies no filters, so each subscriber's `filters` (`eventTypes`, `tokenName`, `userAddress`) are applied client-side. ## Security - Keep tokens out of logs and out of persistent browser storage where you can; prefer an httpOnly cookie session (`session` in `LaunchpadSDKConfig`) so the SDK never holds the token. - Use `wss://`. - Call `deauthenticateStreamWebSocket()` on logout and on wallet disconnect. # Gala MCP server 1.0.0-rc.9 (@gala-chain/gala-mcp-server) The Gala MCP server: wallet, bridge, Launchpad and GSwap DEX tools and prompts over stdio, in toolsets you select. --- # Use Gala from AI tools There are four ways to put Gala in reach of an AI assistant or agent. They are not alternatives to one another: the plugin runs the MCP server for you, and the agent guides and `llms.txt` are what an agent reads to write code instead of calling tools. | Way | What it is | Use it when | | --- | --- | --- | | The `omni-tool` plugin for Claude Code | A Claude Code plugin from the `gala-chain` marketplace: it starts the Gala MCP server and adds a teaching agent, three slash commands, a skill and a hook. Two smaller plugins, `launchpad` and `swap`, run the same server with fewer tools. | You use Claude Code and want one install that works and teaches. See [the omni-tool plugin](/gala-mcp-server/next/ai-tools/omni-tool-plugin.md). | | The MCP server `@gala-chain/gala-mcp-server` | The server on its own, over stdio, for any MCP client: Claude Code, Claude Desktop, Cursor or your own. 324 tools and 286 prompts in toolsets you select. | You use another client, you want to choose toolsets and environment yourself, or you build your own agent. See [MCP server setup](/gala-mcp-server/next/ai-tools/mcp-clients.md). | | The per-package agent guides | One short, task-oriented page per package at `//agents.md`: which package for which job, recipes, invariants with the test that enforces each, failures with their fix. | An agent writes application code against an SDK instead of calling tools. Start at [the agent guide of this package](/gala-mcp-server/next/agents.md). | | `llms.txt` and the machine-readable files | `/llms.txt` indexes every page as raw markdown, `/llms-full.txt` and `//llms-full.txt` carry whole packages, and `/mcp/tools.json` lists every tool with its parameters. | You feed documentation to a model or build your own retrieval. | ## Which one to choose - **You use Claude Code and want to start fast:** install the plugin. It configures the server with the `prod` network and no signing key, so the first session can only read. - **You use Claude Desktop, Cursor or another MCP client:** configure the server directly. The plugin is Claude Code only. - **You want a small tool surface:** select toolsets (`core`, `launchpad`, `gswap`), or install the `launchpad` or `swap` plugin. A smaller set costs the model less context and gives it fewer ways to be wrong. - **You want the model to write code, not call tools:** point it at the agent guide of the SDK and at `llms-full.txt`. Calling a tool is a signed action in your wallet; generating code is not. - **You are unsure whether to give an agent a key:** do not. Every read tool works without one. Read [security and keys](/gala-mcp-server/next/ai-tools/security.md) before you add a key. ## What is behind each way All of them end in the same three SDKs: `@gala-chain/gala-core-sdk` (wallets, signing, the GALA balance, bridging), `@gala-chain/launchpad-sdk` (the Launchpad backend) and `@gala-chain/gswap-sdk` (the GSwap DEX). The server wraps them as tools; the guides document them as code. An answer you get from a tool and the code an agent writes from the guide go through the same signing and the same address rules. ## Where to look things up - Every tool and prompt, with parameters, per toolset: the reference pages of this package, or `/mcp/tools.json` for machines. - Which docs answer a question, from inside a session: the `gala_launchpad_search_gala_docs` tool, which works offline too. - What went wrong: [troubleshooting](/gala-mcp-server/next/ai-tools/troubleshooting.md). --- # MCP server setup `@gala-chain/gala-mcp-server` is a stdio MCP server: the client starts it as a child process and talks to it over stdin and stdout. Every client below needs the same three things: the command that starts it, the environment it runs with, and a restart of the client after a change. ## The command ```bash npx -y @gala-chain/gala-mcp-server@next ``` `npx` fetches and runs the server, so nothing needs installing. To install it once instead: ```bash npm install -g @gala-chain/gala-mcp-server@next gala-mcp ``` The bin is `gala-mcp`. The server needs Node.js 20 or newer. While the server is a release candidate the tag is required: `@next` or the exact version, because a range such as `^1.0.0` matches no prerelease. The only command line flag is `--toolsets`. The server has no `--help`, and a flag it does not know is ignored rather than refused, so a mistyped flag silently does nothing: check the startup log instead. ```bash gala-mcp --toolsets core,gswap ``` ## Environment | Variable | Meaning | Default | | --- | --- | --- | | `ENVIRONMENT` | `prod` (the real GalaChain network) or `stage` (the test network). Anything else stops the server at startup. | `prod` | | `PRIVATE_KEY` | The signing key. Without it the server is read-only: every read works and a write says it needs a wallet. | unset | | `WALLET_ADDRESS` | An optional identity override, passed to the SDK as `galaChainAddress`. It must be the address of `PRIVATE_KEY`, or a `client\|` alias registered for it. | unset | | `GALA_TOOLSETS` | Comma list of `core`, `launchpad`, `gswap`. The `--toolsets` flag wins over it. | all | | `TIMEOUT` | Request timeout in milliseconds. | `30000` | | `DEBUG` | `true` for verbose logs on stderr. | unset | | `ETHEREUM_RPC_URL` | Ethereum RPC endpoint for bridge operations. | the SDK's endpoints | | `SOLANA_RPC_URL` | Solana RPC endpoint for bridge operations. | public Solana endpoints | | `SOLANA_PRIVATE_KEY` | Solana signing key, for bridge operations that need one. | unset | | `STREAM_WEBSOCKET_URL` | Custom stream WebSocket endpoint. | the SDK's endpoint | | `STREAM_ADMIN_API_KEY` | Stream administration access. | unset | | `USER_API_KEY` | User API authentication. | unset | | `GALA_DOCS_BASE_URL` | The docs site the documentation tools read. | `https://docs.gala.com` | | `GALA_DOCS_CACHE_DIR` | Where the fetched docs index is kept. | the user cache directory | | `GALA_DOCS_CACHE_TTL_SECONDS` | How long the cached docs index stays fresh. | `3600` | | `GALA_DOCS_OFFLINE` | `1` never asks the docs site; the bundled index answers. | unset | A configuration mistake (a malformed key, an `ENVIRONMENT` that is not `prod` or `stage`, a `WALLET_ADDRESS` that is not the key's address) is reported by every tool call with what to fix, so the assistant can tell you. ## Toolsets Without a selection the server loads every toolset. Selecting fewer keeps tools you will not use out of the model's context, and a toolset you do not select is never loaded. | Selection | Tools | Prompts | | --- | --- | --- | | all (default) | 324 | 286 | | `core` | 47 | 30 | | `core,launchpad` | 289 | 243 | | `core,gswap` | 79 | 64 | `core` holds the wallet, the session environment, the GALA balance and transfer, bridging and the documentation tools, so almost every selection should include it. `composite` is not selectable: it is enabled when `launchpad` and `gswap` both are. An unknown name, an empty entry or `composite` stops the server at startup with a message naming the valid toolsets. ## Claude Code Add the server to the current project, read-only on the test network: ```bash claude mcp add gala -e ENVIRONMENT=stage -- npx -y @gala-chain/gala-mcp-server@next ``` Only the part after `--` is the server's command; `-e` sets an environment variable of the server. Add `-s user` to make it available in every project, and `-e GALA_TOOLSETS=core,gswap` to select toolsets. Do not put a signing key on this command line: it lands in your shell history and in the client's configuration file in clear text. To share a configuration with a team without sharing a key, commit a project `.mcp.json` that reads the key from each person's own environment (Claude Code expands `${NAME}` in it): ```json { "mcpServers": { "gala": { "command": "npx", "args": ["-y", "@gala-chain/gala-mcp-server@next"], "env": { "ENVIRONMENT": "stage", "GALA_TOOLSETS": "core,gswap", "PRIVATE_KEY": "${GALA_STAGE_KEY}" } } } } ``` If `GALA_STAGE_KEY` is not set, Claude Code reports the missing variable instead of starting the server: that is the safe failure. Run `/mcp` in a session to see whether the server is connected. ## Claude Desktop Edit `claude_desktop_config.json` (Settings, Developer, Edit Config; on macOS it is under `~/Library/Application Support/Claude/`, on Windows under `%APPDATA%\Claude\`): ```json { "mcpServers": { "gala": { "command": "npx", "args": ["-y", "@gala-chain/gala-mcp-server@next"], "env": { "ENVIRONMENT": "prod" } } } } ``` Restart Claude Desktop. This file does not read your shell environment, so a key you add to its `env` block sits in that file in clear text: add one only for a wallet you would accept losing, and read [security and keys](/gala-mcp-server/next/ai-tools/security.md) first. ## Cursor Cursor reads the same `mcpServers` shape from `~/.cursor/mcp.json` (every project) or `.cursor/mcp.json` (one project): ```json { "mcpServers": { "gala": { "command": "npx", "args": ["-y", "@gala-chain/gala-mcp-server@next"], "env": { "ENVIRONMENT": "stage", "PRIVATE_KEY": "${env:GALA_STAGE_KEY}" } } } } ``` Cursor expands `${env:NAME}` from the environment it was started in. Restart Cursor, or toggle the server in its MCP settings, after a change. ## Any other stdio client An MCP client that launches stdio servers needs only the command, its arguments and the environment: ```json { "command": "gala-mcp", "args": ["--toolsets", "core,launchpad"], "env": { "ENVIRONMENT": "stage" } } ``` With the SDK of your own agent, start `gala-mcp` (or the `npx` command above) as a child process over stdio and list its tools. ## Check that it works The client's own server list says whether the process started. Then ask the assistant to run these, which read without a key: ```mcp gala_launchpad_get_environment({}) gala_launchpad_has_wallet({}) gala_launchpad_search_gala_docs({ query: 'which toolsets does the server have' }) ``` The server also logs its enabled toolsets and its tool and prompt counts to stderr at startup; most clients show a server's log in their MCP settings. The syntax of each client's own configuration file belongs to that client and can change; the server's side (the command, `--toolsets` and the environment variables above) is checked against the code in CI. --- # The omni-tool plugin for Claude Code `omni-tool` is a Claude Code plugin that connects Claude to the Gala MCP server and adds a teaching layer on top of it. It is published in the `gala-chain` plugin marketplace, a GitHub repository (`aschulergala/claude-plugin-marketplace`) that is separate from this package and versioned on its own. This page describes what the plugin does and how it relates to the server; the plugin's own repository is the authority for what a given plugin release contains. ## Install Inside Claude Code, add the marketplace once, then install the plugin: ```text /plugin marketplace add aschulergala/claude-plugin-marketplace /plugin install omni-tool ``` The same from a terminal: ```bash claude plugin marketplace add aschulergala/claude-plugin-marketplace claude plugin install omni-tool@gala-chain ``` Restart Claude Code afterwards so the server process starts with the plugin's environment. Then run `/omni-tool:setup`. ## What it ships | Part | What it does | | --- | --- | | MCP server entry | Starts `@gala-chain/gala-mcp-server` from a release-candidate range of the `1.x` line, with `ENVIRONMENT=prod` and no signing key. All toolsets are loaded: 324 tools and 286 prompts. | | Agent `galachain-builder` | A teaching and implementation partner for GalaChain applications. At session start it checks that the server answers and, if not, stops calling tools and shows the setup entry. | | Command `/omni-tool:setup` | Checks the server connection, explains `prod` versus `stage` and read-only versus signing, and saves teaching preferences (personality, code style, automatic explanations). | | Command `/omni-tool:ask` | Asks a question about GalaChain and answers it from the server's documented SDK examples. | | Command `/omni-tool:topics` | Lists the learning topics the server can explain. | | Skill `learning-galachain` | The workflow behind a lesson: concept, use case, steps, a current SDK example with the tools that match it, parameters, pitfalls and next topics. | | Hook on `gala_launchpad_*` results | After a tool call, if the result says the server is missing, stops further calls and points to `/omni-tool:setup`. For other errors it looks up the matching topic. | The topics come from the server's `gala_launchpad_explain_sdk_usage` tool, which has 68 topics in this version. The plugin keeps a local index of them for `/omni-tool:topics`; the server's own list is authoritative when they differ. ## The two smaller plugins The same marketplace also carries two plugins that run the same server with a toolset selection and nothing else, for a smaller tool surface: | Plugin | Toolsets | Tools | | --- | --- | --- | | `launchpad` | `core`, `launchpad` | 289 | | `swap` | `core`, `gswap` | 79 | Install either one with `/plugin install launchpad` or `/plugin install swap`. They carry no agent, commands or skill. Install one plugin of the three, not several: each starts its own copy of the server, and the model then sees every tool twice. ## How it relates to the MCP server The plugin is the server plus a teaching layer. It does not change what a tool does: every tool call goes through the same server, the same address rules and the same session wallet as in any other client. If you already configured the server yourself (for example with `claude mcp add`), installing the plugin starts a second server with the same tools. Keep one of them: remove yours with `claude mcp remove gala`, or do not install the plugin. To change the plugin's environment or toolsets, edit its server entry in your Claude Code configuration as `/omni-tool:setup` shows, or use the server directly with [MCP server setup](/gala-mcp-server/next/ai-tools/mcp-clients.md). ## Safety model - **Read-only until you add a key.** The plugin starts the server with no `PRIVATE_KEY`, so every read works and every write answers that it needs a wallet. A teaching preference such as "full-access" is a preference of the assistant, not a permission: only a key in the server's environment lets it sign. - **`prod` is the default.** With no `ENVIRONMENT` the server uses the real GalaChain network, and a signed write there moves real assets. Choose `stage` (the test network) while you learn; the only accepted values are `prod` and `stage`. - **Quote before you write.** Every write has a read counterpart that returns what it would do. The assistant should call it first and show you the result, and you should read it: ```mcp gala_launchpad_get_swap_quote_exact_input({ fromToken: 'GALA|Unit|none|none', toToken: 'GUSDC|Unit|none|none', amount: '100' }) gala_launchpad_calculate_buy_amount({ tokenName: 'anime', amount: '100', type: 'native' }) ``` - **Keys stay out of the conversation.** Never paste a private key into a chat, a command or a file the assistant can read; configure it in the server's environment. See [security and keys](/gala-mcp-server/next/ai-tools/security.md). - **The preferences file holds no secrets.** `/omni-tool:setup` writes presentation preferences to `.claude/galachain-omnitool.local.md` and nothing that reaches the server. ## Updating Update the plugin from its marketplace (`/plugin marketplace update gala-chain`, then `claude plugin update omni-tool@gala-chain`). The server it starts is fetched by `npx` on its own schedule, so the tools you have can be newer than the plugin's own documentation of them: trust the live tool list and `gala_launchpad_explain_sdk_usage` over any static description, including this page. --- # Security and keys for agents An AI assistant with a signing key can move real assets on your behalf, on the strength of text it read somewhere: a web page, a token description, a chat message. Treat the key as the only thing standing between that text and your wallet, and give the assistant as little as the task needs. ## Rules 1. **Start without a key.** Every read tool works without `PRIVATE_KEY`: pools, prices, balances, quotes, documentation. A server without a key cannot sign, whatever the assistant is told. 2. **Never paste a private key into a chat, a prompt, a command line or a file the assistant can read.** Anything in the conversation is sent to the model provider and kept in transcripts. A key belongs in the server process's environment (see below), nowhere else. 3. **Use a dedicated wallet.** Fund it with what the task needs and no more, and use a key made for testing while you try workflows on `stage`. 4. **Learn on `stage`, the test network.** `ENVIRONMENT` is `prod` (the default) or `stage`, nothing else. Production writes are real. A server started without `ENVIRONMENT` is on `prod`. 5. **Quote, read the quote, then write.** Ask the assistant to run the quote or calculate tool of an action first and to show you the result before it signs anything. Review each write; do not grant blanket approval to a tool in your client's permission settings for a server that can sign. 6. **Select only the toolsets the task needs.** A server with `GALA_TOOLSETS=core,gswap` has no way to create a Launchpad token. Be clear about what this does not do: toolsets narrow the tools, they do not make a toolset read-only. `core` still contains the GALA transfer, so only leaving out `PRIVATE_KEY` makes the server read-only. ## Where a key may live | Place | Acceptable? | | --- | --- | | The server's `env` block in a configuration file only you can read, for a test wallet | Yes, with care: the file holds a secret in clear text. Do not commit it or sync it. | | An environment variable of your shell, referenced from the client configuration (`${NAME}` in a project `.mcp.json`) | Yes: nothing secret is in the file you commit. | | A secret manager that launches the client with the variable set | Yes. | | A chat message, a prompt, a README, an example or a shared file | No. | | A tool argument (see `set_wallet` below) | Avoid. | ## `set_wallet` puts the key in the conversation The tool `gala_launchpad_set_wallet` takes the private key as an argument, so calling it means the key passes through the model and into the transcript. It exists for the case where a person at the keyboard configures a session on a machine they control. When you can, set `PRIVATE_KEY` in the server's environment instead and never call it: ```mcp gala_launchpad_has_wallet({}) gala_launchpad_get_wallet({}) ``` Those two report whether a wallet is configured and which address it is, without a key in either call. ## Addresses A GalaChain user is written `eth|<40 hex digits>` (the checksummed spelling), or `client|`. The server also accepts a checksummed `0x<40 hex>` and converts it. `eth|0x` is refused: it is not an address form, and the refusal names the correct spelling. When an assistant composes an address, the server validates it before anything is signed, and a refused address is a prompt to look the address up, not to try another spelling. Amounts are whole tokens as decimal strings, so `'1.5'` is one and a half tokens. ## What the code enforces These statements are held by tests of this package, not by this page: - The environment is `prod` (the default) or `stage`; anything else is refused. Enforced by `packages/gala-mcp-server/src/session/__tests__/session.test.ts` ("ENVIRONMENT is prod (default) or stage; anything else is refused"). - A malformed key is refused and changes nothing. Enforced by `packages/gala-mcp-server/src/session/__tests__/session.test.ts` ("refuses a malformed key and changes nothing"). - The server refuses `eth|0x`: its address checks take exactly the forms the Launchpad SDK takes. Enforced by `packages/gala-mcp-server/src/__tests__/address-forms-sync.test.ts` ("the server address checks take exactly the forms launchpad-sdk takes"). - A toolset that is not selected is never loaded. Enforced by `packages/gala-mcp-server/src/toolsets/__tests__/module-graph.test.ts` ("module graph per selection"). - Switching the environment changes nothing if any client cannot be built. Enforced by `packages/gala-mcp-server/src/session/__tests__/session.test.ts` ("one participant that cannot be built refuses the switch: the others are aborted, nothing changes"). ## If a key was exposed Treat it as lost: move the funds to a new wallet and stop using the old key. Removing it from a file or a transcript does not undo that it was sent. --- # Agent guide: gala-mcp-server This page is for an AI agent that drives `@gala-chain/gala-mcp-server`, or that helps a person set it up. The server exposes the Gala SDKs as MCP tools and prompts; the tool calls below are shown as `mcp` blocks, and a test holds every call to a real tool with parameters its schema declares. ## Which package for which job | Job | Package | | --- | --- | | Drive wallets, GALA transfers, bridging, Launchpad trading and GSwap swaps from an MCP client | `@gala-chain/gala-mcp-server` (this package): `npm install -g @gala-chain/gala-mcp-server@next` | | Write application code against GalaChain | `@gala-chain/gala-core-sdk` and the product SDKs below; read their agent guides | | Launchpad pools, buys, sells, token creation in code | `@gala-chain/launchpad-sdk` | | GSwap quotes, swaps, liquidity in code | `@gala-chain/gswap-sdk` | Each package publishes an agent guide at `//agents.md` on the docs site (listed in `/llms.txt`), and `gala_launchpad_search_gala_docs` searches them all. ## Find the right tool Tools are grouped in toolsets (`core`, `launchpad`, `gswap`; `composite` is enabled when both launchpad and gswap are). `GALA_TOOLSETS` or `--toolsets` selects them, so a call to a tool of a toolset that is not selected does not exist. The per-toolset reference pages list every tool with its parameters, and the same data is machine-readable at `/mcp/tools.json` (index) and `/mcp//tools.json`. ```mcp // Which docs answer a question, offline too (a bundled index backs the site's): gala_launchpad_search_gala_docs({ query: 'transfer GALA to an eth address', package: 'gala-core-sdk' }) // A code example and the packages it uses, with the docs version next to the SDK version this server runs: gala_launchpad_explain_sdk_usage({ topic: 'buy-tokens' }) // Describe an HTTP endpoint by operation id, exact path + method, or a short query: gala_launchpad_describe_endpoint({ service: 'dex-backend', operationId: 'getPools' }) ``` ## Recipes ### Check the session before writing ```mcp // Is a wallet configured, and which environment is the session on? gala_launchpad_get_wallet({}) gala_launchpad_get_environment({}) ``` A server started without `PRIVATE_KEY` is read-only: the read tools work and a write tool answers an error. Never put a private key in a tool argument when the server already has one configured. ### Transfer GALA ```mcp gala_launchpad_transfer_gala({ recipientAddress: 'eth|1234567890123456789012345678901234567890', amount: '1.5' }) ``` `amount` is whole GALA as a decimal string. `recipientAddress` is `eth|<40 hex digits>` or a bare `0x<40 hex>` (converted); `eth|0x` is refused. ### Buy a Launchpad token Quote first, then buy with the quote's amount and the slippage bound. ```mcp gala_launchpad_calculate_buy_amount({ tokenName: 'anime', amount: '100', type: 'native' }) gala_launchpad_buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: '1000', slippageToleranceFactor: 0.01 }) ``` `expectedAmount` is the `amount` the quote answered, not a number to invent. ### Quote and swap on the DEX ```mcp gala_launchpad_get_swap_quote_exact_input({ fromToken: 'GALA|Unit|none|none', toToken: 'GUSDC|Unit|none|none', amount: '100' }) ``` ### Create a Launchpad token ```mcp gala_launchpad_check_token_name({ tokenName: 'anime' }) gala_launchpad_launch_token({ tokenName: 'anime', tokenSymbol: 'ANIME', tokenDescription: 'Example token', tokenImage: 'https://example.test/anime.png' }) ``` ## Invariants - Every `mcp` tool call shown on this package's docs pages names a tool of the manifest, with parameters its schema declares, and the full server registers exactly the manifest's tools and prompts. Enforced by `packages/gala-mcp-server/src/__tests__/docs-tool-calls.test.ts` ("names only tools of the manifest, with parameters their schema declares") and `packages/gala-mcp-server/src/toolsets/__tests__/groups.test.ts` ("the full server registers every tool and prompt of the manifests"). - A toolset that is not selected is never loaded, so its SDK is not either, and a selection offers only the prompts and SDK-usage topics whose every tool is registered. Enforced by `packages/gala-mcp-server/src/toolsets/__tests__/module-graph.test.ts` ("module graph per selection") and `packages/gala-mcp-server/src/toolsets/__tests__/groups.test.ts` ("loadToolsets, every selection"). - The server's own address checks take exactly the forms launchpad-sdk takes (`eth|`, a checksummed `0x<40 hex>`, a `client|` alias), and `eth|0x` is REFUSED with core's message naming the correct spelling. Enforced by `packages/gala-mcp-server/src/__tests__/address-forms-sync.test.ts` ("the server address checks take exactly the forms launchpad-sdk takes"). - The GALA transfer tool accepts the spellings launchpad-sdk takes and hands them to core as written, and refuses `eth|0x`. Enforced by `packages/gala-mcp-server/src/toolsets/core/gala/__tests__/parity.test.ts` ("1.0.0-rc.5/rc.6: the address spellings launchpad-sdk takes are accepted and handed to core as written; eth|0x... is refused"). - A token name is 1 to 25 letters and digits, like the SDK's. Enforced by `packages/gala-mcp-server/src/__tests__/common-schemas-sync.test.ts` ("TOKEN_NAME_SCHEMA caps a token name at 25 characters, like the SDK (20 before the backend raised it)"). - The environment is `prod` (the default) or `stage`; anything else is refused. Enforced by `packages/gala-mcp-server/src/session/__tests__/session.test.ts` ("ENVIRONMENT is prod (default) or stage; anything else is refused"). - Switching the environment prepares every toolset's client first and commits them all together, so a switch that cannot be built changes nothing and tools never see half of a switch. Enforced by `packages/gala-mcp-server/src/session/__tests__/session.test.ts` ("one participant that cannot be built refuses the switch: the others are aborted, nothing changes"). - The docs tools are offline-safe: a failing site is remembered rather than asked on every call, the stale cache answers when the site fails, and the bundled index answers when there is no cache. Enforced by `packages/gala-mcp-server/src/toolsets/core/tools/docs/__tests__/docs-source.test.ts` ("serves the stale cache when the site fails, and remembers the failure so it is not asked on every call") and `packages/gala-mcp-server/src/toolsets/core/tools/docs/__tests__/docs-source.test.ts` ("falls back to the bundled index with no cache, and throws a clear error when there is none"). ## Failures Tool errors answer text beginning `Error:` with a tip; the SDK's own error code is in the message. | Failure | Meaning | Fix | | --- | --- | --- | | A tool the client cannot find | The tool's toolset is not selected. | Set `GALA_TOOLSETS` (or `--toolsets`) to include it and restart the server. | | An error saying a wallet is required, on a write | The session has no wallet (read-only mode). | Configure `PRIVATE_KEY`, or call `gala_launchpad_set_wallet` once. | | An address refused for `eth\|0x...` | An address was written with a `0x` after `eth\|`. | Write `eth\|` or the bare `0x`. | | Data of the wrong network | The session environment is not the one meant (the default is `prod`). | Check `gala_launchpad_get_environment`; switch with `gala_launchpad_switch_environment`. | | No docs index available | The docs site is unreachable and this build has no bundled index. | Set `GALA_DOCS_BASE_URL` to a reachable site, or upgrade the server. | --- # Troubleshooting AI tool setups ## The server does not appear, or no Gala tools are listed | Symptom | Cause | Fix | | --- | --- | --- | | The client shows the server as failed or never started | The command could not run: Node.js older than 20, no network for `npx`, or a typo in the command. | Run the command from a terminal (`npx -y @gala-chain/gala-mcp-server@next`). A working server waits silently on stdin; press Ctrl+C. Fix what it prints. | | The server starts and exits at once with a message on stderr | A configuration mistake: an unknown toolset name, an empty `--toolsets`, `composite` in a selection, an `ENVIRONMENT` that is not `prod` or `stage`, or a malformed `PRIVATE_KEY`. | Read the message, it names the valid values. Correct the variable and restart the client. | | Install fails to resolve the version | A range such as `^1.0.0` matches no prerelease. | Use the `@next` tag or the exact version. | | The server is connected but a tool is missing | Its toolset is not selected, for example a Launchpad tool with `GALA_TOOLSETS=core,gswap`. | Add the toolset to `GALA_TOOLSETS` or `--toolsets` and restart the client. | | The server was changed but the client behaves as before | The client keeps the process it started. | Restart the client, or disable and enable the server in its MCP settings. | ## Tools answer with an error | Symptom | Cause | Fix | | --- | --- | --- | | A write says a wallet is required | The server has no `PRIVATE_KEY`: it is read-only. | Configure `PRIVATE_KEY` in the server's environment and restart (see [security and keys](/gala-mcp-server/next/ai-tools/security.md)). | | Every tool reports a configuration problem about `WALLET_ADDRESS` | The identity override is not the address of the key. | Unset `WALLET_ADDRESS`, or set it to the key's address, and restart. | | An address is refused for `eth\|0x...` | The address was written with `0x` after `eth\|`. | Write `eth\|` or the bare `0x<40 hex>`. | | Data of the wrong network | The server is on `prod`, the default, and you meant `stage`. | Check with `gala_launchpad_get_environment`; set `ENVIRONMENT=stage` and restart, or call `gala_launchpad_switch_environment`. | | Bridge or wrap tools name a missing package | A Solana package of the bridge is not installed. | Reinstall the server with its dependencies (`npx` does this itself). | | Documentation tools find nothing | The docs site is unreachable and no cached index exists. | Set `GALA_DOCS_BASE_URL` to a reachable site, or set `GALA_DOCS_OFFLINE=1` to use the index bundled with the server. | ## The plugin | Symptom | Cause | Fix | | --- | --- | --- | | Each tool appears twice | The server was added with `claude mcp add` and the plugin starts one too. | Keep one: `claude mcp remove gala`, or uninstall the plugin. | | `/omni-tool:setup` says the server is not connected | The plugin's server did not start, or Claude Code was not restarted after the install. | Restart Claude Code, then run `/mcp` to see the server's state; apply the fixes of the first table. | | The assistant says it cannot sign | The plugin starts the server without a key, on `prod`. | This is the default. Add a key only as described in [security and keys](/gala-mcp-server/next/ai-tools/security.md). | | Tool counts or topics differ from what the plugin says | The plugin documents the server from the day it was published; `npx` fetches a newer server. | Trust the live tool list and `gala_launchpad_explain_sdk_usage`. | ## Still stuck Ask the server's own documentation, which works offline: ```mcp gala_launchpad_search_gala_docs({ query: 'tool not found toolsets' }) ``` The per-package agent guides carry the failure tables of each SDK. This package's is [the agent guide](/gala-mcp-server/next/agents.md). --- # @gala-chain/gala-mcp-server **Version: 1.0.0 release candidate (dist-tag `next`).** Supersedes `@gala-chain/launchpad-mcp-server` (last release 8.1.0): same tools, same names, same environment variables; the bin is now `gala-mcp`. MCP (Model Context Protocol) server for GalaChain: wallets, bridging and wrapping (gala-core-sdk), the Gala Launchpad backend (launchpad-sdk) and the GSwap DEX (gswap-sdk), in toolsets you select. Setting this up for Claude Code, Claude Desktop or Cursor, or using the `omni-tool` Claude Code plugin: [Use Gala from AI tools](/gala-mcp-server/next/ai-tools/overview.md). ## 🚀 Features - **324 tools and 286 prompts (slash commands)** in four toolsets you select: load only the part of the Gala stack you use, so the model's context does not carry tools it will never call - **Type-safe** - TypeScript, with every input validated against the schema the tool publishes - **Built on the Gala SDKs** - [@gala-chain/gala-core-sdk](https://www.npmjs.com/package/@gala-chain/gala-core-sdk), [@gala-chain/launchpad-sdk](https://www.npmjs.com/package/@gala-chain/launchpad-sdk) and [@gala-chain/gswap-sdk](https://www.npmjs.com/package/@gala-chain/gswap-sdk) - **Read-only and full-access modes** - without `PRIVATE_KEY` every read works and writes say they need a wallet - **Real-time monitoring** - WebSocket-based watchers for pool and token creation events - **Works with Claude Desktop, Claude Code and any MCP client** over stdio ## 🧰 Toolsets The server is one package with tools grouped by the SDK they use. `GALA_TOOLSETS` (or `--toolsets`) picks the groups; the default is all of them. A toolset you do not select is never loaded: its tools are not listed, and its SDK is not even imported (a launchpad-only run never loads `gswap-sdk`). | Toolset | Tools | Prompts | SDKs | What is in it | | --- | --- | --- | --- | --- | | `core` | 47 | 30 | gala-core-sdk | Wallet and key tools (create wallet, addresses, key derivation), the session wallet and environment (`set_wallet`, `switch_environment`), versions, the GALA balance and GALA transfers (`fetch_gala_balance`, `transfer_gala`), cross-chain bridging (GalaChain, Ethereum, Solana), wrap/unwrap, external chain balances, `explain_sdk_usage` | | `launchpad` | 242 | 213 | gala-core-sdk + launchpad-sdk | The launchpad backend: pools and bonding-curve trading, token creation, launchpad token balances and transfers, locks and burns, NFTs, holders, streaming, chat, auth, moderation, overseers, API keys, content flags, WebSocket events | | `gswap` | 32 | 34 | gala-core-sdk + gswap-sdk | The GSwap DEX: swap quotes and swaps, pools, liquidity positions and fees, market prices, leaderboard and seasons, pool-creation watcher | | `composite` | 3 | 9 | launchpad-sdk + gswap-sdk | Launchpad token prices and price history from the DEX market. Not selectable: enabled exactly when `launchpad` and `gswap` both are | Tool names do not change with the toolset (they all keep the `gala_launchpad_` prefix, DEX tools included), so prompts, docs and plugins refer to the same names whichever toolsets run. The full per-tool classification, with the reason each tool is in its group, is in [docs/TOOLSET-CLASSIFICATION.md](/gala-mcp-server/next/toolset-classification.md). ### Selecting toolsets ```bash GALA_TOOLSETS=core,gswap gala-mcp # environment variable gala-mcp --toolsets launchpad # command line (wins over the variable) ``` | Selection | Tools | Prompts | | --- | --- | --- | | `core,launchpad,gswap` (default) | 324 | 286 | | `launchpad` | 242 | 209 | | `gswap` | 32 | 34 | | `core` | 47 | 30 | | `core,launchpad` | 289 | 243 | | `core,gswap` | 79 | 64 | | `launchpad,gswap` (+ composite) | 277 | 250 | - Names are comma separated and case-insensitive; order does not matter. An unknown name, an empty entry (`core,,gswap`), an empty `--toolsets` or `composite` is a startup error that names the valid toolsets: a typo never silently turns tools off. - A prompt is listed only when every tool its text names is in the selection, and `explain_sdk_usage` only offers the topics whose tools are in the selection. That is why `launchpad` alone lists 209 of its 213 prompts: the others also name a `core` tool (for example the bridge tools, or the GALA balance). `explain_sdk_usage` is a `core` tool; add `core` to get it. - The GALA balance and GALA transfers (`gala_launchpad_fetch_gala_balance`, `gala_launchpad_transfer_gala`) are `core` tools (since 1.0.0-rc.1; they were `launchpad`'s in 1.0.0-rc.0): a launchpad user who needs them selects `core,launchpad`. - The wallet, environment and settings (`PRIVATE_KEY`, `ENVIRONMENT`, ...) are shared by every toolset and read the same way whichever toolsets run. `set_wallet` and `switch_environment` live in `core`: without `core` the wallet is the one from the environment for the whole run. - At startup the server logs the enabled toolsets and the tool and prompt counts to stderr. ### Which install line ```bash # everything (default) claude mcp add "gala" -- env PRIVATE_KEY=0x... ENVIRONMENT=prod npx -y @gala-chain/gala-mcp-server@next # launchpad only (plus the core tools: wallet, GALA balance and transfer, bridge) claude mcp add "gala-launchpad" -- env GALA_TOOLSETS=core,launchpad PRIVATE_KEY=0x... ENVIRONMENT=prod npx -y @gala-chain/gala-mcp-server@next # DEX only (plus the core tools: wallet, GALA balance and transfer, bridge) claude mcp add "gala-swap" -- env GALA_TOOLSETS=core,gswap PRIVATE_KEY=0x... ENVIRONMENT=prod npx -y @gala-chain/gala-mcp-server@next ``` `@next` (or the exact version, 1.0.0-rc.9, as `@gala-chain/gala-mcp-server@`) is required while 1.0.0 is a release candidate: `^1.0.0` matches no prerelease, and the `latest` dist-tag can still name an older release candidate. ## 📦 Installation ```bash npm install -g @gala-chain/gala-mcp-server@next ``` 1.0.0 is published as a release candidate under the `next` dist-tag: install `@next` or the exact version (the exact version, 1.0.0-rc.9, as `@gala-chain/gala-mcp-server@`); a range such as `^1.0.0` matches no release candidate. ### Module Format The server is an ES module (`dist/index.js`, `"type": "module"`, bin `gala-mcp`) for Node.js 20 or newer. The three Gala SDKs are regular dependencies, installed once each; `@solana/web3.js` and `@solana/spl-token` are dependencies too, because the bridge and wrap tools (core's `./bridge`) need them. Without them the server still starts and lists every tool; only the bridge and wrap tools answer with an error that names the missing package. ## 🏁 Quick Start ### Claude Desktop Configuration Add to your `claude_desktop_config.json`: ```json { "mcpServers": { "gala": { "command": "npx", "args": ["-y", "@gala-chain/gala-mcp-server@next"], "env": { "PRIVATE_KEY": "0x1234567890abcdef...", "ENVIRONMENT": "prod" } } } } ``` **Environment Variables:** - `GALA_TOOLSETS` (optional) - comma list of `core`, `launchpad`, `gswap` (default: all; see [Toolsets](#-toolsets)) - `PRIVATE_KEY` (optional) - Your Ethereum wallet private key (omit for read-only mode) - `ENVIRONMENT` (optional) - `prod` or `stage` (default: `prod`) - `TIMEOUT` (optional) - Request timeout in milliseconds (default: 30000) - `ETHEREUM_RPC_URL` (optional) - Custom Ethereum RPC URL (default: the SDK's built-in endpoints) - `SOLANA_RPC_URL` (optional) - Custom Solana RPC URL for bridge operations (default: public Solana endpoints) - `SOLANA_PRIVATE_KEY` (optional) - Solana key for bridge operations - `STREAM_WEBSOCKET_URL` (optional) - Custom stream WebSocket endpoint - `STREAM_ADMIN_API_KEY` (optional) - Stream administration access - `USER_API_KEY` (optional) - User API authentication - `DEBUG` (optional) - `true` to enable debug logging - `GALA_DOCS_BASE_URL` (optional) - the docs site the documentation tools read (default: `https://docs.gala.com`) - `GALA_DOCS_CACHE_DIR` (optional) - where the fetched docs index is kept (default: the user cache directory) - `GALA_DOCS_CACHE_TTL_SECONDS` (optional) - how long the cached docs index is fresh (default: 3600) - `GALA_DOCS_OFFLINE` (optional) - `1` never asks the docs site; the bundled index answers The documentation tools (`gala_launchpad_search_gala_docs`, and the `docs` field of `gala_launchpad_explain_sdk_usage`) search the docs site's index and work without it: a bundled copy (at most 300 KB compressed) answers when the site cannot be reached. The site lists every package's agent guide in `/llms.txt`; the machine-readable tool reference is at `/mcp/tools.json`. ### Using with Claude Desktop 1. **Install**: `npm install -g @gala-chain/gala-mcp-server@next` 2. **Configure**: Add server to `claude_desktop_config.json` (see above) 3. **Restart Claude Desktop** 4. **Use tools**: Ask Claude to interact with Gala Launchpad! ## 🔐 Operational Modes The MCP server supports two operational modes with dynamic wallet configuration: ### Full-Access Mode (with PRIVATE_KEY) - Execute token trades (buy/sell) - Create new tokens - Transfer GALA and tokens - Update profile information - All read operations (fetch pools, prices, balances, etc.) **Setup:** ```bash claude mcp add "gala" -- env PRIVATE_KEY=0x... ENVIRONMENT=prod npx -y @gala-chain/gala-mcp-server@next ``` ### Read-Only Mode (without PRIVATE_KEY) - Fetch token pools and details - Get real-time prices and price history - Check balances and portfolio - Explore token metadata and distributions - **Cannot:** Execute trades, create tokens, transfer funds (operations requiring wallet signatures) **Setup:** ```bash claude mcp add "gala-readonly" -- env ENVIRONMENT=prod npx -y @gala-chain/gala-mcp-server@next ``` ### Dynamic Wallet Configuration Use the wallet management tools to upgrade or switch wallets at runtime: - `gala_launchpad_has_wallet` - Check current wallet status - `gala_launchpad_set_wallet` - Upgrade from read-only to full-access mode - `gala_launchpad_get_wallet` - Retrieve wallet information ## 🛠️ Available Tools ### Pool Management, Pricing & Event Watchers - `gala_launchpad_fetch_pools` - Fetch token pools with filtering - `gala_launchpad_fetch_all_pools` - Fetch all available pools with automatic pagination - `gala_launchpad_fetch_pool_details` - Get detailed pool state - `gala_launchpad_fetch_pool_details_for_calculation` - Get optimized pool details for local calculations - `gala_launchpad_fetch_composite_pool_data` - **NEW v2.0** - Fetch a raw GSwap pool snapshot - `gala_launchpad_fetch_token_distribution` - Get holder distribution - `gala_launchpad_fetch_volume_data` - Get OHLCV charting data - `gala_launchpad_fetch_token_spot_price` - Fetch USD spot price for DEX tokens - `gala_launchpad_fetch_gala_spot_price` - Fetch current GALA USD spot price - `gala_launchpad_fetch_launchpad_token_spot_price` - Fetch USD spot price for launchpad token - `gala_launchpad_fetch_price_history` - Fetch historical price snapshots from DEX Backend API - `gala_launchpad_fetch_all_price_history` - Fetch all historical price snapshots with auto-pagination - `gala_launchpad_fetch_token_details` - Fetch comprehensive token metadata - `gala_launchpad_check_token_name` - Check name availability - `gala_launchpad_check_token_symbol` - Check symbol availability - `gala_launchpad_resolve_vault_address` - Get GalaChain vault address - `gala_launchpad_resolve_token_class_key` - Get GalaChain TokenClassKey - `gala_launchpad_on_dex_pool_creation` - Watch for new DEX pool creation events - `gala_launchpad_on_launchpad_token_creation` - Watch for new launchpad token creation events #### 🔔 Event Watchers - Real-Time Monitoring **Real-time pool and token discovery with WebSocket-based watchers:** **`gala_launchpad_on_dex_pool_creation` - Watch for DEX Pool Creation** Monitor new liquidity pool creation on GalaSwap DEX with optional filtering: - **Parameters:** - `minTVL` (optional, decimal string) - Only report pools with TVL above this threshold (e.g., "100000" for 100k GALA) - `tokens` (optional, array of strings) - Only report pools containing these token symbols (e.g., ["GALA", "GUSDC"]) - `intervalMs` (optional, number) - Polling interval in milliseconds (default: 2000, minimum: 1000) - `durationSeconds` (optional, number) - How long to poll (default: 300 seconds = 5 minutes) - **Returns:** - `poolsDetected` (number) - Count of new pools found matching criteria - `durationSeconds` (number) - How long the watcher ran (in seconds) - `pools` (array of DexPoolData) - Array of detected pool objects with: - `poolPair` - Pool identifier (e.g., "GALA|Unit|none|none/GUSDC|Unit|none|none/10000") - `token0` / `token1` - Token symbols (e.g., "GALA", "GUSDC") - `tvl` - Total value locked in pool (number) - `fee` - Fee percentage as string (e.g., "0.3", "1") - `volume1d` / `volume30d` - Trading volume metrics - `apr1d` - 1-day APR percentage - **Use Cases:** - Monitor high-value pool creation for opportunities - Track specific token pair pools - Real-time liquidity discovery - Automated opportunity alerts - **Example:** ```javascript // Watch for new high-TVL pools with GALA const result = await gala_launchpad_on_dex_pool_creation({ minTVL: "500000", // Only pools with 500k+ GALA TVL tokens: ["GALA"], // Only GALA pairs intervalMs: 3000, // Check every 3 seconds durationSeconds: 600 // Poll for 10 minutes }); console.log(`Found ${result.poolsDetected} new GALA pools`); result.pools.forEach(pool => { console.log(`${pool.tokenA} / ${pool.tokenB}: $${pool.tvl} TVL`); }); ``` **`gala_launchpad_on_launchpad_token_creation` - Watch for Launchpad Token Creation** Monitor new token launches on Gala Launchpad with optional creator filtering: - **Parameters:** - `creatorAddress` (optional, string) - Only report tokens created by this address (e.g., "eth|...") - `intervalMs` (optional, number) - Polling interval in milliseconds (default: 2000, minimum: 1000) - `durationSeconds` (optional, number) - How long to poll (default: 300 seconds = 5 minutes) - **Returns:** - `tokensDetected` (number) - Count of new tokens found - `durationSeconds` (number) - How long the watcher ran (in seconds) - `tokens` (array of PoolData) - Array of detected token objects with: - `tokenName` - Token name/symbol (e.g., "anime", "dragon") - `tokenSymbol` - Token symbol if different from name - `creatorAddress` - Creator's wallet address (eth| format) - `totalRaised` - GALA amount raised in bonding curve - `remainingSupply` - Tokens still available to purchase - `saleStatus` - "Ongoing" or "Completed" (graduated to DEX) - **Use Cases:** - Track specific creators' new token launches - Monitor all token creation activity - Early opportunity discovery - Creator relationship tracking - **Example:** ```javascript // Watch for tokens from a specific creator const result = await gala_launchpad_on_launchpad_token_creation({ creatorAddress: "eth|1234567890abcdef1234567890abcdef12345678", intervalMs: 2000, // Check every 2 seconds durationSeconds: 300 // Poll for 5 minutes }); console.log(`Found ${result.tokensDetected} new tokens from creator`); result.tokens.forEach(token => { console.log(`${token.tokenName}: ${token.totalRaised} GALA raised`); }); ``` #### Key Characteristics - **Polling-based Architecture** - Uses client-side polling (no WebSocket), configurable intervals - **Automatic Deduplication** - Never reports the same pool/token twice within a single watch session - **Client-side Filtering** - Optional minTVL and tokens parameters reduce API load - **Long-running Support** - Safely polls for extended periods without memory leaks - **Error Resilience** - Continues polling after transient errors (network timeouts, API errors) - **Interval Validation** - Enforces minimum 1000ms interval to prevent API spam - **Return Values** - Both detect count and full objects for flexible usage ### Trading Operations - `gala_launchpad_calculate_buy_amount` - Calculate buy amounts (network call) - `gala_launchpad_calculate_sell_amount` - Calculate sell amounts (network call) - `gala_launchpad_calculate_buy_amount_local` - Calculate buy amounts (local, instant) - `gala_launchpad_calculate_buy_amount_external` - Calculate buy amounts (explicit network call) - `gala_launchpad_calculate_sell_amount_local` - Calculate sell amounts (local, instant) - `gala_launchpad_calculate_sell_amount_external` - Calculate sell amounts (explicit network call) - `gala_launchpad_buy` - Execute token purchase - `gala_launchpad_sell` - Execute token sale - `gala_launchpad_fetch_trades` - Get trade history - `gala_launchpad_calculate_initial_buy` - Calculate initial buy - `gala_launchpad_get_bundler_transaction_result` - Get transaction status by ID - `gala_launchpad_calculate_buy_amount_for_graduation` - Calculate cost to graduate pool - `gala_launchpad_graduate_token` - One-step pool graduation #### 🎓 Understanding Graduation Calculations **CRITICAL:** The `amount` field in `gala_launchpad_calculate_buy_amount_for_graduation` represents **GALA cost**, NOT token quantity! ```javascript // Example response { "amount": "1594263.41948877", "transactionFee": "1594.26341949", "gasFee": "1" } // ❌ WRONG INTERPRETATION: // "Need to buy 1,594,263 tokens" // ✅ CORRECT INTERPRETATION: // "Need to spend 1,594,263.42 GALA to buy all remaining tokens and graduate the pool" ``` **Amount Field Reference:** | Tool | `amount` Field Represents | Example | Meaning | |------|---------------------------|---------|---------| | `calculate_buy_amount` | **Token quantity** received | "16843.758" | 16,843.76 tokens | | `calculate_sell_amount` | **GALA amount** received | "125.50" | 125.50 GALA | | `calculate_buy_amount_for_graduation` | **GALA cost** to graduate | "1594263.419" | 1,594,263.42 GALA | | `calculate_initial_buy` | **Token quantity** from pre-buy | "3663321.363" | 3,663,321.36 tokens | **Key Points:** - Read the full number as-is - decimal point is NOT shifted - Graduation amounts are typically in the hundreds of thousands to millions of GALA - Always use `graduate_token` for convenience - it handles calculations internally - Pool status changes from "Ongoing" to "Completed" upon successful graduation #### ⚡ Performance Optimization for AI Agents The following tools now support optional performance parameters to reduce network calls by **66%** and speed up operations by **~70%**: - `gala_launchpad_fetch_launchpad_token_spot_price` - `gala_launchpad_calculate_buy_amount_for_graduation` - `gala_launchpad_graduate_token` **New Optional Parameters:** - `calculateAmountMode` (enum: `'local'` | `'external'`) - Calculation strategy - `currentSupply` (string) - Pre-fetched current token supply **Optimization Pattern:** ```javascript // ❌ WITHOUT OPTIMIZATION (3 network calls) const spotPrice1 = await gala_launchpad_fetch_launchpad_token_spot_price({ tokenName: "tinyevil" }); // → Network call #1 const graduation1 = await gala_launchpad_calculate_buy_amount_for_graduation({ tokenName: "tinyevil" }); // → Network call #2 const result1 = await gala_launchpad_graduate_token({ tokenName: "tinyevil" }); // → Network call #3 // ✅ WITH OPTIMIZATION (1 network call + instant local calculations) // Step 1: Fetch pool details once const poolDetails = await gala_launchpad_fetch_pool_details_for_calculation({ tokenName: "tinyevil" }); const currentSupply = poolDetails.currentSupply; // Step 2: Reuse currentSupply for instant local calculations const spotPrice2 = await gala_launchpad_fetch_launchpad_token_spot_price({ tokenName: "tinyevil", calculateAmountMode: "local", currentSupply: currentSupply }); // → Instant (no network call) const graduation2 = await gala_launchpad_calculate_buy_amount_for_graduation({ tokenName: "tinyevil", calculateAmountMode: "local", currentSupply: currentSupply }); // → Instant (no network call) const result2 = await gala_launchpad_graduate_token({ tokenName: "tinyevil", calculateAmountMode: "local", currentSupply: currentSupply, slippageToleranceFactor: 0.01 }); // → Uses local calculation (no redundant pool fetch) ``` **Performance Impact:** | Pattern | Network Calls | Speed | Best For | |---------|--------------|-------|----------| | Without optimization | 3 calls | ~600-900ms | One-off operations | | With optimization | 1 call | ~200ms | Batch operations, analytics | | **Reduction** | **66% fewer** | **~70% faster** | | **When to Use Optimization:** - ✅ Multiple calculations on the same token - ✅ Price discovery and analytics - ✅ Trading bot logic with frequent calculations - ✅ Simulations and backtests - ❌ Single one-off calculations (not worth the complexity) **Accuracy:** Local calculations match external (network) with <0.01% difference. ### DEX Pool Discovery **Discover and explore GalaSwap DEX liquidity pools with filtering, sorting, and pagination:** - `gala_launchpad_fetch_dex_pools` - Discover DEX liquidity pools with pagination, sorting, and search filtering - `gala_launchpad_fetch_all_dex_pools` - Discover ALL DEX liquidity pools with automatic pagination **Features:** - 🔍 **Search filtering** - Find pools by token symbol (GALA, GUSDC, etc.) - 📊 **Sorting options** - Sort by TVL, 24h volume, or 30d volume - 📄 **Pagination** - Browse large pool datasets efficiently (max 20 per page) - 🚀 **Auto-pagination** - Fetch all pools automatically with `fetchAllDexPools` - 💰 **Complete pool data** - TVL, fees, APR, volume metrics, and token pricing ### GSwap DEX Trading **Real-time DEX trading for graduated tokens with slippage protection:** The DEX tools run `@gala-chain/gswap-sdk`'s `GSwap` client (launchpad-sdk has no DEX client), built from the same environment, swap backend and `PRIVATE_KEY` as the launchpad SDK and rebuilt when the wallet or the environment changes. Without `PRIVATE_KEY` it is read-only. - `gala_launchpad_get_swap_quote_exact_input` - Get swap quote for exact input amount - `gala_launchpad_get_swap_quote_exact_output` - Get swap quote for exact desired output - `gala_launchpad_execute_swap` - Execute token swap on GalaSwap DEX with slippage protection (queued on chain; waits for the applied result) - `gala_launchpad_get_swap_result` - Resolve a queued swap by its `uniqueKey` when the outcome was unknown, without resubmitting - `gala_launchpad_get_swap_user_assets` - Get user token balances across all DEX pools - `gala_launchpad_get_all_swap_user_assets` - **NEW v2.0** - Get all user assets with auto-pagination - `gala_launchpad_get_swap_pool_info` - Get liquidity and fee tier information for token pairs - `gala_launchpad_get_swap_pool_price` - **NEW v2.0** - Get current price for token pair in DEX pool - `gala_launchpad_fetch_composite_pool_data` - **NEW v2.0** - Fetch a raw pool snapshot (liquidity, ticks, price, positions) for pool inspection - `gala_launchpad_calculate_dex_pool_quote_local` - **NEW v2.0** - DEX quote via the live GSwap quoting service (legacy naming; not offline) - `gala_launchpad_calculate_dex_pool_quote_external` - **NEW v2.0** - DEX quote via the live GSwap quoting service (real-time) - **Liquidity position tools** - Add, remove, collect fees, query positions - **Leaderboard tools** - Top traders, tokens, volume rankings - **Volume tool** - DEX trading volume metrics **Complete DEX Trading Workflow Example:** ```javascript // Step 1: Get a quote (how much output for 100 GALA input?) const quote = await gala_launchpad_get_swap_quote_exact_input({ fromToken: 'GALA', toToken: 'GUSDC', amount: '100' }); // Returns: { estimatedOutput: "100.50", feeTier: 3000, priceImpact: "0.23", ... } // Step 2: Check pool liquidity before large trades const pool = await gala_launchpad_get_swap_pool_info({ tokenA: 'GALA', tokenB: 'GUSDC' }); // Returns: { liquidity: "5000000", feeTiers: [500, 3000, 10000], swapCount: 1234 } // Step 3: Execute the swap with slippage protection const result = await gala_launchpad_execute_swap({ fromToken: 'GALA', toToken: 'GUSDC', inputAmount: '100', estimatedOutput: quote.estimatedOutput, // Use quoted amount! feeTier: quote.feeTier, // Use quoted fee tier! slippageTolerance: 0.01 // 1% slippage tolerance }); // Waits for the queued RequestTrade to apply, then returns: // { submission: { method: "RequestTrade", uniqueKey, transactionId, mode: "queued" }, // confirmation: { transactionId, blockNumber, requestTransactionId, // result: { token0, token1, fee, sell0Qty, buy1Qty, totalFees, ... } }, ... } // A chain rejection (e.g. VALIDATION_FAILED slippage) is returned as a tool error. // Step 4: Check user portfolio after swap const assets = await gala_launchpad_get_swap_user_assets({ walletAddress: 'eth|...' }); // Returns: [{ symbol: 'GALA', balance: '900', decimals: 8 }, { symbol: 'GUSDC', balance: '100.45', decimals: 6 }] ``` **Key Characteristics:** - ✅ **Real-time** - Integrated with unified WebSocket for instant transaction monitoring - ✅ **Slippage Protection** - Automatic minimum output calculation - ✅ **Multi-format tokens** - Supports simple names ('GALA') or full token IDs ('GALA|Unit|none|none') - ✅ **Fee Tiers** - Automatic detection of available liquidity pools (0.05%, 0.3%, 1.0%) - ✅ **Environment-aligned** - Uses same URLs as LaunchpadSDK (STAGE/PROD cannot be mixed) - ✅ **Live Quote Calculation** - **NEW v2.0** - Fresh DEX quotes from the GSwap quoting service on every call #### 📊 Historical Price Analysis **`gala_launchpad_fetch_price_history`** - Fetch historical price snapshots for DEX tokens This tool queries the DEX Backend API for historical token price data, enabling trend analysis and volatility assessment. **Requirements:** - DEX Backend API must be configured and accessible (automatic with environment configuration) - Node.js environment only (not available in browser) - Only works for DEX tokens with recorded price snapshots **Parameters:** - `tokenId` (required) - Token identifier (string format: "collection|category|type|additionalKey" or object with collection, category, type, additionalKey) - `from` (optional) - Start date (ISO 8601, defaults to 30 days ago) - `to` (optional) - End date (ISO 8601, defaults to now) - `sortOrder` (optional) - Sort order: 'ASC' or 'DESC' (default: DESC for newest-first) - `page` (optional) - Page number for pagination (default: 1) - `limit` (optional) - Results per page, max 50 (default: 10) **Use Cases:** - Historical price analysis and charting - Price trend identification - Volatility analysis over time periods - Data export for external analytics **Example:** Ask Claude: > "Fetch the last 30 days of hourly price data for GUSDC token" > "Show me GALA token price history from the last 7 days with daily snapshots" --- #### 📊 All Historical Price Data (Auto-Paginated) **`gala_launchpad_fetch_all_price_history`** - Fetch all historical price snapshots (auto-paginated) Automatically fetches all pages of historical price data and returns complete dataset in single result. **Use Cases:** - Complete volatility analysis - Full historical trend analysis - Statistical calculations on entire dataset - Data export for backtesting **Example:** Ask Claude: > "Get all price history for GUSDC token from January 2024 and calculate volatility" ### Balance & Portfolio - `gala_launchpad_fetch_gala_balance` - Get GALA balance (`core` toolset) - `gala_launchpad_fetch_token_balance` - Get token balance - `gala_launchpad_fetch_tokens_held` - Get portfolio holdings - `gala_launchpad_fetch_tokens_created` - Get created tokens - `gala_launchpad_fetch_profile` - Get user profile - `gala_launchpad_update_profile` - Update profile - `gala_launchpad_get_swap_user_assets` - Get user token balances from DEX - `gala_launchpad_get_all_swap_user_assets` - **NEW v2.0** - Get all user assets with auto-pagination ### Wallet Management - `gala_launchpad_has_wallet` - Check if wallet is configured - `gala_launchpad_get_wallet` - Get currently configured wallet instance - `gala_launchpad_set_wallet` - Configure wallet for signing operations (upgrade from read-only mode) ### Token Creation - `gala_launchpad_launch_token` - Create new token pool - `gala_launchpad_upload_token_image` - Upload token image from filesystem - `gala_launchpad_upload_profile_image` - Upload profile image from filesystem - `gala_launchpad_fetch_launch_token_fee` - Get current GALA fee to launch a token ### Token Transfers - `gala_launchpad_transfer_gala` - Transfer GALA tokens (`core` toolset) - `gala_launchpad_transfer_token` - Transfer launchpad tokens ### Utility Tools - `gala_launchpad_create_wallet` - Create new GalaChain wallet - `gala_launchpad_get_address` - Get user's GalaChain address - `gala_launchpad_get_ethereum_address` - Get user's Ethereum address - `gala_launchpad_get_public_key_from_private_key` - **NEW v4.0.15** - Derive public key from private key (secp256k1) - `gala_launchpad_get_ethereum_address_from_private_key` - **NEW v4.0.15** - Derive Ethereum address from private key - `gala_launchpad_get_config` - Get current SDK configuration - `gala_launchpad_get_url_by_token_name` - Generate frontend URL for a token - `gala_launchpad_explain_sdk_usage` - Get SDK code examples for specific topics - `gala_launchpad_get_cache_info` - Get token metadata cache statistics - `gala_launchpad_clear_cache` - Clear token metadata cache - `gala_launchpad_has_wallet` - Check if wallet is configured - `gala_launchpad_get_wallet` - Get currently configured wallet instance - `gala_launchpad_set_wallet` - Configure wallet for signing operations - `gala_launchpad_get_environment` - Get current MCP server environment - `gala_launchpad_switch_environment` - Switch MCP server environment - `gala_launchpad_get_version` - Get SDK and MCP server version information - `gala_launchpad_is_token_graduated` - Check if token has completed bonding curve - `gala_launchpad_cleanup` - SDK lifecycle cleanup utility ### Overseer Tools - `gala_launchpad_create_overseer_invite` - Create an overseer invite (Admin OR Overseer) - `gala_launchpad_list_overseer_invites` - List all overseer invites with pagination - `gala_launchpad_get_overseer_invite` - Get invite details by code (public endpoint) - `gala_launchpad_claim_overseer_invite` - Claim an overseer invite (JWT) - `gala_launchpad_revoke_overseer_invite` - Revoke an overseer invite - `gala_launchpad_list_overseers` - List all overseers with pagination - `gala_launchpad_revoke_overseer` - Revoke an overseer's access - `gala_launchpad_get_my_overseer_status` - Check own overseer status (JWT) - `gala_launchpad_get_overseer_summary` - Get platform summary for CCTV dashboard (active streams, viewers, pending flags, total pools) - `gala_launchpad_flush_cache_by_address` - Flush cache for a wallet address (Admin OR Overseer) - `gala_launchpad_flush_cache_by_token` - Flush cache for a token (Admin OR Overseer) - `gala_launchpad_flush_all_cache` - Flush ALL cache (Admin OR Overseer, requires confirmation) ### Content Flag Tools - `gala_launchpad_create_flag` - Flag content (chat message, stream, etc.) - `gala_launchpad_list_flags` - List flags for a token with pagination - `gala_launchpad_dismiss_flag` - Dismiss a flag as not actionable - `gala_launchpad_action_flag` - Take action on flagged content ## 💡 Example Usage Ask Claude (or your AI assistant): > "Fetch the 10 most recent token pools on Gala Launchpad" > "What's my GALA balance?" > "Calculate how many tokens I'd get if I buy with 100 GALA on dragnrkti" > "Buy 50 GALA worth of rocketri tokens with 5% slippage" > "Show me all tokens I'm holding" > "Watch for new DEX pool creation for the next 5 minutes" > "Get the current GALA/GUSDC price from the DEX pool" > "Get the platform summary for the CCTV dashboard" > "Create an overseer invite for the new platform team member" ## ⚡ Slash Commands (Prompts) The MCP server exposes **286 slash commands** (prompts) for streamlined workflows - every major operation has a corresponding slash command for quick access. These appear as `/galachain-launchpad:<>` in Claude Desktop. ### Trading Commands **`/galachain-launchpad:analyze-token`** - Comprehensive token analysis (pool details, spot price, graduation cost) - **Arguments**: `tokenName` (required) - **Example**: `/galachain-launchpad:analyze-token tokenName=anime` - Uses optimized LOCAL calculations for speed **`/galachain-launchpad:buy-tokens`** - Guided token purchase with slippage protection - **Arguments**: `tokenName` (required), `galaAmount` (required), `slippage` (optional, default 1%) - **Example**: `/galachain-launchpad:buy-tokens tokenName=anime galaAmount=100 slippage=2` - Shows breakdown and asks for confirmation before executing **`/galachain-launchpad:sell-tokens`** - Guided token sale with slippage protection - **Arguments**: `tokenName` (required), `tokenAmount` (required), `slippage` (optional, default 1%) - **Example**: `/galachain-launchpad:sell-tokens tokenName=anime tokenAmount=1000` - Checks balance and shows breakdown before executing **`/galachain-launchpad:graduate-token`** - One-step pool graduation workflow - **Arguments**: `tokenName` (required), `slippage` (optional, default 1%) - **Example**: `/galachain-launchpad:graduate-token tokenName=anime` - Checks if already graduated, calculates cost, and executes with confirmation ### Portfolio Commands **`/galachain-launchpad:portfolio`** - Complete portfolio analysis with USD values - **Arguments**: None - Shows GALA balance, all token holdings, total portfolio value, and top holdings **`/galachain-launchpad:tokens-held`** - List all tokens currently held - **Arguments**: `search` (optional fuzzy filter), `limit` (optional, default 20) - **Example**: `/galachain-launchpad:tokens-held search=dragon limit=10` **`/galachain-launchpad:tokens-created`** - Show tokens created by the user with status - **Arguments**: `search` (optional), `limit` (optional, default 20) - Shows graduation status and progress for each token **`/galachain-launchpad:balance`** - Check GALA and optional token balance - **Arguments**: `tokenName` (optional) - **Example**: `/galachain-launchpad:balance tokenName=anime` - Displays both token amounts and USD values **`/galachain-launchpad:profile`** - Show user profile and activity summary - **Arguments**: None - Displays profile info, wallet addresses, activity metrics, and current balance ### Analysis Commands **`/galachain-launchpad:compare-tokens`** - Side-by-side comparison of two tokens - **Arguments**: `token1` (required), `token2` (required) - **Example**: `/galachain-launchpad:compare-tokens token1=anime token2=test216253` - Shows comparison table with metrics, holders, and investment analysis **`/galachain-launchpad:graduation-status`** - Check graduation readiness for multiple tokens - **Arguments**: `tokens` (required, comma-separated) - **Example**: `/galachain-launchpad:graduation-status tokens=anime,test216253,dragnrkti` - Shows progress table and identifies graduation opportunities **`/galachain-launchpad:spot-prices`** - Batch spot price lookup for multiple tokens - **Arguments**: `tokens` (required, comma-separated) - **Example**: `/galachain-launchpad:spot-prices tokens=anime,test216253` - Uses optimized LOCAL calculations for instant results **`/galachain-launchpad:pool-details`** - Comprehensive pool information with badges and distribution - **Arguments**: `tokenName` (required) - **Example**: `/galachain-launchpad:pool-details tokenName=anime` - Shows complete pool metrics, achievements, and recent activity **`/galachain-launchpad:trade-history`** - View recent trades with filtering - **Arguments**: `tokenName` (optional), `userAddress` (optional), `tradeType` (optional: BUY/SELL), `limit` (optional, default 20) - **Example**: `/galachain-launchpad:trade-history tokenName=anime tradeType=BUY limit=10` **`/galachain-launchpad:fetch-all-pools`** - Fetch all available pools with auto-pagination - **Arguments**: None - Retrieves complete list of all token pools on Launchpad ### Creation & Discovery Commands **`/galachain-launchpad:create-token`** - Guided token creation workflow - **Arguments**: `tokenName` (required), `tokenSymbol` (required), `description` (required), `websiteUrl` (optional), `twitterUrl` (optional), `telegramUrl` (optional), `imagePath` (optional), `preBuyGala` (optional) - **Example**: `/galachain-launchpad:create-token tokenName=mytoken tokenSymbol=MTK description="My awesome token" websiteUrl=https://example.com` - Validates availability, checks fees, uploads image, and guides through launch process - **Note**: At least one social URL (website, Twitter, or Telegram) is required **`/galachain-launchpad:discover-tokens`** - Discover new tokens on Gala Launchpad - **Arguments**: `type` (optional: recent/popular/near-graduation, default: recent), `limit` (optional, default: 10), `minProgress` (optional: graduation %), `maxPrice` (optional: max USD price) - **Example**: `/galachain-launchpad:discover-tokens type=near-graduation minProgress=90 limit=10` - Helps find investment opportunities with filtering and analysis ### Real-Time Monitoring Commands - NEW v2.0 **`/galachain-launchpad:watch-dex-pools`** - **NEW v2.0** - Monitor new DEX pool creation events in real-time via WebSocket - **Arguments**: `duration` (optional: seconds, default 60), `minTVL` (optional: minimum TVL filter), `tokens` (optional: comma-separated token symbols) - **Example**: `/galachain-launchpad:watch-dex-pools duration=300 minTVL=100000 tokens=GALA,GUSDC` - Real-time alerts as new liquidity pools are created **`/galachain-launchpad:watch-token-launches`** - **NEW v2.0** - Monitor new token launch events in real-time via WebSocket - **Arguments**: `duration` (optional: seconds, default 60), `creatorAddress` (optional: filter by creator) - **Example**: `/galachain-launchpad:watch-token-launches duration=300 creatorAddress=eth|...` - Discover new tokens immediately as they launch ### DEX Pool Discovery Commands **`/galachain-launchpad:fetch-dex-pools`** - Discover DEX liquidity pools with pagination and filtering - **Arguments**: `search` (optional: token symbol filter), `sortBy` (optional: tvl/volume30d/volume1d, default: tvl), `sortOrder` (optional: asc/desc, default: desc), `page` (optional, default: 1), `limit` (optional, default: 10, max: 20) - **Example**: `/galachain-launchpad:fetch-dex-pools search=GALA sortBy=volume30d limit=10` - Browse DEX pools with complete metrics: TVL, trading volume, APR, and fee data **`/galachain-launchpad:fetch-all-dex-pools`** - Discover ALL available DEX liquidity pools with automatic pagination - **Arguments**: `search` (optional: token symbol filter), `sortBy` (optional: tvl/volume30d/volume1d, default: tvl), `sortOrder` (optional: asc/desc, default: desc) - **Example**: `/galachain-launchpad:fetch-all-dex-pools search=GUSDC sortBy=volume1d sortOrder=asc` - Retrieves the complete list of all DEX pools - perfect for comprehensive analysis and discovery ### Pool Management Commands **`/galachain-launchpad:fetch-pools`** - Fetch token pools with filtering **`/galachain-launchpad:fetch-pool-details`** - **NEW v2.0** - Get comprehensive bonding curve pool analytics **`/galachain-launchpad:fetch-pool-details-for-calculation`** - Get optimized pool details for local calculations **`/galachain-launchpad:fetch-token-details`** - Fetch comprehensive token metadata **`/galachain-launchpad:fetch-token-distribution`** - Get holder distribution and supply metrics **`/galachain-launchpad:fetch-volume-data`** - Get OHLCV (candlestick) data for charting **`/galachain-launchpad:fetch-gala-spot-price`** - Fetch current GALA USD spot price **`/galachain-launchpad:fetch-price-history`** - Fetch historical price snapshots with pagination **`/galachain-launchpad:fetch-all-price-history`** - Fetch all historical price data (auto-paginated) **`/galachain-launchpad:check-token-name`** - Check if token name is available **`/galachain-launchpad:check-token-symbol`** - Check if token symbol is available **`/galachain-launchpad:resolve-vault-address`** - Get GalaChain vault address for a token **`/galachain-launchpad:resolve-token-class-key`** - Get GalaChain TokenClassKey for a token ### Trading Calculation Commands **`/galachain-launchpad:calculate-buy-amount`** - Calculate token amounts for buying **`/galachain-launchpad:calculate-sell-amount`** - Calculate GALA amounts for selling **`/galachain-launchpad:fetch-trades`** - Query trading history with optional filters **`/galachain-launchpad:calculate-initial-buy`** - Calculate pre-buy amounts during token creation **`/galachain-launchpad:get-bundler-transaction-result`** - Check bundler transaction status by ID **`/galachain-launchpad:calculate-graduation-cost`** - Calculate cost to graduate a token pool **`/galachain-launchpad:calculate-buy-amount-local`** - Calculate buy amount using LOCAL bonding curve (instant) **`/galachain-launchpad:calculate-buy-amount-external`** - Calculate buy amount using EXTERNAL GalaChain call **`/galachain-launchpad:calculate-sell-amount-local`** - Calculate sell amount using LOCAL bonding curve **`/galachain-launchpad:calculate-sell-amount-external`** - Calculate sell amount using EXTERNAL GalaChain call **`/galachain-launchpad:is-token-graduated`** - Check if token has completed bonding curve and graduated to DEX ### Balance & Portfolio Commands **`/galachain-launchpad:fetch-gala-balance`** - Get your GALA balance **`/galachain-launchpad:fetch-token-balance`** - Get balance for a specific token **`/galachain-launchpad:fetch-tokens-created`** - List tokens you've created with status **`/galachain-launchpad:update-profile`** - Update your user profile information ### Creation Utility Commands **`/galachain-launchpad:upload-profile-image`** - Upload profile image from filesystem **`/galachain-launchpad:fetch-launch-token-fee`** - Get current GALA fee required to launch a token ### Transfer Commands **`/galachain-launchpad:transfer-gala`** - Transfer GALA tokens to another wallet **`/galachain-launchpad:transfer-token`** - Transfer launchpad tokens to another wallet ### Utility & System Commands **`/galachain-launchpad:create-wallet`** - Generate a new wallet with random private key **`/galachain-launchpad:get-address`** - Get the GalaChain format address of authenticated wallet **`/galachain-launchpad:get-ethereum-address`** - Get the standard Ethereum address format of authenticated wallet **`/galachain-launchpad:get-config`** - View current SDK and MCP server configuration **`/galachain-launchpad:get-url-by-token-name`** - Get the launchpad frontend URL for a token **`/galachain-launchpad:explain-sdk-usage`** - Get detailed SDK usage examples for a topic **`/galachain-launchpad:get-cache-info`** - Get token metadata cache statistics **`/galachain-launchpad:clear-cache`** - Clear token metadata cache **`/galachain-launchpad:has-wallet`** - Check if a wallet is configured in the MCP server **`/galachain-launchpad:get-wallet`** - Get the currently configured wallet instance **`/galachain-launchpad:set-wallet`** - Configure a wallet for signing operations **`/galachain-launchpad:get-environment`** - Get the current MCP server environment ### Version Command **`/galachain-launchpad:version`** - Display SDK and MCP server version information - **Arguments**: None - Shows current version numbers and release information ### Slash Command Benefits ✅ **Quick access** - Type `/galachain-launchpad:` to see all available commands ✅ **Guided workflows** - Each command provides step-by-step execution ✅ **Optimized** - Uses LOCAL calculations for maximum performance ✅ **Safe** - Asks for confirmation before executing transactions ✅ **Educational** - Shows what MCP tools are being used behind the scenes ✅ **Real-time monitoring** - **NEW v2.0** - WebSocket watchers for pools and token launches ### Example Slash Command Usage ```text User: /galachain-launchpad:analyze-token tokenName=anime Claude: I'll analyze the token "anime" using the Gala Launchpad MCP server: 1. Fetching optimized pool details... ✅ Current supply: 510,379.79 ✅ Remaining tokens: 9,489,620.21 ✅ Max supply: 10,000,000 2. Calculating USD spot price (LOCAL mode - instant!)... ✅ Spot price: $0.000153 3. Calculating graduation cost (LOCAL mode - instant!)... ✅ GALA required: 1,640,974.33 GALA ✅ Transaction fee: 1,640.97 GALA ✅ Total cost: 1,642,615.30 GALA 4. Pool progress: 5.10% complete Analysis: - Current price is relatively low (early stage token) - Requires significant GALA (~1.6M) to graduate - Only 5% through bonding curve - high risk, high potential reward - Good opportunity for early entry if you believe in the project ``` ## 📚 SDK Usage Reference The MCP server includes a built-in SDK documentation tool that provides complete, runnable code examples for using the SDK directly instead of through MCP tools. This is perfect for developers who want to integrate the SDK into their applications. **Ask Claude for SDK code examples:** > "Explain how to buy tokens using the SDK" > "Show me the SDK code for selling tokens" > "How do I use multiple wallets with the SDK?" > "Show me all MCP tools and their SDK method equivalents" **Available topics:** - `buy-tokens` - Complete buying workflow - `sell-tokens` - Complete selling workflow - `pool-graduation` - Graduate bonding curve pools - `fetch-pools` - Query pool data - `balances` - Check GALA and token balances - `token-creation` - Launch new tokens - `multi-wallet` - Multi-wallet patterns - `transfers` - Transfer tokens between wallets - `error-handling` - Handle exceptions - `installation` - Install and configure SDK - `local-calculations` - Local vs external bonding curve calculations - `mcp-to-sdk-mapping` - Complete tool-to-method mapping Each topic returns complete TypeScript code with explanations, making it easy to transition from MCP tools to direct SDK integration. ## 🔐 Multi-Wallet Support All signing operations support an optional `privateKey` parameter for per-operation wallet overrides. This enables: - Testing multi-wallet workflows - Simulating different user behaviors - Building multi-agent trading systems - Operating multiple wallets from a single MCP server ### Tools Supporting privateKey Override **Trading Operations:** - `gala_launchpad_buy` - Buy tokens from different wallet - `gala_launchpad_sell` - Sell tokens from different wallet **Token Creation:** - `gala_launchpad_launch_token` - Create token from different wallet - `gala_launchpad_upload_token_image` - Upload image for token - `gala_launchpad_upload_profile_image` - Upload profile image **Transfer Operations:** - `gala_launchpad_transfer_gala` - Transfer GALA from different wallet (the key signs that one transfer and is never stored) - `gala_launchpad_transfer_token` takes no override: a `privateKey` is refused (configure the session wallet, `set_wallet`) **Profile:** - `gala_launchpad_update_profile` - Update profile for different wallet ### Example: Multi-Wallet Trading Scenario Ask Claude: > "Create a scenario where Buster's wallet buys and sells tokens: > 1. Send Buster 1000 GALA from the main wallet > 2. Have Buster buy 100 GALA worth of tinyevil tokens using his private key: 0x1234... > 3. Have Buster sell 50 GALA worth back > 4. Check both wallets' final balances" Claude will use: ```javascript // 1. Main wallet sends GALA to Buster gala_launchpad_transfer_gala({ recipientAddress: "0xBusterAddress...", amount: "1000" // No privateKey - uses main wallet }); // 2. Buster buys tokens with his wallet gala_launchpad_buy({ tokenName: "tinyevil", amount: "100", type: "native", expectedAmount: "50000", slippageToleranceFactor: 0.05, privateKey: "0x1234..." // Buster's wallet }); // 3. Buster sells tokens gala_launchpad_sell({ tokenName: "tinyevil", amount: "50", type: "native", expectedAmount: "48", slippageToleranceFactor: 0.05, privateKey: "0x1234..." // Buster's wallet }); ``` ### Private Key Format Requirements The `privateKey` parameter must be: - **Format**: `'0x' + 64 hexadecimal characters` - **Example**: `'0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'` - **Invalid**: Raw hex without '0x', mnemonics, or addresses ### Security Considerations When using privateKey overrides: 1. **Never expose private keys** in prompts or logs 2. **Use test wallets** for development and testing 3. **Limit fund amounts** in test wallets 4. **Monitor operations** when testing multi-wallet scenarios 5. **Validate addresses** before transfers ## 🔧 Development ### Local Development ```bash # From the root of the repository checkout (core, the product SDKs and this server are one pnpm workspace) # Install dependencies pnpm install # Build the SDKs this server resolves through their dist/, then the server pnpm --filter @gala-chain/gala-core-sdk run build pnpm --filter @gala-chain/gswap-sdk run build pnpm --filter @gala-chain/launchpad-sdk run build pnpm --filter @gala-chain/gala-mcp-server run build # Run in development mode pnpm --filter @gala-chain/gala-mcp-server run dev ``` ### Layout ```text src/session/ wallet, environment and settings, shared by every toolset (the env contract lives here) src/toolsets/core/ tools, prompts and the client that need only gala-core-sdk src/toolsets/launchpad/ ... gala-core-sdk + launchpad-sdk src/toolsets/gswap/ ... gala-core-sdk + gswap-sdk src/toolsets/composite/ ... launchpad-sdk + gswap-sdk (enabled with both) src/toolsets/shared/ SDK-free helpers (tool factory, handler factories) src/toolsets/registry.ts, selection.ts load the enabled toolsets (a dynamic import each), parse GALA_TOOLSETS / --toolsets src/manifests/ generated tool and prompt manifests (pnpm generate:manifest; CI runs validate:manifest) ``` A tool belongs to the toolset whose SDKs its handler needs. `launchpad` and `gswap` never import each other or `composite`, `core` imports no product SDK, and the shared code and `src/schemas` import none; `boundary.test.ts` reads the import graph and fails on a violation, and `module-graph.test.ts` checks what a run actually loads. ### Testing ```bash pnpm --filter @gala-chain/gala-mcp-server exec vitest run --maxWorkers=4 # unit tests (SDKs built first) pnpm --filter @gala-chain/gala-mcp-server run validate:manifest # manifests current pnpm --filter @gala-chain/gala-mcp-server run smoke:stdio # starts each selection over stdio, tools/list, clean exit ``` ## 📚 Documentation - [AI Agent Guide](/launchpad-sdk/next/ai-agent-guide.md) - Integration patterns - [Launchpad SDK documentation](/launchpad-sdk/next/overview.md) - Underlying SDK reference ## 🔐 Security **Important Security Notes:** 1. **Private Keys** - Never commit private keys to version control 2. **Environment Variables** - Store credentials in `claude_desktop_config.json` securely 3. **Wallet Safety** - Use separate wallets for development and production 4. **Amount Limits** - Consider setting up trading limits for automated agents ## 🐛 Troubleshooting ### "SDK not initialized" - Ensure `PRIVATE_KEY` is set in environment variables - Check that private key format is valid (0x + 64 hex characters) ### "Tool not found" - Restart Claude Desktop after configuration changes - Verify server is listed in Claude Desktop settings ### "Connection failed" - Check DEBUG=true logs for detailed error messages - Verify network connectivity to Gala Launchpad backends ## 📄 License MIT License - see the `LICENSE` file in the package for details. ## 🤝 Contributing Contributions welcome! Please read `CONTRIBUTING.md` in the monorepo root for guidelines. ## 📞 Support - **Documentation**: [Full Documentation](/launchpad-sdk/next/overview.md) - **SDK Package**: [@gala-chain/launchpad-sdk](https://www.npmjs.com/package/@gala-chain/launchpad-sdk) --- **Built with ❤️ for the Gala ecosystem** --- # 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](#common-workflows) - [GSwap DEX Swap Workflow (queued RequestTrade)](#8-gswap-dex-swap-workflow-queued-requesttrade) - [Critical Gotchas](#critical-gotchas) - [Gotcha #7: Swap outcome unknown — never resubmit](#gotcha-7-swap-outcome-unknown--never-resubmit) - [Gotcha #8: DEX slippage rejection](#gotcha-8-dex-slippage-rejection) - [Constraint Reference](#constraint-reference) - [Error Troubleshooting](#error-troubleshooting) - [Best Practices](#best-practices) --- ## Common Workflows ### 1. Token Launch Workflow **Complete token creation from scratch:** ```mcp // 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** ```mcp // 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:** - `expectedAmount` must be `result.amount` from calculate function, NOT your input amount! - `maxAcceptableReverseBondingCurveFee` must be `result.reverseBondingCurveFee` from calculate function! ### 3. Trading Workflow (Sell Tokens) **Same two-step pattern:** ```mcp // 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:** ```mcp // 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:** ```mcp // ============================================================================ // 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:** - `lockAuthority` defaults to caller - only the authority can unlock - `name` parameter helps identify specific locks when unlocking - `expires` timestamp 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. ```mcp // 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:** ```mcp // 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:** ```mcp // 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:** ```mcp // 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:** ```mcp // 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:** ```mcp gala_launchpad_buy({ amount: '10', expectedAmount: '10' // ❌ WRONG - This is your input, not the expected output! }) ``` **Correct:** ```mcp // 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:** ```mcp gala_launchpad_fetch_trades({ pageSize: 100 // ❌ WRONG - Trades max is 20! }) ``` **Correct:** ```mcp 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:** ```mcp gala_launchpad_fetch_tokens_held({ tokenName: 'anime', // Exact match pageSize: 1 // Only need 1 result }) ``` **Use `search` for discovery:** ```mcp 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|` - a GalaChain alias, sent as written - ❌ `eth|0x<40 hex digits>` - **not an address form**: refused with `INVALID_ETH_USER_REF_PREFIX`; an `eth|` reference takes the 40 digits with no `0x` (the error's `expected` names 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: ```mcp // 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})$` | `'eth\|abc123...'`, `'0xabc123...'` (auto-normalized) | | `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:** ```mcp // 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:** ```mcp // 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: ```mcp 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 `expectedAmount` for 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 pools - `0.05` (5%) - Standard for most trades - `0.10` (10%) - High volatility, new tokens ### 4. Use Token Filtering Efficiently **For single token lookups:** ```mcp gala_launchpad_fetch_token_balance({ tokenName: 'anime', address: 'eth|...' }) // 99% payload reduction vs fetching all tokens ``` **For discovery:** ```mcp gala_launchpad_fetch_tokens_held({ search: 'dragon', pageSize: 10 }) ``` ### 5. Verify Trades Complete After executing trades, always verify: ```mcp 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: ```mcp // 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 1. `calculate_buy_amount()` or `calculate_sell_amount()` 2. Extract `result.amount` from response 3. Use `result.amount` as `expectedAmount` in buy/sell 4. Verify with `fetch_trades()` ### Lock/Unlock Flow 1. `lock_tokens()` - Lock tokens, passed as a `tokens` array (optional: lockAuthority, name, expires) 2. `unlock_tokens()` - Release tokens, passed as a `tokens` array (must be lock authority) 3. Use `name` to 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](/gala-mcp-server/next/overview.md) - [SDK Documentation](/launchpad-sdk/next/overview.md) - Constraints reference: `docs/CONSTRAINTS-REFERENCE.md` in the package --- # GalaChain Launchpad SDK - GSwap Pool Inspection & Quotes ## Installation ```bash npm install @gala-chain/launchpad-sdk@next @gala-chain/gala-core-sdk@next ``` --- ## Setup ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ wallet: process.env.PRIVATE_KEY!, env: 'prod', }); ``` --- ## Pool Inspection + Live Quotes The DEX is `@gala-chain/gswap-sdk`'s `GSwap` client (the MCP server's DEX tools build one from the same key as the launchpad SDK; launchpad-sdk itself has none). `gSwap.pools.getCompositePool` returns a raw contract snapshot (pool info, current price, tick liquidity, and positions) for inspecting a pool. It is not wired into any offline quote calculator — every quote comes from a live call to `gSwap.quoting`. ```typescript continue import BigNumber from 'bignumber.js'; import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(process.env.PRIVATE_KEY!), walletAddress: sdk.getAddress(), // the launchpad SDK built with the same key }); // STEP 1: Inspect the pool's current state (one network call) const composite = await gSwap.pools.getCompositePool( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', 3000, // 0.30% fee tier ); console.log('Current price:', composite.currentTradingPrice.price); // STEP 2: Get a live quote for the amount you actually want to trade (its own network call) const quote = await gSwap.quoting.quoteExactInput( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', '100', ); console.log('100 GALA ->', quote.amountOut, 'GUSDC'); // STEP 3: Submit the swap — this queues a RequestTrade, then waits for it to apply const submitted = await gSwap.swaps.swap( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', quote.feeTier, { exactIn: '100', amountOutMinimum: new BigNumber(quote.amountOut).times(0.99).toFixed(), // 1% slippage }, ); const applied = await submitted.confirm(); console.log('Applied transaction:', applied.transactionId); ``` --- ## Multiple Quotes Example There is no local/offline calculation path off a cached pool snapshot — each amount you want priced is its own call to `quoteExactInput`/`quoteExactOutput`. ```typescript continue const amounts = ['10', '50', '100', '500', '1000', '5000', '10000']; for (const amount of amounts) { const quote = await gSwap.quoting.quoteExactInput( 'GALA|Unit|none|none', 'GUSDC|Unit|none|none', amount, ); console.log(`${amount} GALA -> ${quote.amountOut} GUSDC`); } ``` --- ## Recovering a Swap Whose Outcome Is Unknown If `.confirm()` times out or a dispatch failure leaves the outcome unclear, resolve the queued request by its `uniqueKey` instead of resubmitting — resubmitting a consumed key is unsafe: ```typescript continue const recovered = await gSwap.swaps.confirmSwap(submitted.uniqueKey); ``` --- ## Fee Tiers | Value | Rate | Use Case | |-------|------|----------| | `500` | 0.05% | Stable pairs | | `3000` | 0.30% | Standard (default) | | `10000` | 1.00% | Volatile pairs | --- ## Token Format Pipe-delimited: `collection|category|type|additionalKey` | Token | Format | |-------|--------| | GALA | `GALA\|Unit\|none\|none` | | GUSDC | `GUSDC\|Unit\|none\|none` | --- # Tier 1 Workflows - Quick Reference Guide ## Pool Discovery: `/galachain-launchpad:discover-pools` Find DEX liquidity pools with metrics. **Arguments:** - `search` (optional) - Token symbol filter - `sortBy` (optional) - tvl, volume30d, volume1d, fee - `limit` (optional) - 1-100 pools - `minTvl` (optional) - Minimum TVL in USD - `minVolume` (optional) - Minimum 24h volume in USD **Example:** ```text /galachain-launchpad:discover-pools sortBy=volume1d limit=10 minTvl=50000 ``` **Related Commands:** - `/galachain-launchpad:fetch-all-pools` - Get all pools - `/galachain-launchpad:fetch-pool-details` - Detailed analytics - `/galachain-launchpad:check-leaderboard` - Top pools ranking --- ## Token Analysis: `/galachain-launchpad:analyze-token` Complete due diligence on a token. **Arguments:** - `tokenName` (required) - Token to analyze **Example:** ```text /galachain-launchpad:analyze-token tokenName=anime ``` **Related Commands:** - `/galachain-launchpad:fetch-token-distribution` - Holder analysis - `/galachain-launchpad:fetch-volume-data` - Volume trends **Key Metrics:** - Whale concentration (top 5 holders %) - Holder count and distribution - 24h/7d/30d volume - Achievement badges --- ## Price Trends: `/galachain-launchpad:price-trends` Technical analysis with moving averages. **Arguments:** - `tokenName` (required) - Token to analyze - `days` (optional) - 1-365 days of history **Example:** ```text /galachain-launchpad:price-trends tokenName=demonkpop days=30 ``` **Related Commands:** - `/galachain-launchpad:fetch-price-history` - OHLC data - `/galachain-launchpad:fetch-current-price` - Spot price - `/galachain-launchpad:fetch-all-price-history` - Complete history (Node.js only) **Indicators:** - 7-day & 30-day moving averages - Support/resistance levels - Volatility (standard deviation) - Trend direction --- ## Liquidity Management: `/galachain-launchpad:manage-liquidity` LP position lifecycle management. **Arguments:** - `action` (required) - add, monitor, collect, remove - `token0`, `token1`, `feeTier`, `minPrice`, `maxPrice`, `amount0`, `amount1` - For "add" action **Example:** ```text /galachain-launchpad:manage-liquidity action=add token0=GALA token1=GUSDC feeTier=3000 minPrice=0.24 maxPrice=0.30 amount0Desired=1000 amount1Desired=300 ``` **Related Commands:** - `/galachain-launchpad:add-liquidity-by-price` - Create position - `/galachain-launchpad:collect-fees` - Harvest fees - `/galachain-launchpad:remove-liquidity` - Exit position **Fee Tiers:** - 500 = 0.05% (low volatility) - 3000 = 0.30% (standard) - 10000 = 1.00% (high volatility) --- ## Bridge Operations: `/galachain-launchpad:bridge-tokens` Cross-chain transfers and wrapping. **Arguments:** - `action` (required) - out, in, wrap, unwrap, fee, status - `network` (required for bridges) - ethereum, solana - `tokenId` (required for wraps) - Token to bridge - `amount` (required) - Amount to transfer - `txId` (required for status) - Transaction to check **Examples:** ```text /galachain-launchpad:bridge-tokens action=out network=ethereum tokenId=GALA amount=100 /galachain-launchpad:bridge-tokens action=wrap tokenId=MUSIC amount=100 /galachain-launchpad:bridge-tokens action=status txId=abc123... ``` **Related Commands:** - `/galachain-launchpad:discover-bridgeable-tokens` - Which tokens bridge where - `/galachain-launchpad:estimate-fee` - Calculate costs - `/galachain-launchpad:bridge-status` - Check transaction **Supported Tokens:** - **Ethereum:** GALA, GWETH, GUSDC, GUSDT, GWTRX, GWBTC - **Solana:** GALA, GSOL - **Internal:** MUSIC ↔ GMUSIC --- ## Common Workflows ### Before Trading (3 steps) 1. Discover pools: `/discover-pools sortBy=volume1d` 2. Analyze token: `/analyze-token tokenName=...` 3. Check price trends: `/price-trends tokenName=...` ### For Liquidity Providers (5 steps) 1. Discover pools: `/discover-pools sortBy=volume1d` 2. Manage liquidity: `/manage-liquidity action=add` 3. Monitor: `/manage-liquidity action=monitor` 4. Collect: `/manage-liquidity action=collect` 5. Remove: `/manage-liquidity action=remove` ### Multi-Chain Portfolio (3 steps) 1. Check bridgeable: `/discover-bridgeable-tokens network=ethereum` 2. Estimate fee: `/estimate-fee operation=bridge network=ethereum tokenId=GALA amount=100` 3. Bridge: `/bridge-tokens action=out network=ethereum tokenId=GALA amount=100` --- ## Decision Tree ### "I want to trade a token" ```text → /discover-pools (find where it trades) → /analyze-token (is it safe?) → /price-trends (when should I buy?) → Execute trade ``` ### "I want to provide liquidity" ```text → /discover-pools (find best pool) → /manage-liquidity action=add (deposit capital) → /manage-liquidity action=monitor (watch position) → /manage-liquidity action=collect (harvest fees) ``` ### "I want to move funds between chains" ```text → /discover-bridgeable-tokens (what can bridge?) → /estimate-fee (how much does it cost?) → /bridge-tokens action=out (initiate bridge) → /bridge-status (monitor transfer) ``` --- ## Pro Tips **Pool Discovery:** - Sort by volume1d for active markets - Set minTvl=50000 to avoid low-liquidity traps - Check leaderboard for market consensus **Token Analysis:** - Red flag: Top 5 holders > 60% - Good sign: 500+ holders with diverse distribution - Watch volume trend: Growing or declining? **Price Trends:** - Price > 7d SMA > 30d SMA = Uptrend - Price < 7d SMA < 30d SMA = Downtrend - High volatility = Wider stops needed **Liquidity Management:** - Tight range (±5%) = High APR, needs monitoring - Normal range (±10%) = Balanced, recommended - Wide range (±20%+) = Low APR, minimal monitoring **Bridge Operations:** - Ethereum: Higher fees, 10-30 min - Solana: Lower fees, 5-20 min - Wrap/unwrap: Instant, minimal fee --- # Tier 3 Prompts Quick Reference **Fast lookup guide for Tier 3 (MEDIUM Priority) workflow prompts.** Moderation, community engagement and streaming prompts. --- ## Moderation Workflows | Prompt | Purpose | Arguments | Quick Example | |--------|---------|-----------|---------------| | **invite-moderators** | Add new moderators to community | `tokenName`, `role`, `description`, `expiresAt` | `/galachain-launchpad:invite-moderators tokenName=mytoken role=MODERATOR` | | **manage-moderators** | List, promote, demote, revoke | `tokenName`, `action` (list/promote/demote/revoke), `address` | `/galachain-launchpad:manage-moderators tokenName=mytoken action=list` | | **moderate-comments** | Review, approve, delete, flag comments | `tokenName`, `action` (list/delete/flag/approve), `commentId`, `reason` | `/galachain-launchpad:moderate-comments tokenName=mytoken action=list` | | **ban-users** | Temporary/permanent user bans | `tokenName`, `userAddress`, `banDuration` (1h/1d/1w/1m/permanent), `reason` | `/galachain-launchpad:ban-users tokenName=mytoken userAddress=eth\|1234567890123456789012345678901234567890 banDuration=1week` | --- ## Community Engagement | Prompt | Purpose | Arguments | Quick Example | |--------|---------|-----------|---------------| | **post-comments** | Post and reply to comments | `tokenName`, `content`, `parentCommentId` | `/galachain-launchpad:post-comments tokenName=mytoken content="Great project!"` | | **react-to-content** | Add emoji reactions | `contentType` (comment/pool/chat_message), `contentId`, `reaction` (like/love/haha/wow/sad/angry) | `/galachain-launchpad:react-to-content contentType=comment contentId=123 reaction=love` | | **monitor-community** | Analytics & health metrics | `tokenName`, `timeframe` (1h/24h/7d/30d), `metric` (engagement/growth/sentiment) | `/galachain-launchpad:monitor-community tokenName=mytoken timeframe=7d metric=engagement` | --- ## Streaming Management | Prompt | Purpose | Arguments | Quick Example | |--------|---------|-----------|---------------| | **manage-streams** | Start, stop, configure, monitor streams | `tokenName`, `action` (start/stop/configure/status), `settings` | `/galachain-launchpad:manage-streams tokenName=mytoken action=start` | | **manage-recordings** | Access VOD recordings | `tokenName`, `action` (list/download/delete/share), `recordingId`, `quality` | `/galachain-launchpad:manage-recordings tokenName=mytoken action=list` | | **manage-simulcast** | Multi-platform streaming setup | `tokenName`, `action` (add/list/test/remove), `platform`, `url`, `streamKey` | `/galachain-launchpad:manage-simulcast tokenName=mytoken action=add platform=youtube` | --- ## Quick Navigation ### By Use Case **Need to manage moderators?** - List moderators → `manage-moderators action=list` - Add moderator → `invite-moderators role=MODERATOR` - Update role → `manage-moderators action=promote` - Remove moderator → `manage-moderators action=revoke` **Need to moderate content?** - Review comments → `moderate-comments action=list` - Delete spam → `moderate-comments action=delete` - Ban user → `ban-users reason="spam"` **Need community engagement?** - Post comment → `post-comments content="text"` - React to comment → `react-to-content reaction=like` - Check health → `monitor-community metric=engagement` **Need to stream?** - Start stream → `manage-streams action=start` - Add YouTube → `manage-simulcast action=add platform=youtube` - Get recordings → `manage-recordings action=list` - Download VOD → `manage-recordings action=download` ### By Role **Community Manager:** - `invite-moderators` - Onboard moderators - `manage-moderators` - Track moderator team - `monitor-community` - Dashboard for metrics - `moderate-comments` - Handle flagged content **Moderator:** - `ban-users` - Enforce rules - `moderate-comments` - Remove spam - `manage-moderators` - View team **Streamer:** - `manage-streams` - Live broadcast control - `manage-simulcast` - Multi-platform setup - `manage-recordings` - VOD management **Community Member:** - `post-comments` - Participate in discussion - `react-to-content` - Engage with content - `monitor-community` - Watch community growth --- ## Common Workflows ### Onboard a New Moderator ```text 1. invite-moderators (role=MODERATOR, description="Name - role") 2. Share generated invite URL 3. Moderator claims invite with wallet 4. Verify in manage-moderators action=list ``` ### Set Up Multi-Platform Stream ```text 1. manage-streams action=start (get primary RTMP URL) 2. manage-simulcast action=add platform=youtube (get YT stream key) 3. Add to OBS/Wirecast: Primary URL 4. OBS outputs to primary, auto-forwards to YouTube 5. manage-simulcast action=list (check status) 6. View metrics from manage-streams action=status ``` ### Enforce Community Guidelines ```text 1. moderate-comments action=list (review pending) 2. Delete spam: moderate-comments action=delete reason="spam" 3. Flag borderline: moderate-comments action=flag 4. Serious: ban-users reason="harassment" banDuration=1week 5. Track: monitor-community metric=engagement ``` ### Archive Live Stream ```text 1. Stream is automatically recorded 2. manage-recordings action=list (see available) 3. manage-recordings action=download quality=hd 4. Recording URL valid for 24 hours 5. Download before auto-deletion (30 days) ``` --- ## Argument Cheat Sheet ### Ban Durations - `1hour` or `1h` - 1 hour (shortest) - `1day` or `1d` - 24 hours - `1week` or `1w` - 7 days - `1month` or `1m` - 30 days - `permanent` - No auto-expiration ### Reactions - `like` - 👍 Thumbs up - `love` - ❤️ Heart - `haha` - 😂 Laugh - `wow` - 😮 Wow - `sad` - 😢 Sad face - `angry` - 😠 Angry face ### Content Types - `comment` - Comments on token pages - `pool` - Pool/token announcements - `chat_message` - Stream/community chat ### Moderation Actions - `list` - View items - `delete` - Remove - `flag` - Mark for review - `approve` - Confirm visibility - `add`/`remove` - Create/delete ### Timeframes - `1h` - 1 hour - `24h` - Full day - `7d` - 1 week - `30d` - 1 month ### Stream Quality - `hd` - 1080p (best quality, larger file) - `sd` - 720p (balanced) ### Moderator Roles - `MODERATOR` - Comment/chat/ban/unban - `TECHNICAL_PRODUCER` - Stream control, simulcast - `MANAGER` - All + recordings + settings --- ## Common Issues ### Ban/Unban **Q: How do I unban someone?** - Use `manage-moderators` with action=revoke (old role) then action=promote to new role - Or wait for ban duration to expire automatically ### Recording Not Available **Q: Where's my recording?** - Auto-saved after stream ends - Check `manage-recordings action=list` - Available for 30 days (configurable) - Download before expiration ### Simulcast Connection Failed **Q: Why isn't YouTube getting the stream?** 1. Verify stream key is correct 2. Test: `manage-simulcast action=test platform=youtube` 3. Check OBS/Wirecast output bitrate matches platform limits 4. Verify network connectivity on both sides ### Community Health Low **Q: Engagement is dropping, what happened?** 1. Check sentiment: `monitor-community metric=sentiment` 2. Review moderation: too many bans? 3. Check posts: `monitor-community metric=engagement` 4. Survey community or post announcement --- ## Testing Commands ```bash # Verify all Tier 3 prompts exist /galachain-launchpad:invite-moderators tokenName=test /galachain-launchpad:manage-moderators tokenName=test /galachain-launchpad:moderate-comments tokenName=test /galachain-launchpad:ban-users tokenName=test /galachain-launchpad:post-comments tokenName=test /galachain-launchpad:react-to-content contentType=comment /galachain-launchpad:monitor-community tokenName=test /galachain-launchpad:manage-streams tokenName=test /galachain-launchpad:manage-recordings tokenName=test /galachain-launchpad:manage-simulcast tokenName=test ``` --- ## Performance Tips **For Moderators:** - Review comments in batches (action=list, then bulk delete) - Use flags for team discussion before permanent delete - Track ban history to refine criteria **For Streamers:** - Test simulcast connection before going live - Record backups locally while streaming - Monitor multi-platform chat simultaneously - Adjust bitrate if platforms are out of sync **For Managers:** - Regular check-ins with moderators (manage-moderators) - Monthly community health report (monitor-community timeframe=30d) - Archive important recordings before expiration - Review sentiment trends for engagement drops --- **Version**: Phase 4 - Tier 3 Quick Reference **Last Updated**: January 11, 2026 **Status**: ✅ Complete --- # SDK usage topics Task-oriented examples for the Gala SDKs, one section per topic: the key concept, when to use it, the SDK methods it covers, a complete example, the MCP tools that do the same job and the pitfalls. The `gala_launchpad_explain_sdk_usage` tool returns one section of this page by topic key (the anchor of a section is `topic-`), read from the docs index, so a fix to a section reaches agents without an npm release. Every example is compiled against the built SDK types by the docs build. ## Buy Tokens **Key concept:** Bonding-curve buys are flat LaunchpadSDK methods. Calculate the expected output before submitting so the transaction carries amount and fee protection. **When to use:** Use for a token that has not graduated to the current-contract DEX. **Covers methods:** `calculateBuyAmount()`, `buy()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const quote = await sdk.calculateBuyAmount({ tokenName: 'anime', amount: '100', type: 'native' }); const result = await sdk.buy({ tokenName: 'anime', amount: '100', type: 'native', expectedAmount: quote.amount, maxAcceptableReverseBondingCurveFee: quote.reverseBondingCurveFee, slippageToleranceFactor: 0.01 }); console.log(result.transactionId, result.outputAmount); ``` **MCP Tool Equivalents:** - `gala_launchpad_calculate_buy_amount` - `gala_launchpad_buy` **Pitfalls:** Do not pass a pipe-delimited TokenClassKey to buy(); bonding-curve methods use the simple token name. **Related Topics:** `sell-tokens`, `pool-graduation`, `token-identification` ## Sell Tokens **Key concept:** A bonding-curve sale uses calculateSellAmount() followed by sell() with the returned expected amount and reverse-fee bound. **When to use:** Use before graduation when the token is still traded by the Launchpad bonding curve. **Covers methods:** `calculateSellAmount()`, `sell()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const quote = await sdk.calculateSellAmount({ tokenName: 'anime', amount: '100', type: 'exact' }); const result = await sdk.sell({ tokenName: 'anime', amount: '100', type: 'exact', expectedAmount: quote.amount, maxAcceptableReverseBondingCurveFee: quote.reverseBondingCurveFee, slippageToleranceFactor: 0.01 }); console.log(result.transactionId, result.outputAmount); ``` **MCP Tool Equivalents:** - `gala_launchpad_calculate_sell_amount` - `gala_launchpad_sell` **Pitfalls:** Use exact for the token quantity you are selling; use native only for a target GALA amount. **Related Topics:** `buy-tokens`, `pool-graduation` ## Pool Graduation **Key concept:** Graduation is a flat Launchpad workflow: estimate the required buy amount, then call graduateToken() to move the pool to DEX trading. **When to use:** Use when a token is near its graduation threshold and the wallet is ready to submit the migration trade. **Covers methods:** `calculateBuyAmountForGraduation()`, `graduateToken()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const quote = await sdk.calculateBuyAmountForGraduation('anime'); console.log('GALA required:', quote.amount); const result = await sdk.graduateToken({ tokenName: 'anime', slippageToleranceFactor: 0.01 }); console.log(result.transactionId); ``` **MCP Tool Equivalents:** - `gala_launchpad_calculate_buy_amount_for_graduation` - `gala_launchpad_graduate_token` **Pitfalls:** After graduation, trade with a gswap-sdk GSwap client and the resulting TokenClassKey; do not continue bonding-curve trading blindly. **Related Topics:** `graduation-detection`, `dex-trading`, `token-identification` ## Fetch Pools **Key concept:** fetchPools() and fetchAllPools() query bonding-curve pools; detail and calculation endpoints provide data for UI and quote workflows. **When to use:** Use for listings, token lookup, chart preparation, and deciding which trading surface applies. **Covers methods:** `fetchPools()`, `fetchAllPools()`, `fetchPoolDetails()`, `fetchPoolDetailsForCalculation()`, `fetchVolumeData()`, `fetchTokenPrice()`, `fetchTokenDistribution()`, `resolveVaultAddress()`, `resolveTokenClassKey()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const page = await sdk.fetchPools({ type: 'recent', pageSize: 10 }); const all = await sdk.fetchAllPools({ type: 'recent' }); const details = await sdk.fetchPoolDetails('anime'); const calculationData = await sdk.fetchPoolDetailsForCalculation('anime'); console.log(page, all.items.length, details, calculationData); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_pools` - `gala_launchpad_fetch_all_pools` - `gala_launchpad_fetch_pool_details` - `gala_launchpad_fetch_pool_details_for_calculation` - `gala_launchpad_fetch_volume_data` - `gala_launchpad_fetch_token_spot_price` - `gala_launchpad_fetch_token_distribution` - `gala_launchpad_resolve_vault_address` - `gala_launchpad_resolve_token_class_key` **Pitfalls:** The old token-badges endpoint was removed; use current pool, distribution, and token-detail endpoints instead. **Related Topics:** `balances`, `token-details`, `graduation-detection` ## Balances **Key concept:** Balance methods cover native GALA, token balances, available amounts, locked amounts, held tokens, and created tokens. **When to use:** Use for portfolio screens and preflight checks before a write. **Covers methods:** `fetchGalaBalance()`, `fetchTokenBalance()`, `fetchAvailableBalance()`, `fetchLockedBalance()`, `fetchTokensHeld()`, `fetchTokensCreated()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const address = sdk.getAddress(); const gala = await sdk.fetchGalaBalance(); const token = await sdk.fetchTokenBalance({ tokenName: 'anime', address }); const available = await sdk.fetchAvailableBalance({ tokenName: 'anime', address }); const locked = await sdk.fetchLockedBalance({ tokenName: 'anime', address }); const held = await sdk.fetchTokensHeld({ address, pageSize: 20 }); console.log(gala, token, available, locked, held); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_gala_balance` - `gala_launchpad_fetch_token_balance` - `gala_launchpad_fetch_available_balance` - `gala_launchpad_fetch_locked_tokens` - `gala_launchpad_fetch_tokens_held` - `gala_launchpad_fetch_tokens_created` **Pitfalls:** Available balance excludes locked amounts; use the address format expected by each method. **Related Topics:** `transfers`, `locks`, `profile-management` ## Token Creation **Key concept:** Token creation validates the name and symbol, reads the launch fee, optionally uploads an image, and calls launchToken(). **When to use:** Use when creating a new pre-graduation token from a Node.js or browser application. **Covers methods:** `isTokenNameAvailable()`, `isTokenSymbolAvailable()`, `fetchLaunchTokenFee()`, `uploadTokenImage()`, `launchToken()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); if (!(await sdk.isTokenNameAvailable('anime')) || !(await sdk.isTokenSymbolAvailable('ANIME'))) throw new Error('Name or symbol is unavailable'); console.log('Launch fee:', await sdk.fetchLaunchTokenFee()); const result = await sdk.launchToken({ tokenName: 'anime', tokenSymbol: 'ANIME', tokenDescription: 'Example token', tokenImage: 'https://example.test/anime.png' }); console.log(result.transactionId); ``` **MCP Tool Equivalents:** - `gala_launchpad_check_token_name` - `gala_launchpad_check_token_symbol` - `gala_launchpad_fetch_launch_token_fee` - `gala_launchpad_upload_token_image` - `gala_launchpad_launch_token` **Pitfalls:** Availability checks are advisory; handle a rejected launch and never put a real private key in source control. **Related Topics:** `pool-graduation`, `token-details`, `wallet-connect` ## Token Details **Key concept:** fetchTokenDetails() reads DEX-facing metadata by TokenClassKey, while fetchToken() is the Launchpad token-name lookup. **When to use:** Use when the UI needs canonical collection, symbol, decimals, or contract metadata. **Covers methods:** `fetchTokenDetails()`, `fetchPoolDetails()`, `validateToken()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const details = await sdk.fetchTokenDetails('GALA|Unit|none|none'); const launchpadToken = await sdk.fetchToken('anime'); const stats = await sdk.fetchTokenStats('anime'); console.log(details, launchpadToken, stats); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_token_details` - `gala_launchpad_fetch_pool_details` - `gala_launchpad_validate_token` **Pitfalls:** Do not confuse a simple Launchpad token name with a pipe-delimited DEX TokenClassKey. **Related Topics:** `token-identification`, `fetch-pools`, `spot-prices-smart-routing` ## Token Distribution **Key concept:** Distribution and holder-context methods expose supply ownership and a specific wallet’s position without requiring a write wallet. **When to use:** Use for token pages, concentration warnings, and holder dashboards. **Covers methods:** `fetchTokenDistribution()`, `fetchUserHolderContext()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const distribution = await sdk.fetchTokenDistribution('anime'); const context = await sdk.fetchUserHolderContext('anime', 'eth|1234567890123456789012345678901234567890'); console.log(distribution, context); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_token_distribution` - `gala_launchpad_fetch_user_holder_context` **Pitfalls:** Treat balances as decimal strings; do not use binary floating-point arithmetic for financial comparisons. **Related Topics:** `holders`, `balances`, `trading-analytics` ## Token Status **Key concept:** Use isTokenGraduated() for an explicit check and the supported Launchpad creation watcher for realtime token events. **When to use:** Use before choosing bonding-curve versus DEX code and when refreshing token listings. **Covers methods:** `isTokenGraduated()`, `onLaunchpadTokenCreation()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const graduated = await sdk.isTokenGraduated('anime'); console.log('Graduated:', graduated); const unsubscribe = sdk.onLaunchpadTokenCreation((event) => console.log('Created:', event)); unsubscribe(); ``` **MCP Tool Equivalents:** - `gala_launchpad_is_token_graduated` - `gala_launchpad_on_launchpad_token_creation` **Pitfalls:** The legacy DEX pool-creation subscription is not the supported v7 path; use current DEX reads and Launchpad realtime APIs. **Related Topics:** `graduation-detection`, `fetch-pools`, `event-subscriptions` ## Wallet Connect **Key concept:** LaunchpadSDK accepts a wallet or provider and exposes backend and Ethereum address formats through getAddress() and getEthereumAddress(). **When to use:** Use at application startup before signing operations. **Covers methods:** `getAddress()`, `getEthereumAddress()`, `hasWallet()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); if (!sdk.hasWallet()) throw new Error('Wallet is required'); console.log(sdk.getAddress()); console.log(sdk.getEthereumAddress()); ``` **MCP Tool Equivalents:** - `gala_launchpad_has_wallet` - `gala_launchpad_get_address` - `gala_launchpad_get_ethereum_address` **Pitfalls:** getAddress() returns eth| format; getEthereumAddress() returns 0x format. **Related Topics:** `multi-wallet`, `transfers`, `session-auth` ## Multi Wallet **Key concept:** The SDK supports replacing its wallet at runtime; exported helpers provide key derivation utilities for controlled onboarding flows. **When to use:** Use for account switching and key import flows. **Covers methods:** `setWallet()`, `getWallet()`, `getPublicKeyFromPrivateKey()`, `getEthereumAddressFromPrivateKey()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; import { getPublicKeyFromPrivateKey, getEthereumAddressFromPrivateKey } from '@gala-chain/gala-core-sdk'; import { Wallet } from 'ethers'; const sdk = createLaunchpadSDK({ env: 'stage' }); sdk.setWallet(new Wallet(process.env.WALLET_PRIVATE_KEY!)); console.log(sdk.getAddress(), sdk.getWallet()); const publicKey = getPublicKeyFromPrivateKey(process.env.WALLET_PRIVATE_KEY!); const ethereumAddress = getEthereumAddressFromPrivateKey(process.env.WALLET_PRIVATE_KEY!); console.log(publicKey, ethereumAddress); ``` **MCP Tool Equivalents:** - `gala_launchpad_set_wallet` - `gala_launchpad_get_wallet` - `gala_launchpad_get_public_key_from_private_key` - `gala_launchpad_get_ethereum_address_from_private_key` **Pitfalls:** The helper functions are package exports, not LaunchpadSDK instance methods; never log private keys. **Related Topics:** `wallet-connect`, `utilities-system`, `session-auth` ## Transfers **Key concept:** GALA has a dedicated transfer method; other assets use transferToken() with a token name or full token identifier. **When to use:** Use after validating the recipient and amount, with a signing wallet configured. **Covers methods:** `transferGala()`, `transferToken()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const gala = await sdk.transferGala({ recipientAddress: 'eth|1234567890123456789012345678901234567890', amount: '1' }); const token = await sdk.transferToken({ to: 'eth|1234567890123456789012345678901234567890', tokenId: 'GALA|Unit|none|none', amount: '1' }); console.log(gala.transactionId, token.transactionId); ``` **MCP Tool Equivalents:** - `gala_launchpad_transfer_gala` - `gala_launchpad_transfer_token` **Pitfalls:** v7 token writes return direct chain results; confirm with a balance read when business logic needs verification. **Related Topics:** `balances`, `locks`, `wallet-connect` ## Locks **Key concept:** Lock, unlock, and burn are native token writes in v7. Burn is irreversible and all three require a signer. **When to use:** Use for vesting/escrow workflows or an intentional supply reduction. **Covers methods:** `lockTokens()`, `unlockTokens()`, `burnTokens()`, `fetchLockedBalance()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const locked = await sdk.lockTokens({ tokens: [{ tokenName: 'anime', amount: '100' }] }); await sdk.unlockTokens({ tokens: [{ tokenName: 'anime', amount: '25' }] }); const balance = await sdk.fetchLockedBalance({ tokenName: 'anime', address: sdk.getAddress() }); console.log(locked, balance); // Only call after explicit confirmation: await sdk.burnTokens({ tokens: [{ tokenName: 'anime', amount: '1' }] }); ``` **MCP Tool Equivalents:** - `gala_launchpad_lock_tokens` - `gala_launchpad_unlock_tokens` - `gala_launchpad_burn_tokens` - `gala_launchpad_fetch_locked_tokens` **Pitfalls:** Burn cannot be undone; v7 does not use the old DEX service or EIP-712 DEX write path here. **Related Topics:** `balances`, `transfers`, `error-handling` ## Dex Trading **Key concept:** The DEX is gswap-sdk: build a GSwap client with the same key (launchpad-sdk has none). Quote with gSwap.quoting, submit with gSwap.swaps, and wait for queued confirmation. **When to use:** Use for graduated tokens and standard GalaChain assets. **Covers methods:** `gSwap.quoting.quoteExactInput()`, `gSwap.quoting.quoteExactOutput()`, `gSwap.swaps.swap()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; import { GSwap } from '@gala-chain/gswap-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(process.env.WALLET_PRIVATE_KEY!), walletAddress: sdk.getAddress() }); const quote = await gSwap.quoting.quoteExactInput('GALA|Unit|none|none', 'GUSDC|Unit|none|none', '100'); const submission = await gSwap.swaps.swap('GALA|Unit|none|none', 'GUSDC|Unit|none|none', quote.fee, { exactIn: '100', amountOutMinimum: quote.amountOut }); const trade = await submission.confirm(); console.log(trade); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_swap_quote_exact_input` - `gala_launchpad_get_swap_quote_exact_output` - `gala_launchpad_execute_swap` - `gala_launchpad_get_swap_result` **Pitfalls:** A returned submission is not proof of execution until confirm() resolves. **Related Topics:** `queued-swap-recovery`, `dex-pools`, `liquidity-positions` ## Error Handling **Key concept:** Read typed errors and transaction state, and use getBundlerTransactionResult() when a Launchpad submission needs a result lookup. **When to use:** Use around every write boundary and in retry/recovery code. **Covers methods:** `getBundlerTransactionResult()`, `getConfig()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); try { console.log(await sdk.getBundlerTransactionResult('bundle-id')); } catch (error) { console.error('SDK operation failed:', error); } ``` **MCP Tool Equivalents:** - `gala_launchpad_get_bundler_transaction_result` - `gala_launchpad_get_config` **Pitfalls:** Do not retry an unknown queued DEX write by submitting a second swap; use unique-key recovery. **Related Topics:** `queued-swap-recovery`, `buy-tokens`, `dex-trading` ## Installation **Key concept:** createLaunchpadSDK() is the supported entry point; environment selection is explicit and defaults can be inspected with getConfig(). **When to use:** Use as the first setup step in Node.js, browser, or MCP integrations. **Covers methods:** `getVersion()`, `getConfig()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); console.log('SDK version:', sdk.getVersion()); console.log('Environment:', sdk.getConfig().environment); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_version` - `gala_launchpad_get_config` **Pitfalls:** Use env: 'prod' or env: 'stage'; old uppercase and QA1 environment names are not v7 values. **Related Topics:** `configuration`, `wallet-connect` ## Local Calculations **Key concept:** Bonding-curve amount calculations have local and external variants; local is fast while external reads backend state. **When to use:** Use local calculations for responsive UI and external calculations when fresh state matters. **Covers methods:** `calculateBuyAmountLocal()`, `calculateSellAmountLocal()`, `calculateBuyAmountExternal()`, `calculateSellAmountExternal()`, `calculateInitialBuyAmount()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const localBuy = await sdk.calculateBuyAmountLocal({ tokenName: 'anime', amount: '10', type: 'native' }); const externalSell = await sdk.calculateSellAmountExternal({ tokenName: 'anime', amount: '10', type: 'exact' }); const initial = await sdk.calculateInitialBuyAmount('10'); console.log(localBuy, externalSell, initial); ``` **MCP Tool Equivalents:** - `gala_launchpad_calculate_buy_amount_local` - `gala_launchpad_calculate_sell_amount_external` - `gala_launchpad_calculate_initial_buy` **Pitfalls:** Local results depend on cached pool metadata and are not transaction confirmation. **Related Topics:** `buy-tokens`, `sell-tokens`, `fetch-pools` ## Price History **Key concept:** Price series are gswap-sdk's market reads (launchpad-sdk resolves a launchpad token name to its class key); the MCP tools page them. **When to use:** Use for charts, return calculations, and historical market analysis. **Covers methods:** `resolveTokenClassKey()`, `gSwap.market.getPriceSeries()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; import { GSwap } from '@gala-chain/gswap-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk: price series are the swap backend's const key = await sdk.resolveTokenClassKey('anime'); const series = await gSwap.market.getPriceSeries(key, '1W'); console.log(series.currentPrice, series.prices.length); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_price_history` - `gala_launchpad_fetch_all_price_history` **Pitfalls:** Use the current market price-series API; removed legacy graph and badge routes are not substitutes. **Related Topics:** `spot-prices-smart-routing`, `trading-analytics`, `fetch-pools` ## Spot Prices Smart Routing **Key concept:** fetchTokenPrice() prices a launchpad token by name (bonding curve, or the swap backend once graduated); any token by class key, GALA included, is gswap-sdk's gSwap.market.getPrice(). **When to use:** Use when a price display may receive either a Launchpad name or DEX identifier. **Covers methods:** `fetchTokenPrice()`, `gSwap.market.getPrice()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; import { GSwap } from '@gala-chain/gswap-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk: the DEX price of a token by class key, GALA included const launchpadPrice = await sdk.fetchTokenPrice({ tokenName: 'anime' }); const galaPrice = await gSwap.market.getPrice('GALA|Unit|none|none'); console.log(launchpadPrice, galaPrice?.price); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_token_spot_price` - `gala_launchpad_fetch_gala_spot_price` **Pitfalls:** Do not construct a DEX token key from a token name; resolve the canonical key first. **Related Topics:** `token-identification`, `price-history`, `dex-token-discovery` ## Profile Management **Key concept:** Profile reads and writes are flat SDK methods; managed-token lookup is a separate creator-dashboard read. **When to use:** Use for account pages and token-owner management views. **Covers methods:** `fetchProfile()`, `updateProfile()`, `uploadProfileImage()`, `getManagedTokens()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const profile = await sdk.fetchProfile(); await sdk.updateProfile({ fullName: 'Example creator' }); const managed = await sdk.getManagedTokens(); console.log(profile, managed); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_profile` - `gala_launchpad_update_profile` - `gala_launchpad_upload_profile_image` - `gala_launchpad_get_managed_tokens` **Pitfalls:** Profile image upload accepts its own DTO; do not confuse it with token image upload. **Related Topics:** `balances`, `token-creation`, `multi-wallet` ## Liquidity Positions **Key concept:** GSwap positions are gswap-sdk's gSwap.positions. Reads are signer-free; writes return queued submissions. **When to use:** Use for concentrated-liquidity portfolio screens and LP maintenance. **Covers methods:** `gSwap.positions.getUserPositions()`, `gSwap.positions.addLiquidityByTicks()`, `gSwap.positions.removeLiquidity()`, `gSwap.positions.collectPositionFees()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; import { GSwap } from '@gala-chain/gswap-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(process.env.WALLET_PRIVATE_KEY!), walletAddress: sdk.getAddress() }); const positions = await gSwap.positions.getUserPositions(sdk.getAddress()); console.log(positions); // Writes use the position DTO and return a queued SubmittedTransaction. // const added = await gSwap.positions.addLiquidityByTicks({ token0: 'GALA|Unit|none|none', token1: 'GUSDC|Unit|none|none', fee: 3000, tickLower: -60, tickUpper: 60, amount0Desired: '10', amount1Desired: '1' }); // await added.confirm(); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_user_liquidity_positions` - `gala_launchpad_add_liquidity_by_ticks` - `gala_launchpad_remove_liquidity` - `gala_launchpad_collect_position_fees` **Pitfalls:** LP operations require full DEX token identifiers; old flat DEX methods are gone. **Related Topics:** `dex-trading`, `dex-pools`, `queued-swap-recovery` ## Advanced Dex Analysis **Key concept:** GSwap quoting replaces legacy composite-pool and exact-amount helpers while preserving exact-input and exact-output workflows. **When to use:** Use for route analysis, price impact, and trade previews. **Covers methods:** `gSwap.quoting.quoteExactInput()`, `gSwap.quoting.quoteExactOutput()` ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk; quotes need no signer const exactIn = await gSwap.quoting.quoteExactInput('GALA|Unit|none|none', 'GUSDC|Unit|none|none', '100'); const exactOut = await gSwap.quoting.quoteExactOutput('GALA|Unit|none|none', 'GUSDC|Unit|none|none', '10'); console.log(exactIn, exactOut); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_swap_quote_exact_input` - `gala_launchpad_get_swap_quote_exact_output` - `gala_launchpad_calculate_dex_pool_quote_local` - `gala_launchpad_calculate_dex_pool_quote_external` **Pitfalls:** A quote can become stale; apply minimum output or maximum input on the subsequent swap. **Related Topics:** `dex-trading`, `dex-pools`, `spot-prices-smart-routing` ## Trading Analytics **Key concept:** Trade queries and OHLCV volume data provide historical activity without requiring a signer. **When to use:** Use for market dashboards, rankings, and post-trade analysis. **Covers methods:** `fetchTrades()`, `fetchVolumeData()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const trades = await sdk.fetchTrades({ tokenName: 'anime', pageSize: 20 }); const volume = await sdk.fetchVolumeData({ tokenName: 'anime', resolution: 3600 }); console.log(trades, volume); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_trades` - `gala_launchpad_fetch_volume_data` **Pitfalls:** Keep amount fields as strings and use API pagination instead of assuming one page is complete. **Related Topics:** `trade-history`, `recent-trades`, `price-history` ## Utilities And Helpers **Key concept:** Utility methods cover supply reads, cache inspection, cleanup, and transaction lookup. **When to use:** Use to build diagnostics, warm data, and controlled shutdown paths. **Covers methods:** `fetchTokenClassesWithSupply()`, `getBundlerTransactionResult()`, `getCacheInfo()`, `clearCache()`, `cleanup()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const supply = await sdk.fetchTokenClassesWithSupply([{ collection: 'GALA', category: 'Unit', type: 'none', additionalKey: 'none' }]); console.log(supply, sdk.getCacheInfo()); sdk.clearCache(); await sdk.cleanup(); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_token_classes_with_supply` - `gala_launchpad_get_cache_info` - `gala_launchpad_clear_cache` - `gala_launchpad_cleanup` **Pitfalls:** clearCache() is local maintenance; it does not invalidate chain state or cancel a transaction. **Related Topics:** `utilities-system`, `error-handling`, `balances` ## Utilities System **Key concept:** Configuration, version, URL, wallet state, and websocket lifecycle are available as flat SDK utilities. **When to use:** Use for diagnostics, health panels, and graceful shutdown. **Covers methods:** `getConfig()`, `getVersion()`, `getUrlByTokenName()`, `hasWallet()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); console.log(sdk.getConfig(), sdk.getVersion()); console.log(sdk.getUrlByTokenName('anime'), sdk.hasWallet()); console.log('WebSocket connected:', sdk.isWebSocketConnected()); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_config` - `gala_launchpad_get_version` - `gala_launchpad_get_url_by_token_name` - `gala_launchpad_has_wallet` **Pitfalls:** The SDK config environment is not inferred from arbitrary URLs; choose a supported env explicitly. **Related Topics:** `installation`, `wallet-connect`, `error-handling` ## Fetch All Dex Seasons **Key concept:** gSwap.leaderboard.getSeasons() returns the competition seasons (newest first), with Date bounds. **When to use:** Use to populate a season selector or historical rankings. **Covers methods:** `gSwap.leaderboard.getSeasons()` ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk console.log(await gSwap.leaderboard.getSeasons()); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_all_dex_seasons` **Pitfalls:** Do not assume the first season is current. **Related Topics:** `fetch-current-dex-season`, `fetch-dex-leaderboard-by-season-id` ## Fetch Current Dex Season **Key concept:** gSwap.leaderboard.getCurrentSeason() returns the running season (start and end inclusive) or null. **When to use:** Use before requesting current-season rankings. **Covers methods:** `gSwap.leaderboard.getCurrentSeason()` ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk const season = await gSwap.leaderboard.getCurrentSeason(); if (season) console.log(season.id); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_current_dex_season` **Pitfalls:** Handle null explicitly when no season is active. **Related Topics:** `fetch-all-dex-seasons`, `fetch-current-dex-leaderboard` ## Fetch Dex Leaderboard By Season Id **Key concept:** gSwap.leaderboard.getLeaderboard(seasonId) retrieves the rankings of a known season (the top 100 wallets). **When to use:** Use for historical season pages and audits. **Covers methods:** `gSwap.leaderboard.getLeaderboard()` ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk console.log(await gSwap.leaderboard.getLeaderboard(1)); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_dex_leaderboard_by_season_id` **Pitfalls:** Use an ID returned by gSwap.leaderboard.getSeasons(). **Related Topics:** `fetch-all-dex-seasons`, `fetch-current-dex-season` ## Fetch Current Dex Leaderboard **Key concept:** gSwap.leaderboard.getCurrentLeaderboard() is the convenience query for active rankings. **When to use:** Use for a current leaderboard widget. **Covers methods:** `gSwap.leaderboard.getCurrentLeaderboard()` ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk console.log(await gSwap.leaderboard.getCurrentLeaderboard()); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_current_dex_leaderboard` **Pitfalls:** Render null as an empty state. **Related Topics:** `fetch-current-dex-season`, `fetch-dex-leaderboard-by-season-id` ## Fetch Dex Aggregated Volume Summary **Key concept:** gSwap.market.getVolumeSummary() returns platform-level DEX metrics (TVL, 1d/7d/30d volume, trades; deltas as fractions). **When to use:** Use for overview dashboards and season reporting. **Covers methods:** `gSwap.market.getVolumeSummary()` ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk console.log(await gSwap.market.getVolumeSummary()); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_dex_aggregated_volume_summary` **Pitfalls:** Aggregate volume is not wallet- or token-filtered trade history. **Related Topics:** `trading-analytics`, `platform-stats` ## Fetch Dex Pools **Key concept:** GSwap pool discovery is gswap-sdk's gSwap.pools and replaces removed flat fetchDexPools methods. **When to use:** Use for DEX pool lists, pool metadata, and slot-0 price state. **Covers methods:** `gSwap.pools.getPools()`, `gSwap.pools.getPool()`, `gSwap.pools.getSlot0()` ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk; pool reads need no signer const pools = await gSwap.pools.getPools(); const pool = await gSwap.pools.getPool('GALA|Unit|none|none', 'GUSDC|Unit|none|none', 3000); const slot0 = await gSwap.pools.getSlot0('GALA|Unit|none|none', 'GUSDC|Unit|none|none', 3000); console.log(pools, pool, slot0); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_dex_pools` - `gala_launchpad_fetch_all_dex_pools` - `gala_launchpad_get_swap_pool_info` - `gala_launchpad_get_swap_pool_price` **Pitfalls:** Use full token identifiers and a valid fee tier; DEX reads do not require a signer. **Related Topics:** `dex-token-discovery`, `dex-trading`, `advanced-dex-analysis` ## Event Subscriptions **Key concept:** Launchpad stream subscriptions and typed callbacks provide supported realtime updates; DEX state is read through GSwap. **When to use:** Use for live token pages, stream status, and event-driven UI. **Covers methods:** `subscribeToStream()`, `onLaunchpadTokenCreation()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); await sdk.connectStreamWebSocket(); const subscription = await sdk.subscribeToStream('anime', { onStreamStatus: (status) => console.log(status), onChatMessage: (message) => console.log(message) }); console.log(subscription); ``` **MCP Tool Equivalents:** - `gala_launchpad_connect_stream_websocket` - `gala_launchpad_subscribe_to_stream` - `gala_launchpad_on_launchpad_token_creation` **Pitfalls:** Always retain and invoke the cleanup function supplied by the subscription workflow. **Related Topics:** `streaming`, `stream-chat`, `token-status` ## Mcp To Sdk Mapping **Key concept:** MCP names are snake_case transport names; direct SDK calls use flat LaunchpadSDK methods, and the DEX tools use a gswap-sdk GSwap client (gSwap.quoting, gSwap.swaps, ...). **When to use:** Use when migrating an MCP workflow into application code. **Covers methods:** `buy()`, `calculateBuyAmount()`, `fetchPools()`, `gSwap.swaps.swap()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); // gala_launchpad_calculate_buy_amount -> sdk.calculateBuyAmount() // gala_launchpad_buy -> sdk.buy() // gala_launchpad_fetch_pools -> sdk.fetchPools() console.log(await sdk.calculateBuyAmount({ tokenName: 'anime', amount: '10', type: 'native' })); ``` **MCP Tool Equivalents:** - `gala_launchpad_explain_sdk_usage` - `gala_launchpad_calculate_buy_amount` - `gala_launchpad_buy` - `gala_launchpad_fetch_pools` **Pitfalls:** Do not copy an MCP tool name into JavaScript; remove the gala_launchpad_ prefix and convert snake_case. **Related Topics:** `installation`, `dex-trading`, `buy-tokens` ## Bridge Operations **Key concept:** Bridge fee, transfer, status, external balance, and bridgeability methods cover GalaChain, Ethereum, and Solana. **When to use:** Use when moving a supported asset between GalaChain and an external network. **Covers methods:** `estimateBridgeFee()`, `bridgeOut()`, `bridgeIn()`, `getBridgeStatus()`, `fetchEthereumWalletAllBalances()`, `fetchSolanaWalletAllBalances()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const fee = await sdk.estimateBridgeFee({ tokenId: 'GALA|Unit|none|none', destinationChain: 'Ethereum' }); const balances = await sdk.fetchEthereumWalletAllBalances('0x1234567890123456789012345678901234567890'); console.log(fee, balances); ``` **MCP Tool Equivalents:** - `gala_launchpad_estimate_bridge_fee` - `gala_launchpad_bridge_out` - `gala_launchpad_bridge_in` - `gala_launchpad_get_bridge_status` - `gala_launchpad_fetch_ethereum_wallet_all_balances` - `gala_launchpad_fetch_solana_wallet_all_balances` **Pitfalls:** Bridge DTOs and destination networks are chain-specific; do not reuse a Solana address as an Ethereum recipient. **Related Topics:** `wrap-unwrap-operations`, `dex-token-discovery`, `error-handling` ## Dex Token Discovery **Key concept:** The GSwap symbol registry is gswap-sdk's gSwap.symbols.list(), replacing removed flat available-token methods. **When to use:** Use before constructing a quote, swap, or position request. **Covers methods:** `gSwap.symbols.list()` ```typescript import { GSwap } from '@gala-chain/gswap-sdk'; const gSwap = new GSwap({ env: 'stage' }); // gswap-sdk const symbols = await gSwap.symbols.list(); console.log(symbols.find((entry) => entry.symbol === 'GALA')); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_available_dex_tokens` - `gala_launchpad_fetch_all_available_dex_tokens` **Pitfalls:** Use canonical registry metadata; do not invent a TokenClassKey from a display symbol. **Related Topics:** `token-identification`, `dex-pools`, `dex-trading` ## Wrap Unwrap Operations **Key concept:** Cross-channel wrap and unwrap remain flat LaunchpadSDK methods backed by GalaConnect. **When to use:** Use when an asset has a supported wrapped counterpart and a signer is configured. **Covers methods:** `fetchWrappableTokens()`, `getWrapCounterpart()`, `estimateWrapFee()`, `wrapToken()`, `unwrapToken()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const tokens = await sdk.fetchWrappableTokens({ limit: 50 }); const MUSIC = '$MUSIC|Unit|none|none'; // token ids are class keys: a bare symbol is refused const counterpart = await sdk.getWrapCounterpart(MUSIC); const fee = await sdk.estimateWrapFee(MUSIC, '1'); const wrapped = await sdk.wrapToken({ tokenId: MUSIC, amount: '1' }); // throws a GalaSDKError unless completed console.log(tokens, counterpart, fee, wrapped.transactionId); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_wrappable_tokens` - `gala_launchpad_get_wrap_counterpart` - `gala_launchpad_estimate_wrap_fee` - `gala_launchpad_wrap_token` - `gala_launchpad_unwrap_token` **Pitfalls:** Check isTokenWrappable() and the current counterpart before writing. **Related Topics:** `bridge-operations`, `dex-token-discovery` ## Referral System **Key concept:** Referral URL, paginated referrals, complete lists, and summaries expose the creator referral program. **When to use:** Use for referral links, attribution dashboards, and reward summaries. **Covers methods:** `fetchReferralUrl()`, `fetchReferrals()`, `fetchAllReferrals()`, `fetchReferralsSummary()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const url = await sdk.fetchReferralUrl(); const page = await sdk.fetchReferrals({ page: 1, limit: 20 }); console.log(url, page, await sdk.fetchReferralsSummary()); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_referral_url` - `gala_launchpad_fetch_referrals` - `gala_launchpad_fetch_all_referrals` - `gala_launchpad_fetch_referrals_summary` **Pitfalls:** Use the returned referral URL rather than manually concatenating addresses. **Related Topics:** `profile-management`, `wallet-connect` ## Session Auth **Key concept:** JWT session methods support login, refresh, logout, inspection, and access-token retrieval. **When to use:** Use for authenticated API sessions independent of wallet-signature operations. **Covers methods:** `login()`, `getSession()`, `ensureValidToken()`, `refreshToken()`, `logout()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); await sdk.login(); console.log(await sdk.getSession(), await sdk.ensureValidToken()); await sdk.logout({ allDevices: false }); ``` **MCP Tool Equivalents:** - `gala_launchpad_login` - `gala_launchpad_get_session` - `gala_launchpad_ensure_valid_token` - `gala_launchpad_refresh_token` - `gala_launchpad_logout` **Pitfalls:** Keep access tokens out of logs and refresh before expiry. **Related Topics:** `wallet-connect`, `profile-management`, `api-key-management` ## Streaming **Key concept:** Streaming methods cover lifecycle, credentials, recordings, simulcasts, global status, roles, and access checks. **When to use:** Use for creator Studio and platform moderation workflows. **Covers methods:** `startStream()`, `stopStream()`, `getStreamRecordings()`, `getSimulcastTargets()`, `getGlobalStreamingStatus()`, `getStreamRole()`, `getTokenAccess()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const access = await sdk.getTokenAccess({ tokenName: 'anime' }); if (access.permissions.length > 0) console.log(await sdk.getStreamCredentials('anime'), await sdk.getSimulcastTargets('anime')); console.log(await sdk.getGlobalStreamingStatus()); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_token_access` - `gala_launchpad_get_global_streaming_status` - `gala_launchpad_get_stream_recordings` - `gala_launchpad_get_simulcast_targets` **Pitfalls:** Check role and token access before owner/admin operations. **Related Topics:** `stream-chat`, `event-subscriptions`, `moderator-invites` ## Stream Chat **Key concept:** Stream chat uses websocket lifecycle plus send, reaction, typing, per-token controls, and slow-mode methods. **When to use:** Use for live chat clients and creator moderation controls. **Covers methods:** `connectStreamWebSocket()`, `subscribeToStream()`, `sendStreamChatViaWebSocket()`, `sendStreamReaction()`, `disableChat()`, `enableChat()`, `setSlowMode()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); await sdk.connectStreamWebSocket(); await sdk.subscribeToStream('anime'); await sdk.sendStreamChatViaWebSocket('anime', 'Hello from the SDK'); await sdk.sendStreamReaction('anime', '🔥'); await sdk.setSlowMode('anime', 30); sdk.disconnectStreamWebSocket(); ``` **MCP Tool Equivalents:** - `gala_launchpad_connect_stream_websocket` - `gala_launchpad_subscribe_to_stream` - `gala_launchpad_send_stream_chat_via_web_socket` - `gala_launchpad_send_stream_reaction` - `gala_launchpad_set_chat_enabled` - `gala_launchpad_set_slow_mode` **Pitfalls:** Global chat enable/disable was removed; use per-token controls and current websocket APIs. **Related Topics:** `streaming`, `chat-messages`, `content-reactions` ## Ban Management **Key concept:** Ban methods create, remove, list, inspect, and enumerate active users for a token. **When to use:** Use for owner or moderator chat and content moderation. **Covers methods:** `createBan()`, `removeBan()`, `listBans()`, `getBanStatus()`, `getActiveUsers()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const result = await sdk.createBan({ tokenName: 'anime', userAddress: 'eth|1234567890123456789012345678901234567890', reason: 'Spam', durationSeconds: 3600 }); console.log(await sdk.getBanStatus({ tokenName: 'anime', userAddress: result.ban.userAddress })); ``` **MCP Tool Equivalents:** - `gala_launchpad_create_ban` - `gala_launchpad_remove_ban` - `gala_launchpad_list_bans` - `gala_launchpad_get_ban_status` - `gala_launchpad_get_active_users` **Pitfalls:** Ban permissions depend on owner, JWT, or API-key role. **Related Topics:** `content-flag-management`, `content-reactions`, `api-key-management` ## Api Key Management **Key concept:** API-key methods provide role-scoped machine access. **When to use:** Use for backend moderation or automation, never directly in a browser. **Covers methods:** `createApiKey()`, `listApiKeys()`, `getApiKey()`, `updateApiKey()`, `revokeApiKey()`, `getApiKeyRoles()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const created = await sdk.createApiKey({ role: 'MODERATOR', description: 'Chat moderation bot' }); console.log(created, await sdk.listApiKeys()); // Revoke when decommissioned: await sdk.revokeApiKey(created.id); ``` **MCP Tool Equivalents:** - `gala_launchpad_create_api_key` - `gala_launchpad_list_api_keys` - `gala_launchpad_get_api_key` - `gala_launchpad_update_api_key` - `gala_launchpad_revoke_api_key` - `gala_launchpad_get_api_key_roles` **Pitfalls:** Store a returned secret once in a secret manager. **Related Topics:** `session-auth`, `ban-management`, `moderator-invites` ## Moderator Invites **Key concept:** Moderator methods create, claim, list, inspect, update, and revoke token-scoped delegation. **When to use:** Use when a token owner grants limited Studio or moderation access. **Covers methods:** `createModeratorInvite()`, `claimModeratorInvite()`, `getModeratedTokens()`, `listModeratorInvites()`, `revokeModeratorInvite()`, `getModeratorInviteByCode()`, `updateModeratorInviteRole()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const invite = await sdk.createModeratorInvite({ tokenName: 'anime', role: 'MODERATOR', description: 'Community helper' }); console.log(invite, await sdk.listModeratorInvites({ tokenName: 'anime' })); ``` **MCP Tool Equivalents:** - `gala_launchpad_create_moderator_invite` - `gala_launchpad_claim_moderator_invite` - `gala_launchpad_list_moderator_invites` - `gala_launchpad_update_moderator_invite_role` - `gala_launchpad_revoke_moderator_invite` - `gala_launchpad_get_moderator_invite` **Pitfalls:** Invite codes are bearer credentials; send them only through a trusted channel. **Related Topics:** `api-key-management`, `overseer-invites`, `streaming` ## Overseer Invites **Key concept:** Overseer workflows provide platform-wide invites, claims, status, summaries, and statistics. **When to use:** Use only in a protected platform administration service. **Covers methods:** `createOverseerInvite()`, `listOverseerInvites()`, `claimOverseerInvite()`, `listOverseers()`, `getOverseerSummary()`, `getUserStats()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const invite = await sdk.createOverseerInvite({ description: 'Platform support', expiresAt: '2027-01-01T00:00:00Z' }); console.log(invite, await sdk.getOverseerSummary(), await sdk.getUserStats()); ``` **MCP Tool Equivalents:** - `gala_launchpad_create_overseer_invite` - `gala_launchpad_list_overseer_invites` - `gala_launchpad_claim_overseer_invite` - `gala_launchpad_list_overseers` - `gala_launchpad_get_overseer_summary` - `gala_launchpad_get_user_stats` **Pitfalls:** Overseer methods are high privilege; audit every call. **Related Topics:** `ban-management`, `global-bans`, `restricted-names` ## Content Flag Management **Key concept:** Flags can be created, listed, dismissed, and actioned; comments have a dedicated topic. **When to use:** Use for moderation queues and policy enforcement. **Covers methods:** `createFlag()`, `listFlags()`, `listGlobalFlags()`, `dismissFlag()`, `actionFlag()` ```typescript import { ContentType, createLaunchpadSDK, FlagReason, FlagStatus } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const created = await sdk.createFlag({ tokenName: 'anime', contentType: ContentType.CHAT_MESSAGE, contentId: 'message-id', reportedUserAddress: 'eth|1234567890123456789012345678901234567890', reason: FlagReason.SPAM }); console.log(created, await sdk.listFlags({ tokenName: 'anime', status: FlagStatus.PENDING })); // A moderator can action it: await sdk.actionFlag({ flagId: created.flag.id, action: 'DELETE_CONTENT' }); ``` **MCP Tool Equivalents:** - `gala_launchpad_create_flag` - `gala_launchpad_list_flags` - `gala_launchpad_list_global_flags` - `gala_launchpad_dismiss_flag` - `gala_launchpad_action_flag` **Pitfalls:** Use the action DTO accepted by the server and retain the flag ID. **Related Topics:** `comments`, `ban-management`, `ai-moderation` ## Content Reactions **Key concept:** Content reactions distinguish generic content from chat-message and comment helpers. **When to use:** Use for emoji reactions in social feeds and live chat. **Covers methods:** `addContentReaction()`, `removeContentReaction()`, `addReactionToChatMessage()`, `removeReactionFromChatMessage()`, `addReactionToComment()`, `removeReactionFromComment()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); await sdk.addReactionToChatMessage({ messageId: 'chat-message-id', reactionType: 'fire' }); await sdk.addReactionToComment({ messageId: 'comment-id', reactionType: 'heart' }); await sdk.removeReactionFromComment({ messageId: 'comment-id', reactionType: 'heart' }); ``` **MCP Tool Equivalents:** - `gala_launchpad_add_content_reaction` - `gala_launchpad_remove_content_reaction` - `gala_launchpad_add_reaction_to_chat_message` - `gala_launchpad_remove_reaction_from_chat_message` - `gala_launchpad_add_reaction_to_comment` - `gala_launchpad_remove_reaction_from_comment` **Pitfalls:** Use the type-specific helper when the backend needs to resolve a message or comment. **Related Topics:** `comments`, `chat-messages`, `stream-chat` ## Trade History **Key concept:** getTrades() supports filters and pagination for historical trades. **When to use:** Use for account history, token activity, and audit views. **Covers methods:** `getTrades()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const result = await sdk.getTrades({ tokenName: 'anime', txnType: 'BUY', pageSize: 50 }); console.log(result.trades, result.pageInfo); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_trades` **Pitfalls:** Use pageInfo to continue pagination and keep amounts as strings. **Related Topics:** `recent-trades`, `trading-analytics`, `holders` ## Token Ban Management **Key concept:** Overseer-only token-ban methods hide or restore tokens and expose current state. **When to use:** Use in platform safety administration. **Covers methods:** `banToken()`, `unbanToken()`, `listTokenBans()`, `getTokenBan()`, `isTokenBanned()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); console.log(await sdk.isTokenBanned({ tokenName: 'anime' })); console.log(await sdk.listTokenBans({ pageSize: 20 })); ``` **MCP Tool Equivalents:** - `gala_launchpad_ban_token` - `gala_launchpad_unban_token` - `gala_launchpad_list_token_bans` - `gala_launchpad_get_token_ban` - `gala_launchpad_is_token_banned` **Pitfalls:** Token bans are platform-wide moderation actions; require explicit authorization. **Related Topics:** `overseer-invites`, `restricted-names`, `content-flag-management` ## Nft Collection Management **Key concept:** NFT collection, token-class, fee, mint, and balance methods remain flat SDK operations. **When to use:** Use for collection administration and NFT portfolio flows. **Covers methods:** `getNftCollectionClaimFee()`, `getNftTokenClassCreateFee()`, `estimateNftMintFee()`, `estimateNftOperationFees()`, `isNftCollectionAvailable()`, `claimNftCollection()`, `fetchNftCollections()`, `createNftTokenClass()`, `fetchNftTokenClasses()`, `mintNft()`, `fetchNftBalances()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); console.log(await sdk.isNftCollectionAvailable('ExampleCollection')); console.log(await sdk.getNftCollectionClaimFee(), await sdk.fetchNftCollections(sdk.getAddress())); ``` **MCP Tool Equivalents:** - `gala_launchpad_check_nft_collection_available` - `gala_launchpad_get_nft_collection_claim_fee` - `gala_launchpad_fetch_nft_collections` - `gala_launchpad_fetch_nft_balances` **Pitfalls:** Validate availability before writes and treat mint operations as wallet-authorized. **Related Topics:** `wallet-connect`, `balances`, `error-handling` ## Token Identification **Key concept:** Launchpad methods use simple token names; GSwap methods use registered symbols or full TokenClassKeys. **When to use:** Use before crossing from bonding-curve reads into DEX quotes or swaps. **Covers methods:** `fetchPools()`, `isTokenGraduated()`, `resolveTokenClassKey()`, `fetchTokenPrice()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const graduated = await sdk.isTokenGraduated('anime'); const tokenClassKey = await sdk.resolveTokenClassKey('anime'); console.log(graduated, tokenClassKey, await sdk.fetchTokenPrice({ tokenName: 'anime' })); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_pools` - `gala_launchpad_is_token_graduated` - `gala_launchpad_resolve_token_class_key` - `gala_launchpad_fetch_token_spot_price` **Pitfalls:** Never hand-build a TokenClassKey. **Related Topics:** `graduation-detection`, `dex-token-discovery`, `dex-trading` ## Graduation Detection **Key concept:** Check the explicit graduation flag and refresh pool metadata before selecting a trading surface. **When to use:** Use at the boundary between bonding curve and DEX systems. **Covers methods:** `isTokenGraduated()`, `fetchPools()`, `onLaunchpadTokenCreation()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); const graduated = await sdk.isTokenGraduated('anime'); const pools = await sdk.fetchPools({ tokenName: 'anime', pageSize: 1 }); if (graduated) console.log('Trade it with a gswap-sdk GSwap client and the canonical key from pool data', pools); ``` **MCP Tool Equivalents:** - `gala_launchpad_is_token_graduated` - `gala_launchpad_fetch_pools` - `gala_launchpad_on_launchpad_token_creation` **Pitfalls:** A DEX pool watch (gSwap.pools.watchNewPools) is not a replacement for a status read. **Related Topics:** `token-status`, `token-identification`, `pool-graduation` ## Ai Moderation **Key concept:** Overseer-only AI methods manage settings, trigger analysis, read results, and inspect status. **When to use:** Use in a protected moderation service before automated action. **Covers methods:** `getAIModerationSettings()`, `updateAIModerationSettings()`, `getAIModeration()`, `triggerAIModeration()`, `getAIModerationStatus()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); console.log(await sdk.getAIModerationSettings(), await sdk.getAIModerationStatus()); // Trigger only after policy review: await sdk.triggerAIModeration({ contentId: 'message-id', contentType: 'CHAT' }); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_ai_moderation_settings` - `gala_launchpad_update_ai_moderation_settings` - `gala_launchpad_get_ai_moderation_result` - `gala_launchpad_trigger_ai_moderation` - `gala_launchpad_get_ai_moderation_status` **Pitfalls:** AI output is a signal, not authorization to delete or ban without policy. **Related Topics:** `content-flag-management`, `ban-management`, `overseer-invites` ## Weekly Challenge **Key concept:** Weekly challenge methods expose current rankings and token history snapshots. **When to use:** Use for competition pages and historical token performance. **Covers methods:** `getWeeklyChallengeLeaderboard()`, `getTokenWeeklyHistory()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); console.log(await sdk.getWeeklyChallengeLeaderboard({ limit: 20 })); console.log(await sdk.getTokenWeeklyHistory({ vaultAddress: 'client|example-token' })); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_weekly_challenge_leaderboard` - `gala_launchpad_get_token_weekly_history` **Pitfalls:** Label snapshot timestamps rather than presenting them as live price data. **Related Topics:** `trading-analytics`, `platform-stats` ## Platform Stats **Key concept:** getPlatformStats() returns platform-wide trading and token metrics. **When to use:** Use for a public platform dashboard or operations summary. **Covers methods:** `getPlatformStats()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); console.log(await sdk.getPlatformStats()); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_platform_stats` **Pitfalls:** Platform totals differ from an individual token’s trades or holder distribution. **Related Topics:** `trading-analytics`, `fetch-dex-aggregated-volume-summary` ## Restricted Names **Key concept:** Overseer-only methods read and update the platform blocked-name list. **When to use:** Use in controlled platform administration tooling. **Covers methods:** `getRestrictedNames()`, `updateRestrictedNames()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); console.log(await sdk.getRestrictedNames()); // Update only after approval: await sdk.updateRestrictedNames({ names: ['reserved-name'] }); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_restricted_names` - `gala_launchpad_update_restricted_names` **Pitfalls:** Treat the list as policy configuration and validate the complete replacement payload. **Related Topics:** `overseer-invites`, `token-creation`, `token-ban-management` ## Websocket Admin **Key concept:** Admin event emitters and connection inspection support platform realtime operations. **When to use:** Use only from an authenticated overseer/admin service. **Covers methods:** `emitTradeExecuted()`, `emitStreamStatus()`, `emitChatMessage()`, `getConnectedClients()`, `isUserOnline()`, `getOnlineUsers()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); console.log(await sdk.getConnectedClients({}), await sdk.isUserOnline('eth|1234567890123456789012345678901234567890')); // Emit only a validated payload: await sdk.emitChatStatus('anime', { enabled: true }); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_connected_clients` - `gala_launchpad_is_user_online` - `gala_launchpad_get_online_users` - `gala_launchpad_emit_chat_status` - `gala_launchpad_emit_websocket_event` **Pitfalls:** Emitters change live state seen by clients; validate payloads and permissions. **Related Topics:** `event-subscriptions`, `overseer-invites`, `stream-chat` ## Oembed **Key concept:** OEmbed methods produce metadata for home, pool, and profile pages. **When to use:** Use when a social platform requests a preview document. **Covers methods:** `getHomeOEmbed()`, `getPoolOEmbed()`, `getProfileOEmbed()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); console.log(await sdk.getHomeOEmbed()); console.log(await sdk.getPoolOEmbed({ tokenName: 'anime' })); console.log(await sdk.getProfileOEmbed({ address: 'eth|1234567890123456789012345678901234567890' })); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_home_oembed` - `gala_launchpad_get_pool_oembed` - `gala_launchpad_get_profile_oembed` **Pitfalls:** Use SDK DTOs so canonical URLs and metadata stay aligned with the frontend. **Related Topics:** `token-details`, `profile-management` ## Messages **Key concept:** The unified messages API handles CHAT and COMMENT records with one CRUD and pinning surface. **When to use:** Use when an application wants one content abstraction. **Covers methods:** `fetchMessages()`, `createMessage()`, `updateMessage()`, `deleteMessage()`, `getPinnedMessage()`, `pinMessage()`, `unpinMessage()`, `getMessageStats()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const messages = await sdk.fetchMessages({ tokenName: 'anime', type: 'CHAT_MESSAGE', pageSize: 20 }); console.log(messages, await sdk.getMessageStats()); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_messages` - `gala_launchpad_create_message` - `gala_launchpad_update_message` - `gala_launchpad_delete_message` - `gala_launchpad_get_pinned_message` - `gala_launchpad_pin_message` - `gala_launchpad_unpin_message` - `gala_launchpad_get_message_stats` **Pitfalls:** Use the message type explicitly and retain returned IDs. **Related Topics:** `comments`, `chat-messages`, `content-reactions` ## Holders **Key concept:** Holder helpers provide top holders, counts, rank, balance ranges, and history. **When to use:** Use for whale analysis and holder dashboards. **Covers methods:** `fetchTokenDistribution()`, `getTopHolders()`, `getHolderCount()`, `getHolderRank()`, `getHoldersByBalance()`, `getHolderHistory()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); console.log(await sdk.getTopHolders('anime', 10)); console.log(await sdk.getHolderCount('anime')); console.log(await sdk.getHolderRank('anime', 'eth|1234567890123456789012345678901234567890')); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_top_holders` - `gala_launchpad_get_holder_count` - `gala_launchpad_get_holder_rank` - `gala_launchpad_get_holders_by_balance` - `gala_launchpad_get_holder_history` **Pitfalls:** Holder results are point-in-time data; label timestamps and do not treat them as identity verification. **Related Topics:** `token-distribution`, `trade-history`, `balances` ## Trading Quotes **Key concept:** Fee, sale-detail, trade-quote, and premint-quote methods provide planning data for Launchpad workflows. **When to use:** Use before presenting cost estimates or constructing a bonding-curve operation. **Covers methods:** `fetchLaunchpadFee()`, `fetchSaleDetails()`, `getTradeQuote()`, `getPremintQuote()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); console.log(await sdk.fetchLaunchpadFee(), await sdk.fetchSaleDetails('anime')); console.log(await sdk.getTradeQuote({ tokenName: 'anime', amount: '10', type: 'NATIVE', method: 'IN' })); ``` **MCP Tool Equivalents:** - `gala_launchpad_fetch_launchpad_fee` - `gala_launchpad_fetch_sale_details` - `gala_launchpad_get_trade_quote` - `gala_launchpad_get_premint_quote` **Pitfalls:** A quote is informational until the matching write submits with slippage protection. **Related Topics:** `buy-tokens`, `sell-tokens`, `local-calculations` ## Global Feed Subscription **Key concept:** The supported stream subscription API delivers realtime events; MCP also exposes a global-feed reference. **When to use:** Use for a platform activity feed or realtime monitoring client. **Covers methods:** `subscribeToStream()`, `connectStreamWebSocket()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); await sdk.connectStreamWebSocket(); const subscription = await sdk.subscribeToStream('anime', { onStreamStatus: (event) => console.log(event), onReaction: (event) => console.log(event) }); console.log(subscription); ``` **MCP Tool Equivalents:** - `gala_launchpad_global_feed_reference` - `gala_launchpad_monitor_global_feed_events_reference` - `gala_launchpad_connect_stream_websocket` - `gala_launchpad_subscribe_to_stream` **Pitfalls:** Filter by token and event type; do not assume every event is a trade. **Related Topics:** `event-subscriptions`, `streaming`, `recent-trades` ## Events Tracking **Key concept:** The SDK exposes a batching event service at sdk.events; track events and flush them at lifecycle boundaries. **When to use:** Use for product analytics and durable client-event delivery when events are configured. **Covers methods:** `getConfig()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); sdk.events.track('token_viewed', { tokenName: 'anime' }); console.log(sdk.events.getStats()); await sdk.events.flush(); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_config` - `gala_launchpad_explain_sdk_usage` **Pitfalls:** Events are telemetry, not chain transactions; flush before shutdown and keep secrets out of payloads. **Related Topics:** `utilities-and-helpers`, `global-feed-subscription` ## Global Bans **Key concept:** Global ban methods apply platform-wide moderation and are separate from token-scoped bans. **When to use:** Use only in platform moderation administration. **Covers methods:** `getBanStats()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const ban = await sdk.createGlobalBan({ userAddress: 'eth|1234567890123456789012345678901234567890', reason: 'Repeated abuse' }); console.log(await sdk.getGlobalBan({ userAddress: ban.ban.userAddress })); ``` **MCP Tool Equivalents:** - `gala_launchpad_global_feed_status_reference` - `gala_launchpad_get_overseer_summary` **Pitfalls:** Global bans affect all communities; require a higher authorization threshold. **Related Topics:** `ban-management`, `overseer-invites`, `token-ban-management` ## Recent Trades **Key concept:** getRecentTrades() is a compact activity query; use getTrades() for filters and deep paging. **When to use:** Use for token pages and lightweight feeds. **Covers methods:** `getRecentTrades()`, `getTrades()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage' }); console.log(await sdk.getRecentTrades('anime', 10)); console.log(await sdk.getTrades({ tokenName: 'anime', txnType: 'BUY', pageSize: 20 })); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_recent_trades` - `gala_launchpad_get_trades` **Pitfalls:** Recent results are a convenience window, not a complete historical export. **Related Topics:** `trade-history`, `trading-analytics`, `global-feed-subscription` ## Queued Swap Recovery **Key concept:** GSwap swap() returns a durable queued submission; confirmSwap(uniqueKey) resolves a persisted outcome without resubmitting. **When to use:** Use after timeout, process restart, or unknown submission outcome. **Covers methods:** `gSwap.swaps.swap()`, `gSwap.swaps.confirmSwap()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; import { PrivateKeySigner } from '@gala-chain/gala-core-sdk'; import { GSwap } from '@gala-chain/gswap-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const gSwap = new GSwap({ env: 'stage', signer: new PrivateKeySigner(process.env.WALLET_PRIVATE_KEY!), walletAddress: sdk.getAddress() }); const quote = await gSwap.quoting.quoteExactInput('GALA|Unit|none|none', 'GUSDC|Unit|none|none', '10'); const submission = await gSwap.swaps.swap('GALA|Unit|none|none', 'GUSDC|Unit|none|none', quote.fee, { exactIn: '10', amountOutMinimum: quote.amountOut }); try { console.log(await submission.confirm()); } catch (error) { console.log('Recover with:', submission.uniqueKey, error); console.log(await gSwap.swaps.confirmSwap(submission.uniqueKey)); } ``` **MCP Tool Equivalents:** - `gala_launchpad_execute_swap` - `gala_launchpad_get_swap_result` **Pitfalls:** Recovery must use the original uniqueKey; never submit a second swap just because confirmation timed out. **Related Topics:** `dex-trading`, `error-handling` ## Comments **Key concept:** Comments have a dedicated CRUD surface with token-scoped reads and explicit IDs. **When to use:** Use for community discussion attached to a Launchpad pool. **Covers methods:** `getComments()`, `createComment()`, `updateComment()`, `deleteComment()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const comments = await sdk.getComments({ tokenName: 'anime', pageSize: 20 }); const created = await sdk.createComment({ tokenName: 'anime', content: 'Great project!' }); await sdk.updateComment(String(created.comment.id), { content: 'Updated comment' }); console.log(comments, created); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_comments` - `gala_launchpad_create_comment` - `gala_launchpad_update_comment` - `gala_launchpad_delete_comment` **Pitfalls:** Keep the comment ID; content IDs are not interchangeable across chat and comments. **Related Topics:** `content-reactions`, `content-flag-management`, `chat-messages` ## Chat Messages **Key concept:** Chat-message CRUD is separate from the websocket transport used for live delivery. **When to use:** Use for history views, moderation tools, and edits/deletes. **Covers methods:** `getChatMessages()`, `sendChatMessage()`, `updateChatMessage()`, `deleteChatMessage()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); const history = await sdk.getChatMessages({ tokenName: 'anime', pageSize: 20 }); const sent = await sdk.sendChatMessage({ tokenName: 'anime', content: 'Hello chat' }); await sdk.updateChatMessage(sent.message.messageId, { content: 'Edited hello' }); console.log(history, sent); ``` **MCP Tool Equivalents:** - `gala_launchpad_get_chat_messages` - `gala_launchpad_send_chat_message` - `gala_launchpad_update_chat_message` - `gala_launchpad_delete_chat_message` **Pitfalls:** Use websocket methods for live delivery and durable CRUD methods for persistence. **Related Topics:** `stream-chat`, `comments`, `content-reactions` ## Notifications **Key concept:** Push-token registration, notification preferences, and client flags support device-aware applications. **When to use:** Use during device onboarding and settings changes. **Covers methods:** `registerPushToken()`, `unregisterPushToken()`, `fetchNotificationPreferences()`, `updateNotificationPreferences()`, `fetchClientFlags()` ```typescript import { createLaunchpadSDK } from '@gala-chain/launchpad-sdk'; const sdk = createLaunchpadSDK({ env: 'stage', wallet: process.env.WALLET_PRIVATE_KEY! }); await sdk.registerPushToken({ token: 'device-token', platform: 'ios' }); console.log(await sdk.fetchNotificationPreferences(), await sdk.fetchClientFlags()); // Remove on sign-out: await sdk.unregisterPushToken('device-token'); ``` **MCP Tool Equivalents:** - `gala_launchpad_register_push_token` - `gala_launchpad_unregister_push_token` - `gala_launchpad_fetch_notification_preferences` - `gala_launchpad_update_notification_preferences` - `gala_launchpad_fetch_client_flags` **Pitfalls:** Treat device tokens as identifiers and unregister them on sign-out. **Related Topics:** `session-auth`, `profile-management`, `utilities-system` --- # Classification: gala-mcp-server toolsets (final) Groups are the shipped ones (`src/manifests/tools-manifest.ts`, generated from the toolset modules and checked in CI by `validate:manifest`); "defined at" is the final location. "Old reach" is what the pre-split handler reached, from the import-graph scan of the old tree (every handler took a LaunchpadSDK; DEX tools reached GSwap through `dexClientOf(sdk)`), with the old file:line as evidence. A group is what the operation needs: a launchpad `tokenName` input means launchpad. Enforced by `src/__tests__/boundary.test.ts` (import graph) and `src/toolsets/__tests__/module-graph.test.ts` (what a run loads). ## Counts | group | tools | prompts | SDKs | | --- | --- | --- | --- | | core | 47 | 30 | gala-core-sdk | | launchpad | 242 | 213 | gala-core-sdk + launchpad-sdk | | gswap | 32 | 34 | gala-core-sdk + gswap-sdk | | composite | 3 | 9 | launchpad-sdk + gswap-sdk (enabled with both) | | total | 324 | 286 | | Tools per selection (composite follows launchpad + gswap): `core` 47, `launchpad` 242, `gswap` 32, `core,launchpad` 289, `core,gswap` 79, `launchpad,gswap` 277, `default (all)` 324. Since 1.0.0-rc.1 `gala_launchpad_fetch_gala_balance` and `gala_launchpad_transfer_gala` are `core` tools (in 1.0.0-rc.0 they were `launchpad`'s, as straddles: they ran on launchpad-sdk's gateway services). They run on gala-core-sdk alone, with the answers and error texts they had (`src/toolsets/core/gala/__tests__/parity.test.ts`), except three deliberate 1.0.0-rc.2 differences pinned there against the old tools: a `client|` recipient is accepted, an HTTP failure adds the gateway's message, and an amount that is no number is reported as such. ## STRADDLE / composite tools (every one) - `gala_launchpad_burn_tokens` -> launchpad: STRADDLE (brief: core): each token is a tokenId OR a launchpad tokenName (launchpad name resolution) - `gala_launchpad_fetch_all_price_history` -> composite: launchpad name resolution / launchpad price AND the gswap market - `gala_launchpad_fetch_available_balance` -> launchpad: STRADDLE (brief: gateway balances = core): tokenName resolved by the launchpad backend - `gala_launchpad_fetch_locked_tokens` -> launchpad: STRADDLE (brief: gateway balances = core): tokenName resolved by the launchpad backend - `gala_launchpad_fetch_price_history` -> composite: launchpad name resolution / launchpad price AND the gswap market - `gala_launchpad_fetch_token_balance` -> launchpad: STRADDLE (brief: gateway balances = core): routes launchpad tokens to the launchpad backend - `gala_launchpad_fetch_token_spot_price` -> composite: launchpad name resolution / launchpad price AND the gswap market - `gala_launchpad_lock_tokens` -> launchpad: STRADDLE (brief: core): each token is a tokenId OR a launchpad tokenName (launchpad name resolution in GalaChainLockService) - `gala_launchpad_transfer_token` -> launchpad: STRADDLE (brief: core): the input names a launchpad token (tokenName), resolved by the launchpad backend (LaunchpadSDK.resolveTokenClassKey) - `gala_launchpad_unlock_tokens` -> launchpad: STRADDLE (brief: core): each token is a tokenId OR a launchpad tokenName (launchpad name resolution) ## Tools (324) | tool | group | defined at | old reach (evidence) | reason | | --- | --- | --- | --- | --- | | `gala_launchpad_fetch_pools` | launchpad | src/toolsets/launchpad/tools/pools/fetchPools.ts:12 | LaunchpadSDK.fetchPools (src/tools/pools/fetchPools.ts:56 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_all_pools` | launchpad | src/toolsets/launchpad/tools/pools/fetchAllPools.ts:13 | LaunchpadSDK.fetchAllPools (src/tools/pools/fetchAllPools.ts:55 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_pool_details` | launchpad | src/toolsets/launchpad/tools/pools/fetchPoolDetails.ts:10 | LaunchpadSDK.fetchPoolDetails (src/tools/pools/fetchPoolDetails.ts:19 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_pool_details_for_calculation` | launchpad | src/toolsets/launchpad/tools/pools/fetchPoolDetailsForCalculation.ts:9 | LaunchpadSDK.fetchPoolDetailsForCalculation (src/tools/pools/fetchPoolDetailsForCalculation.ts:21); @gala-chain/launchpad-sdk::fetchPoolDetailsForCalculation (src/tools/pools/fetchPoolDetailsForCalculation.ts:21) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_token_details` | launchpad | src/toolsets/launchpad/tools/pools/fetchTokenDetails.ts:14 | LaunchpadSDK.fetchTokenDetails (src/tools/pools/fetchTokenDetails.ts:45 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_token_distribution` | launchpad | src/toolsets/launchpad/tools/pools/index.ts:38 | LaunchpadSDK.fetchTokenDistribution (src/tools/pools/index.ts:49); @gala-chain/launchpad-sdk::fetchTokenDistribution (src/tools/pools/index.ts:49) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_user_holder_context` | launchpad | src/toolsets/launchpad/tools/pools/index.ts:45 | LaunchpadSDK.fetchUserHolderContext (src/tools/pools/index.ts:73 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_volume_data` | launchpad | src/toolsets/launchpad/tools/pools/index.ts:72 | LaunchpadSDK.fetchVolumeData (src/tools/pools/index.ts:105 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_token_spot_price` | composite | src/toolsets/composite/tools/prices/fetchTokenSpotPrice.ts:14 | LaunchpadSDK.fetchTokenDetails (src/utils/market-prices.ts:132); LaunchpadSDK.fetchTokenPrice (src/utils/market-prices.ts:191); GSwap (dexClientOf) (src/utils/market-prices.ts:162); GSwap market (src/utils/market-prices.ts:162); @gala-chain/gala-core-sdk::additionalKey (src/utils/market-prices.ts:123); @gala-chain/gala-core-sdk::category (src/utils/market-prices.ts:123); +12 more | launchpad name resolution / launchpad price AND the gswap market | | `gala_launchpad_fetch_gala_spot_price` | gswap | src/toolsets/gswap/tools/prices/fetchGalaSpotPrice.ts:8 | LaunchpadSDK.fetchTokenDetails (src/utils/market-prices.ts:132); GSwap (dexClientOf) (src/utils/market-prices.ts:162); GSwap market (src/utils/market-prices.ts:162); @gala-chain/gala-core-sdk::additionalKey (src/utils/market-prices.ts:123); @gala-chain/gala-core-sdk::category (src/utils/market-prices.ts:123); @gala-chain/gala-core-sdk::collection (src/utils/market-prices.ts:123); +9 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_launchpad_token_spot_price` | launchpad | src/toolsets/launchpad/tools/pools/index.ts:110 | LaunchpadSDK.fetchTokenPrice (src/tools/pools/index.ts:201 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_price_history` | composite | src/toolsets/composite/tools/prices/fetchPriceHistory.ts:17 | LaunchpadSDK.resolveTokenClassKey (src/utils/market-prices.ts:270); GSwap (dexClientOf) (src/utils/market-prices.ts:272); GSwap market (src/utils/market-prices.ts:272); @gala-chain/gala-core-sdk::additionalKey (src/utils/market-prices.ts:123); @gala-chain/gala-core-sdk::category (src/utils/market-prices.ts:123); @gala-chain/gala-core-sdk::collection (src/utils/market-prices.ts:123); +12 more | launchpad name resolution / launchpad price AND the gswap market | | `gala_launchpad_fetch_all_price_history` | composite | src/toolsets/composite/tools/prices/fetchAllPriceHistory.ts:17 | LaunchpadSDK.resolveTokenClassKey (src/utils/market-prices.ts:270); GSwap (dexClientOf) (src/utils/market-prices.ts:272); GSwap market (src/utils/market-prices.ts:272); @gala-chain/gala-core-sdk::additionalKey (src/utils/market-prices.ts:123); @gala-chain/gala-core-sdk::category (src/utils/market-prices.ts:123); @gala-chain/gala-core-sdk::collection (src/utils/market-prices.ts:123); +12 more | launchpad name resolution / launchpad price AND the gswap market | | `gala_launchpad_check_token_name` | launchpad | src/toolsets/launchpad/tools/pools/index.ts:133 | LaunchpadSDK.isTokenNameAvailable (src/tools/pools/index.ts:210); @gala-chain/launchpad-sdk::isTokenNameAvailable (src/tools/pools/index.ts:210) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_check_token_symbol` | launchpad | src/toolsets/launchpad/tools/pools/index.ts:146 | LaunchpadSDK.isTokenSymbolAvailable (src/tools/pools/index.ts:223); @gala-chain/launchpad-sdk::isTokenSymbolAvailable (src/tools/pools/index.ts:223) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_validate_token` | launchpad | src/toolsets/launchpad/tools/pools/validateToken.ts:11 | LaunchpadSDK.validateToken (src/tools/pools/validateToken.ts:36 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_resolve_vault_address` | launchpad | src/toolsets/launchpad/tools/pools/index.ts:159 | LaunchpadSDK.resolveVaultAddress (src/tools/pools/index.ts:238); @gala-chain/launchpad-sdk::resolveVaultAddress (src/tools/pools/index.ts:238) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_resolve_token_class_key` | launchpad | src/toolsets/launchpad/tools/pools/index.ts:171 | LaunchpadSDK.resolveTokenClassKey (src/tools/pools/index.ts:256); @gala-chain/launchpad-sdk::resolveTokenClassKey (src/tools/pools/index.ts:256) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_token_classes_with_supply` | launchpad | src/toolsets/launchpad/tools/pools/index.ts:190 | LaunchpadSDK.fetchTokenClassesWithSupply (src/tools/pools/index.ts:300 (dispatched by name)); @gala-chain/gala-core-sdk::additionalKey (src/tools/pools/index.ts:308); @gala-chain/gala-core-sdk::category (src/tools/pools/index.ts:306); @gala-chain/gala-core-sdk::collection (src/tools/pools/index.ts:305); @gala-chain/gala-core-sdk::maxSupply (src/tools/pools/index.ts:310); @gala-chain/gala-core-sdk::totalBurned (src/tools/pools/index.ts:311); +2 more | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_on_dex_pool_creation` | gswap | src/toolsets/gswap/tools/watchers/onDexPoolCreation.ts:9 | GSwap (dexClientOf) (src/tools/pools/onDexPoolCreation.ts:18); GSwap pools (src/tools/pools/onDexPoolCreation.ts:18); @gala-chain/gswap-sdk::fee (src/tools/pools/onDexPoolCreation.ts:24); @gala-chain/gswap-sdk::poolRef (src/tools/pools/onDexPoolCreation.ts:21); @gala-chain/gswap-sdk::pools (src/tools/pools/onDexPoolCreation.ts:18); @gala-chain/gswap-sdk::token0 (src/tools/pools/onDexPoolCreation.ts:22); +3 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_on_launchpad_token_creation` | launchpad | src/toolsets/launchpad/tools/pools/onLaunchpadTokenCreation.ts:8 | LaunchpadSDK.onLaunchpadTokenCreation (src/tools/pools/onLaunchpadTokenCreation.ts:10 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_check_pool_exists` | launchpad | src/toolsets/launchpad/tools/pools/checkPoolExists.ts:20 | LaunchpadSDK.checkPoolExists (src/tools/pools/checkPoolExists.ts:43 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_on_pool_updated` | launchpad | src/toolsets/launchpad/tools/pools/onPoolUpdated.ts:12 | LaunchpadSDK.watchPoolUpdated (src/tools/pools/onPoolUpdated.ts:27 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_pool_realtime_state` | launchpad | src/toolsets/launchpad/tools/pools/getPoolRealtimeState.ts:18 | LaunchpadSDK.getPoolRealtimeState (src/tools/pools/getPoolRealtimeState.ts:45 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_on_holder_count_changed` | launchpad | src/toolsets/launchpad/tools/pools/onHolderCountChanged.ts:12 | LaunchpadSDK.watchHolderCountUpdated (src/tools/pools/onHolderCountChanged.ts:27 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_token_config` | launchpad | src/toolsets/launchpad/tools/pools/updateTokenConfig.ts:29 | LaunchpadSDK.updateTokenConfig (src/tools/pools/updateTokenConfig.ts:101 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_calculate_buy_amount` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:52 | LaunchpadSDK.calculateBuyAmount (src/tools/trading/index.ts:73 (dispatched by name)); @gala-chain/launchpad-sdk::TRADING_TYPES (src/tools/trading/helpers/trading-schemas.ts:28) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_calculate_sell_amount` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:78 | LaunchpadSDK.calculateSellAmount (src/tools/trading/index.ts:99 (dispatched by name)); @gala-chain/launchpad-sdk::TRADING_TYPES (src/tools/trading/helpers/trading-schemas.ts:28) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_buy` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:108 | LaunchpadSDK.DEFAULT_MAX_ACCEPTABLE_REVERSE_BONDING_CURVE_FEE_SLIPPAGE_FACTOR (src/tools/trading/index.ts:539); LaunchpadSDK.buy (src/tools/trading/index.ts:121 (dispatched by name)); LaunchpadSDK.launchpad (src/tools/trading/index.ts:550); LaunchpadSDK.maxAcceptableReverseBondingCurveFeeSlippageFactor (src/tools/trading/helpers/arg-extractors.ts:79 (dispatched by name)); LaunchpadSDK.resolveVaultAddress (src/tools/trading/index.ts:518); LaunchpadSDK.slippageToleranceFactor (src/tools/trading/helpers/arg-extractors.ts:80 (dispatched by name)); +9 more | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_sell` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:126 | LaunchpadSDK.DEFAULT_MAX_ACCEPTABLE_REVERSE_BONDING_CURVE_FEE_SLIPPAGE_FACTOR (src/tools/trading/index.ts:539); LaunchpadSDK.launchpad (src/tools/trading/index.ts:550); LaunchpadSDK.maxAcceptableReverseBondingCurveFeeSlippageFactor (src/tools/trading/helpers/arg-extractors.ts:79 (dispatched by name)); LaunchpadSDK.resolveVaultAddress (src/tools/trading/index.ts:518); LaunchpadSDK.sell (src/tools/trading/index.ts:140 (dispatched by name)); LaunchpadSDK.slippageToleranceFactor (src/tools/trading/helpers/arg-extractors.ts:80 (dispatched by name)); +9 more | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_trades` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:149 | LaunchpadSDK.fetchTrades (src/tools/trading/index.ts:190 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_calculate_initial_buy` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:201 | LaunchpadSDK.calculateInitialBuyAmount (src/tools/trading/index.ts:213 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_bundler_transaction_result` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:218 | LaunchpadSDK.getBundlerTransactionResult (src/tools/trading/index.ts:238 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_calculate_buy_amount_for_graduation` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:247 | LaunchpadSDK.calculateBuyAmountForGraduation (src/tools/trading/index.ts:267 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_graduate_token` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:272 | LaunchpadSDK.graduateToken (src/tools/trading/index.ts:296 (dispatched by name)); LaunchpadSDK.maxAcceptableReverseBondingCurveFeeSlippageFactor (src/tools/trading/helpers/arg-extractors.ts:92 (dispatched by name)); LaunchpadSDK.slippageToleranceFactor (src/tools/trading/helpers/arg-extractors.ts:91 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_calculate_buy_amount_local` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:338 | LaunchpadSDK.calculateBuyAmountLocal (src/tools/trading/index.ts:346 (dispatched by name)); @gala-chain/launchpad-sdk::TRADING_TYPES (src/tools/trading/helpers/trading-schemas.ts:28) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_calculate_buy_amount_external` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:351 | LaunchpadSDK.calculateBuyAmountExternal (src/tools/trading/index.ts:359 (dispatched by name)); @gala-chain/launchpad-sdk::TRADING_TYPES (src/tools/trading/helpers/trading-schemas.ts:28) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_calculate_sell_amount_local` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:364 | LaunchpadSDK.calculateSellAmountLocal (src/tools/trading/index.ts:373 (dispatched by name)); @gala-chain/launchpad-sdk::TRADING_TYPES (src/tools/trading/helpers/trading-schemas.ts:28) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_calculate_sell_amount_external` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:378 | LaunchpadSDK.calculateSellAmountExternal (src/tools/trading/index.ts:386 (dispatched by name)); @gala-chain/launchpad-sdk::TRADING_TYPES (src/tools/trading/helpers/trading-schemas.ts:28) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_launchpad_fee` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:396 | LaunchpadSDK.fetchLaunchpadFee (src/tools/trading/index.ts:407 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_sale_details` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:412 | LaunchpadSDK.fetchSaleDetails (src/tools/trading/index.ts:431 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_trade_quote` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:436 | LaunchpadSDK.getTradeQuote (src/tools/trading/index.ts:468 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_premint_quote` | launchpad | src/toolsets/launchpad/tools/trading/index.ts:478 | LaunchpadSDK.getPremintQuote (src/tools/trading/index.ts:498 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_swap_quote_exact_input` | gswap | src/toolsets/gswap/tools/dex/index.ts:32 | GSwap (dexClientOf) (src/tools/dex/helpers.ts:168); GSwap quoting (src/tools/dex/helpers.ts:168); @gala-chain/gswap-sdk::amountIn (src/tools/dex/helpers.ts:174); @gala-chain/gswap-sdk::amountOut (src/tools/dex/helpers.ts:174); @gala-chain/gswap-sdk::priceImpact (src/tools/dex/helpers.ts:173); @gala-chain/gswap-sdk::quoteExactInput (src/tools/dex/helpers.ts:168); +2 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_swap_quote_exact_output` | gswap | src/toolsets/gswap/tools/dex/index.ts:39 | GSwap (dexClientOf) (src/tools/dex/helpers.ts:168); GSwap quoting (src/tools/dex/helpers.ts:168); @gala-chain/gswap-sdk::amountIn (src/tools/dex/helpers.ts:174); @gala-chain/gswap-sdk::amountOut (src/tools/dex/helpers.ts:174); @gala-chain/gswap-sdk::priceImpact (src/tools/dex/helpers.ts:173); @gala-chain/gswap-sdk::quoteExactInput (src/tools/dex/helpers.ts:168); +2 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_calculate_dex_pool_quote_local` | gswap | src/toolsets/gswap/tools/dex/index.ts:46 | GSwap (dexClientOf) (src/tools/dex/helpers.ts:203); GSwap quoting (src/tools/dex/helpers.ts:203); @gala-chain/gswap-sdk::priceImpact (src/tools/dex/helpers.ts:208); @gala-chain/gswap-sdk::quoteExactInput (src/tools/dex/helpers.ts:203); @gala-chain/gswap-sdk::quoteExactOutput (src/tools/dex/helpers.ts:202); @gala-chain/gswap-sdk::quoting (src/tools/dex/helpers.ts:203) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_calculate_dex_pool_quote_external` | gswap | src/toolsets/gswap/tools/dex/index.ts:51 | GSwap (dexClientOf) (src/tools/dex/helpers.ts:203); GSwap quoting (src/tools/dex/helpers.ts:203); @gala-chain/gswap-sdk::priceImpact (src/tools/dex/helpers.ts:208); @gala-chain/gswap-sdk::quoteExactInput (src/tools/dex/helpers.ts:203); @gala-chain/gswap-sdk::quoteExactOutput (src/tools/dex/helpers.ts:202); @gala-chain/gswap-sdk::quoting (src/tools/dex/helpers.ts:203) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_execute_swap` | gswap | src/toolsets/gswap/tools/dex/index.ts:56 | GSwap (dexClientOf) (src/tools/dex/index.ts:80); GSwap swaps (src/tools/dex/index.ts:80); @gala-chain/gswap-sdk::swap (src/tools/dex/index.ts:80); @gala-chain/gswap-sdk::swaps (src/tools/dex/index.ts:80); @gala-chain/gswap-sdk::uniqueKey (src/tools/dex/index.ts:90) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_swap_result` | gswap | src/toolsets/gswap/tools/dex/index.ts:104 | GSwap (dexClientOf) (src/tools/dex/index.ts:121); GSwap swaps (src/tools/dex/index.ts:121); @gala-chain/gswap-sdk::confirmSwap (src/tools/dex/index.ts:121); @gala-chain/gswap-sdk::swaps (src/tools/dex/index.ts:121) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_swap_user_assets` | gswap | src/toolsets/gswap/tools/dex/index.ts:169 | GSwap (dexClientOf) (src/tools/dex/index.ts:181); GSwap assets (src/tools/dex/index.ts:181); @gala-chain/gswap-sdk::assets (src/tools/dex/index.ts:181); @gala-chain/gswap-sdk::getUserAssets (src/tools/dex/index.ts:181); @gala-chain/gswap-sdk::tokens (src/tools/dex/index.ts:192) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_all_swap_user_assets` | gswap | src/toolsets/gswap/tools/dex/index.ts:197 | GSwap (dexClientOf) (src/tools/dex/index.ts:216); GSwap assets (src/tools/dex/index.ts:216); @gala-chain/gswap-sdk::assets (src/tools/dex/index.ts:216); @gala-chain/gswap-sdk::count (src/tools/dex/index.ts:213); @gala-chain/gswap-sdk::getUserAssets (src/tools/dex/index.ts:216); @gala-chain/gswap-sdk::tokens (src/tools/dex/index.ts:218) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_dex_pools` | gswap | src/toolsets/gswap/tools/dex-pools/index.ts:92 | GSwap (dexClientOf) (src/tools/dex-pools/index.ts:97); GSwap pools (src/tools/dex-pools/index.ts:97); @gala-chain/gswap-sdk::getPools (src/tools/dex-pools/index.ts:97); @gala-chain/gswap-sdk::pools (src/tools/dex-pools/index.ts:97) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_all_dex_pools` | gswap | src/toolsets/gswap/tools/dex-pools/index.ts:112 | GSwap (dexClientOf) (src/tools/dex-pools/index.ts:119); GSwap pools (src/tools/dex-pools/index.ts:119); @gala-chain/gswap-sdk::getPools (src/tools/dex-pools/index.ts:119); @gala-chain/gswap-sdk::pools (src/tools/dex-pools/index.ts:119) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_swap_pool_info` | gswap | src/toolsets/gswap/tools/dex-pools/index.ts:126 | GSwap (dexClientOf) (src/tools/dex-pools/index.ts:137); GSwap pools (src/tools/dex-pools/index.ts:137); @gala-chain/gswap-sdk::fee (src/tools/dex-pools/index.ts:146); @gala-chain/gswap-sdk::getPools (src/tools/dex-pools/index.ts:137); @gala-chain/gswap-sdk::pools (src/tools/dex-pools/index.ts:137); @gala-chain/gswap-sdk::token0 (src/tools/dex-pools/index.ts:140); +1 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_composite_pool_data` | gswap | src/toolsets/gswap/tools/dex-pools/index.ts:152 | GSwap (dexClientOf) (src/tools/dex-pools/index.ts:162); GSwap pools (src/tools/dex-pools/index.ts:162); @gala-chain/gswap-sdk::getCompositePool (src/tools/dex-pools/index.ts:162); @gala-chain/gswap-sdk::pools (src/tools/dex-pools/index.ts:162) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_swap_pool_price` | gswap | src/toolsets/gswap/tools/dex-pools/index.ts:167 | GSwap (dexClientOf) (src/tools/dex-pools/index.ts:177); GSwap pools (src/tools/dex-pools/index.ts:177); @gala-chain/gswap-sdk::getSlot0 (src/tools/dex-pools/index.ts:177); @gala-chain/gswap-sdk::pools (src/tools/dex-pools/index.ts:177) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_available_dex_tokens` | gswap | src/toolsets/gswap/tools/dex-pools/index.ts:182 | GSwap (dexClientOf) (src/tools/dex-pools/index.ts:192); GSwap symbols (src/tools/dex-pools/index.ts:192); @gala-chain/gswap-sdk::additionalKey (src/tools/dex/helpers.ts:122); @gala-chain/gswap-sdk::category (src/tools/dex/helpers.ts:122); @gala-chain/gswap-sdk::collection (src/tools/dex/helpers.ts:122); @gala-chain/gswap-sdk::decimals (src/tools/dex/helpers.ts:117); +4 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_all_available_dex_tokens` | gswap | src/toolsets/gswap/tools/dex-pools/index.ts:211 | GSwap (dexClientOf) (src/tools/dex-pools/index.ts:217); GSwap symbols (src/tools/dex-pools/index.ts:217); @gala-chain/gswap-sdk::additionalKey (src/tools/dex/helpers.ts:122); @gala-chain/gswap-sdk::category (src/tools/dex/helpers.ts:122); @gala-chain/gswap-sdk::collection (src/tools/dex/helpers.ts:122); @gala-chain/gswap-sdk::decimals (src/tools/dex/helpers.ts:117); +4 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_user_liquidity_positions` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:23 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:29); GSwap positions (src/tools/dex-liquidity/index.ts:29); @gala-chain/gswap-sdk::amount0 (src/tools/dex/helpers.ts:221); @gala-chain/gswap-sdk::amount1 (src/tools/dex/helpers.ts:222); @gala-chain/gswap-sdk::fee (src/tools/dex/helpers.ts:219); @gala-chain/gswap-sdk::fees0 (src/tools/dex/helpers.ts:227); +11 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_all_user_liquidity_positions` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:34 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:29); GSwap positions (src/tools/dex-liquidity/index.ts:29); @gala-chain/gswap-sdk::amount0 (src/tools/dex/helpers.ts:221); @gala-chain/gswap-sdk::amount1 (src/tools/dex/helpers.ts:222); @gala-chain/gswap-sdk::fee (src/tools/dex/helpers.ts:219); @gala-chain/gswap-sdk::fees0 (src/tools/dex/helpers.ts:227); +11 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_liquidity_position_by_id` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:41 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:171); GSwap positions (src/tools/dex-liquidity/index.ts:171); @gala-chain/gswap-sdk::amount0 (src/tools/dex/helpers.ts:221); @gala-chain/gswap-sdk::amount1 (src/tools/dex/helpers.ts:222); @gala-chain/gswap-sdk::fee (src/tools/dex/helpers.ts:219); @gala-chain/gswap-sdk::fees0 (src/tools/dex/helpers.ts:227); +11 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_get_liquidity_position` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:52 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:171); GSwap positions (src/tools/dex-liquidity/index.ts:171); @gala-chain/gswap-sdk::amount0 (src/tools/dex/helpers.ts:221); @gala-chain/gswap-sdk::amount1 (src/tools/dex/helpers.ts:222); @gala-chain/gswap-sdk::fee (src/tools/dex/helpers.ts:219); @gala-chain/gswap-sdk::fees0 (src/tools/dex/helpers.ts:227); +11 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_estimate_remove_liquidity` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:63 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:73); GSwap positions (src/tools/dex-liquidity/index.ts:73); @gala-chain/gswap-sdk::estimateRemoveLiquidity (src/tools/dex-liquidity/index.ts:73); @gala-chain/gswap-sdk::positions (src/tools/dex-liquidity/index.ts:73) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_add_liquidity_by_price` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:78 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:95); GSwap positions (src/tools/dex-liquidity/index.ts:95); @gala-chain/gswap-sdk::addLiquidityByPrice (src/tools/dex-liquidity/index.ts:95); @gala-chain/gswap-sdk::positions (src/tools/dex-liquidity/index.ts:95) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_add_liquidity_by_ticks` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:106 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:117); GSwap positions (src/tools/dex-liquidity/index.ts:117); @gala-chain/gswap-sdk::addLiquidityByTicks (src/tools/dex-liquidity/index.ts:117); @gala-chain/gswap-sdk::positions (src/tools/dex-liquidity/index.ts:117) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_remove_liquidity` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:122 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:132); GSwap positions (src/tools/dex-liquidity/index.ts:132); @gala-chain/gswap-sdk::positions (src/tools/dex-liquidity/index.ts:132); @gala-chain/gswap-sdk::removeLiquidity (src/tools/dex-liquidity/index.ts:132) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_swap_position_direct` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:141 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:171); GSwap positions (src/tools/dex-liquidity/index.ts:171); @gala-chain/gswap-sdk::amount0 (src/tools/dex/helpers.ts:221); @gala-chain/gswap-sdk::amount1 (src/tools/dex/helpers.ts:222); @gala-chain/gswap-sdk::fee (src/tools/dex/helpers.ts:219); @gala-chain/gswap-sdk::fees0 (src/tools/dex/helpers.ts:227); +11 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_collect_position_fees` | gswap | src/toolsets/gswap/tools/dex-liquidity/index.ts:152 | GSwap (dexClientOf) (src/tools/dex-liquidity/index.ts:162); GSwap positions (src/tools/dex-liquidity/index.ts:162); @gala-chain/gswap-sdk::collectPositionFees (src/tools/dex-liquidity/index.ts:162); @gala-chain/gswap-sdk::positions (src/tools/dex-liquidity/index.ts:162) | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_all_dex_seasons` | gswap | src/toolsets/gswap/tools/dex-analytics/index.ts:63 | GSwap (dexClientOf) (src/tools/dex-analytics/index.ts:68); GSwap leaderboard (src/tools/dex-analytics/index.ts:68); @gala-chain/gswap-sdk::end (src/tools/dex-analytics/index.ts:26); @gala-chain/gswap-sdk::getSeasons (src/tools/dex-analytics/index.ts:68); @gala-chain/gswap-sdk::id (src/tools/dex-analytics/index.ts:26); @gala-chain/gswap-sdk::leaderboard (src/tools/dex-analytics/index.ts:68); +3 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_current_dex_season` | gswap | src/toolsets/gswap/tools/dex-analytics/index.ts:78 | GSwap (dexClientOf) (src/tools/dex-analytics/index.ts:83); GSwap leaderboard (src/tools/dex-analytics/index.ts:83); @gala-chain/gswap-sdk::end (src/tools/dex-analytics/index.ts:26); @gala-chain/gswap-sdk::getCurrentSeason (src/tools/dex-analytics/index.ts:83); @gala-chain/gswap-sdk::id (src/tools/dex-analytics/index.ts:26); @gala-chain/gswap-sdk::leaderboard (src/tools/dex-analytics/index.ts:83); +3 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_dex_leaderboard_by_season_id` | gswap | src/toolsets/gswap/tools/dex-analytics/index.ts:94 | GSwap (dexClientOf) (src/tools/dex-analytics/index.ts:106); GSwap leaderboard (src/tools/dex-analytics/index.ts:106); @gala-chain/gswap-sdk::entries (src/tools/dex-analytics/index.ts:37); @gala-chain/gswap-sdk::getLeaderboard (src/tools/dex-analytics/index.ts:106); @gala-chain/gswap-sdk::leaderboard (src/tools/dex-analytics/index.ts:106); @gala-chain/gswap-sdk::seasonId (src/tools/dex-analytics/index.ts:36); +1 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_current_dex_leaderboard` | gswap | src/toolsets/gswap/tools/dex-analytics/index.ts:118 | GSwap (dexClientOf) (src/tools/dex-analytics/index.ts:123); GSwap leaderboard (src/tools/dex-analytics/index.ts:123); @gala-chain/gswap-sdk::entries (src/tools/dex-analytics/index.ts:37); @gala-chain/gswap-sdk::getCurrentLeaderboard (src/tools/dex-analytics/index.ts:123); @gala-chain/gswap-sdk::leaderboard (src/tools/dex-analytics/index.ts:123); @gala-chain/gswap-sdk::seasonId (src/tools/dex-analytics/index.ts:36); +1 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_dex_aggregated_volume_summary` | gswap | src/toolsets/gswap/tools/dex-analytics/index.ts:138 | GSwap (dexClientOf) (src/tools/dex-analytics/index.ts:144); GSwap market (src/tools/dex-analytics/index.ts:144); @gala-chain/gswap-sdk::getVolumeSummary (src/tools/dex-analytics/index.ts:144); @gala-chain/gswap-sdk::market (src/tools/dex-analytics/index.ts:144); @gala-chain/gswap-sdk::volume1d (src/tools/dex-analytics/index.ts:44); @gala-chain/gswap-sdk::volume1dDelta (src/tools/dex-analytics/index.ts:45); +4 more | gswap-sdk client only (dexClientOf) | | `gala_launchpad_fetch_gala_balance` | core | src/toolsets/core/tools/gala/index.ts:27 | LaunchpadSDK.fetchGalaBalance (src/tools/balance/index.ts:50 (dispatched by name)) | gala-core-sdk gateway read (GatewayReads.fetchTokenBalance); moved from launchpad in 1.0.0-rc.1 with its answers and error texts unchanged (core/gala/__tests__/parity.test.ts); since rc.2 an HTTP failure adds the gateway's message | | `gala_launchpad_fetch_token_balance` | launchpad | src/toolsets/launchpad/tools/balance/index.ts:31 | LaunchpadSDK.fetchTokenBalance (src/tools/balance/index.ts:65 (dispatched by name)) | STRADDLE (brief: gateway balances = core): routes launchpad tokens to the launchpad backend | | `gala_launchpad_fetch_locked_tokens` | launchpad | src/toolsets/launchpad/tools/balance/index.ts:46 | LaunchpadSDK.fetchLockedBalance (src/tools/balance/index.ts:88); LaunchpadSDK.resolveTokenClassKey (src/tools/balance/helpers/format-balance.ts:71); @gala-chain/launchpad-sdk::fetchLockedBalance (src/tools/balance/index.ts:88); @gala-chain/launchpad-sdk::resolveTokenClassKey (src/tools/balance/helpers/format-balance.ts:71) | STRADDLE (brief: gateway balances = core): tokenName resolved by the launchpad backend | | `gala_launchpad_fetch_tokens_held` | launchpad | src/toolsets/launchpad/tools/balance/index.ts:76 | LaunchpadSDK.fetchTokensHeld (src/tools/balance/index.ts:107 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_tokens_created` | launchpad | src/toolsets/launchpad/tools/balance/index.ts:89 | LaunchpadSDK.fetchTokensCreated (src/tools/balance/index.ts:120 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_profile` | launchpad | src/toolsets/launchpad/tools/balance/index.ts:101 | LaunchpadSDK.fetchProfile (src/tools/balance/index.ts:136 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_profile` | launchpad | src/toolsets/launchpad/tools/balance/index.ts:117 | LaunchpadSDK.updateProfile (src/tools/balance/index.ts:157 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_available_balance` | launchpad | src/toolsets/launchpad/tools/balance/index.ts:174 | LaunchpadSDK.fetchAvailableBalance (src/tools/balance/index.ts:209 (dispatched by name)) | STRADDLE (brief: gateway balances = core): tokenName resolved by the launchpad backend | | `gala_launchpad_get_managed_tokens` | launchpad | src/toolsets/launchpad/tools/balance/index.ts:148 | LaunchpadSDK.getManagedTokens (src/tools/balance/index.ts:190 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_referral_url` | launchpad | src/toolsets/launchpad/tools/referrals/index.ts:20 | LaunchpadSDK.fetchReferralUrl (src/tools/referrals/index.ts:27 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_referrals` | launchpad | src/toolsets/launchpad/tools/referrals/index.ts:32 | LaunchpadSDK.fetchReferrals (src/tools/referrals/index.ts:56 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_all_referrals` | launchpad | src/toolsets/launchpad/tools/referrals/index.ts:67 | LaunchpadSDK.fetchAllReferrals (src/tools/referrals/index.ts:89 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_referrals_summary` | launchpad | src/toolsets/launchpad/tools/referrals/index.ts:98 | LaunchpadSDK.fetchReferralsSummary (src/tools/referrals/index.ts:110 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_launch_token` | launchpad | src/toolsets/launchpad/tools/creation/index.ts:52 | LaunchpadSDK.launchpad (src/tools/creation/index.ts:131); @gala-chain/launchpad-sdk::createSale (src/tools/creation/index.ts:131); @gala-chain/launchpad-sdk::launchpad (src/tools/creation/index.ts:131) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_upload_token_image` | launchpad | src/toolsets/launchpad/tools/creation/index.ts:138 | LaunchpadSDK.uploadTokenImage (src/tools/creation/index.ts:171); @gala-chain/launchpad-sdk::privateKey (src/tools/creation/index.ts:168); @gala-chain/launchpad-sdk::uploadTokenImage (src/tools/creation/index.ts:171) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_upload_profile_image` | launchpad | src/toolsets/launchpad/tools/creation/index.ts:178 | LaunchpadSDK.uploadProfileImage (src/tools/creation/index.ts:210); @gala-chain/launchpad-sdk::address (src/tools/creation/index.ts:204); @gala-chain/launchpad-sdk::privateKey (src/tools/creation/index.ts:207); @gala-chain/launchpad-sdk::uploadProfileImage (src/tools/creation/index.ts:210) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_launch_token_fee` | launchpad | src/toolsets/launchpad/tools/creation/index.ts:227 | LaunchpadSDK.fetchLaunchTokenFee (src/tools/creation/index.ts:229); @gala-chain/launchpad-sdk::fetchLaunchTokenFee (src/tools/creation/index.ts:229) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_nft_collection_claim_fee` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:37 | LaunchpadSDK.getNftCollectionClaimFee (src/tools/nft/index.ts:38); @gala-chain/launchpad-sdk::getNftCollectionClaimFee (src/tools/nft/index.ts:38) | launchpad-sdk NftCollectionService | | `gala_launchpad_get_nft_token_class_create_fee` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:45 | LaunchpadSDK.getNftTokenClassCreateFee (src/tools/nft/index.ts:46); @gala-chain/launchpad-sdk::getNftTokenClassCreateFee (src/tools/nft/index.ts:46) | launchpad-sdk NftCollectionService | | `gala_launchpad_estimate_nft_mint_fee` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:61 | LaunchpadSDK.estimateNftMintFee (src/tools/nft/index.ts:90); @gala-chain/launchpad-sdk::estimateNftMintFee (src/tools/nft/index.ts:90) | launchpad-sdk NftCollectionService | | `gala_launchpad_estimate_nft_operation_fees` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:109 | LaunchpadSDK.estimateNftOperationFees (src/tools/nft/index.ts:125); @gala-chain/launchpad-sdk::estimateNftOperationFees (src/tools/nft/index.ts:125) | launchpad-sdk NftCollectionService | | `gala_launchpad_check_nft_collection_available` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:140 | LaunchpadSDK.isNftCollectionAvailable (src/tools/nft/index.ts:150); @gala-chain/launchpad-sdk::isNftCollectionAvailable (src/tools/nft/index.ts:150) | launchpad-sdk NftCollectionService | | `gala_launchpad_claim_nft_collection` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:158 | LaunchpadSDK.claimNftCollection (src/tools/nft/index.ts:168); @gala-chain/launchpad-sdk::claimNftCollection (src/tools/nft/index.ts:168) | launchpad-sdk NftCollectionService | | `gala_launchpad_fetch_nft_collections` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:176 | LaunchpadSDK.fetchNftCollections (src/tools/nft/index.ts:186); @gala-chain/launchpad-sdk::fetchNftCollections (src/tools/nft/index.ts:186) | launchpad-sdk NftCollectionService | | `gala_launchpad_create_nft_token_class` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:198 | LaunchpadSDK.createNftTokenClass (src/tools/nft/index.ts:242); @gala-chain/launchpad-sdk::createNftTokenClass (src/tools/nft/index.ts:242) | launchpad-sdk NftCollectionService | | `gala_launchpad_fetch_nft_token_classes` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:250 | LaunchpadSDK.fetchNftTokenClasses (src/tools/nft/index.ts:268); @gala-chain/launchpad-sdk::fetchNftTokenClasses (src/tools/nft/index.ts:268) | launchpad-sdk NftCollectionService | | `gala_launchpad_mint_nft` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:280 | LaunchpadSDK.mintNft (src/tools/nft/index.ts:304); @gala-chain/launchpad-sdk::mintNft (src/tools/nft/index.ts:304) | launchpad-sdk NftCollectionService | | `gala_launchpad_fetch_nft_balances` | launchpad | src/toolsets/launchpad/tools/nft/index.ts:312 | LaunchpadSDK.fetchNftBalances (src/tools/nft/index.ts:326); @gala-chain/launchpad-sdk::fetchNftBalances (src/tools/nft/index.ts:326) | launchpad-sdk NftCollectionService | | `gala_launchpad_transfer_gala` | core | src/toolsets/core/tools/gala/index.ts:58 | LaunchpadSDK.resolveTokenClassKey (src/tools/handler-factories.ts:1469); LaunchpadSDK.transferGala (src/tools/handler-factories.ts:1447 (dispatched by name)); LaunchpadSDK.transferToken (src/tools/handler-factories.ts:1470); @gala-chain/launchpad-sdk::resolveTokenClassKey (src/tools/handler-factories.ts:1469); @gala-chain/launchpad-sdk::transferToken (src/tools/handler-factories.ts:1470) | gala-core-sdk gateway write (GatewayWrites.transferGala); moved from launchpad in 1.0.0-rc.1 with its answers and error texts unchanged (core/gala/__tests__/parity.test.ts); since rc.2 a client| recipient is accepted, an HTTP failure adds the gateway's message and an amount that is no number says so | | `gala_launchpad_transfer_token` | launchpad | src/toolsets/launchpad/tools/transfers/index.ts:20 | LaunchpadSDK.resolveTokenClassKey (src/tools/handler-factories.ts:1469); LaunchpadSDK.transferGala (src/tools/handler-factories.ts:1447 (dispatched by name)); LaunchpadSDK.transferToken (src/tools/handler-factories.ts:1470); @gala-chain/launchpad-sdk::resolveTokenClassKey (src/tools/handler-factories.ts:1469); @gala-chain/launchpad-sdk::transferToken (src/tools/handler-factories.ts:1470) | STRADDLE (brief: core): the input names a launchpad token (tokenName), resolved by the launchpad backend (LaunchpadSDK.resolveTokenClassKey) | | `gala_launchpad_lock_tokens` | launchpad | src/toolsets/launchpad/tools/locks/index.ts:22 | LaunchpadSDK.lockTokens (src/tools/locks/index.ts:40 (dispatched by name)) | STRADDLE (brief: core): each token is a tokenId OR a launchpad tokenName (launchpad name resolution in GalaChainLockService) | | `gala_launchpad_unlock_tokens` | launchpad | src/toolsets/launchpad/tools/locks/index.ts:45 | LaunchpadSDK.unlockTokens (src/tools/locks/index.ts:64 (dispatched by name)) | STRADDLE (brief: core): each token is a tokenId OR a launchpad tokenName (launchpad name resolution) | | `gala_launchpad_burn_tokens` | launchpad | src/toolsets/launchpad/tools/burns/index.ts:16 | LaunchpadSDK.burnTokens (src/tools/burns/index.ts:35 (dispatched by name)) | STRADDLE (brief: core): each token is a tokenId OR a launchpad tokenName (launchpad name resolution) | | `gala_launchpad_create_wallet` | core | src/toolsets/core/tools/wallet/createWallet.ts:10 | @gala-chain/gala-core-sdk::address (src/tools/utils/createWallet.ts:15); @gala-chain/gala-core-sdk::createWallet (src/tools/utils/createWallet.ts:13); @gala-chain/gala-core-sdk::galaAddress (src/tools/utils/createWallet.ts:17); @gala-chain/gala-core-sdk::privateKey (src/tools/utils/createWallet.ts:16) | pure key/wallet function of gala-core-sdk | | `gala_launchpad_create_solana_wallet` | core | src/toolsets/core/tools/wallet/createSolanaWallet.ts:12 | @gala-chain/gala-core-sdk::address (src/tools/utils/createSolanaWallet.ts:15); @gala-chain/gala-core-sdk::createSolanaWallet (src/tools/utils/createSolanaWallet.ts:13); @gala-chain/gala-core-sdk::privateKey (src/tools/utils/createSolanaWallet.ts:17); @gala-chain/gala-core-sdk::publicKey (src/tools/utils/createSolanaWallet.ts:16) | pure key/wallet function of gala-core-sdk | | `gala_launchpad_get_address` | core | src/toolsets/core/tools/wallet/getAddress.ts:10 | LaunchpadSDK.getAddress (src/tools/utils/getAddress.ts:10); @gala-chain/launchpad-sdk::getAddress (src/tools/utils/getAddress.ts:10) | session state (wallet identity, environment, versions), served by the server session on gala-core-sdk | | `gala_launchpad_get_ethereum_address` | core | src/toolsets/core/tools/wallet/getEthereumAddress.ts:9 | LaunchpadSDK.getEthereumAddress (src/tools/utils/getEthereumAddress.ts:10); @gala-chain/launchpad-sdk::getEthereumAddress (src/tools/utils/getEthereumAddress.ts:10) | session state (wallet identity, environment, versions), served by the server session on gala-core-sdk | | `gala_launchpad_get_public_key_from_private_key` | core | src/toolsets/core/tools/wallet/getPublicKeyFromPrivateKey.ts:13 | @gala-chain/gala-core-sdk::compressedPublicKey (src/tools/utils/getPublicKeyFromPrivateKey.ts:35); @gala-chain/gala-core-sdk::getPublicKeyFromPrivateKey (src/tools/utils/getPublicKeyFromPrivateKey.ts:31); @gala-chain/gala-core-sdk::publicKey (src/tools/utils/getPublicKeyFromPrivateKey.ts:34) | pure key/wallet function of gala-core-sdk | | `gala_launchpad_get_ethereum_address_from_private_key` | core | src/toolsets/core/tools/wallet/getEthereumAddressFromPrivateKey.ts:13 | @gala-chain/gala-core-sdk::getEthereumAddressFromPrivateKey (src/tools/utils/getEthereumAddressFromPrivateKey.ts:31) | pure key/wallet function of gala-core-sdk | | `gala_launchpad_get_config` | launchpad | src/toolsets/launchpad/tools/utils/getConfig.ts:18 | LaunchpadSDK.getConfig (src/tools/utils/getConfig.ts:13); @gala-chain/launchpad-sdk::getConfig (src/tools/utils/getConfig.ts:13); server::param (src/tools/utils/getConfig.ts:14) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_url_by_token_name` | launchpad | src/toolsets/launchpad/tools/utils/getUrlByTokenName.ts:9 | LaunchpadSDK.getUrlByTokenName (src/tools/utils/getUrlByTokenName.ts:10); @gala-chain/launchpad-sdk::getUrlByTokenName (src/tools/utils/getUrlByTokenName.ts:10) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_explain_sdk_usage` | core | src/toolsets/core/tools/docs/explainSdkUsage.ts:407 | LaunchpadSDK.actionFlag (src/tools/utils/explainSdkUsage.ts:486 (dispatched by name)); LaunchpadSDK.addContentReaction (src/tools/utils/explainSdkUsage.ts:490 (dispatched by name)); LaunchpadSDK.addReactionToChatMessage (src/tools/utils/explainSdkUsage.ts:490 (dispatched by name)); LaunchpadSDK.addReactionToComment (src/tools/utils/explainSdkUsage.ts:490 (dispatched by name)); LaunchpadSDK.banToken (src/tools/utils/explainSdkUsage.ts:497 (dispatched by name)); LaunchpadSDK.bridgeIn (src/tools/utils/explainSdkUsage.ts:409 (dispatched by name)); +190 more | documentation tool; its topic enum narrows to the topics whose tools are registered | | `gala_launchpad_search_gala_docs` | core | src/toolsets/core/tools/docs/searchGalaDocs.ts:19 | none (unreleased; no earlier tool) | documentation tool: reads the docs site's index through the shared docs source (site, disk cache, bundled copy), needs no SDK | | `gala_launchpad_is_token_graduated` | launchpad | src/toolsets/launchpad/tools/utils/isTokenGraduated.ts:9 | LaunchpadSDK.isTokenGraduated (src/tools/utils/isTokenGraduated.ts:14); @gala-chain/launchpad-sdk::isTokenGraduated (src/tools/utils/isTokenGraduated.ts:14) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_cache_info` | launchpad | src/toolsets/launchpad/tools/utils/getCacheInfo.ts:15 | LaunchpadSDK.getCacheInfo (src/tools/utils/getCacheInfo.ts:15); @gala-chain/launchpad-sdk::getCacheInfo (src/tools/utils/getCacheInfo.ts:15) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_clear_cache` | launchpad | src/toolsets/launchpad/tools/utils/clearCache.ts:17 | LaunchpadSDK.clearCache (src/tools/utils/clearCache.ts:27 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_version` | core | src/toolsets/core/tools/session/getVersion.ts:19 | LaunchpadSDK.getVersion (src/tools/utils/getVersion.ts:15); @gala-chain/launchpad-sdk::getVersion (src/tools/utils/getVersion.ts:15) | session state (wallet identity, environment, versions), served by the server session on gala-core-sdk | | `gala_launchpad_has_wallet` | core | src/toolsets/core/tools/session/hasWallet.ts:12 | LaunchpadSDK.hasWallet (src/tools/utils/hasWallet.ts:13); @gala-chain/launchpad-sdk::hasWallet (src/tools/utils/hasWallet.ts:13) | session state (wallet identity, environment, versions), served by the server session on gala-core-sdk | | `gala_launchpad_get_wallet` | core | src/toolsets/core/tools/session/getWallet.ts:12 | LaunchpadSDK.getWallet (src/tools/utils/getWallet.ts:14); @gala-chain/launchpad-sdk::getWallet (src/tools/utils/getWallet.ts:14) | session state (wallet identity, environment, versions), served by the server session on gala-core-sdk | | `gala_launchpad_set_wallet` | core | src/toolsets/core/tools/session/setWallet.ts:12 | LaunchpadSDK.hasWallet (src/tools/utils/setWallet.ts:37); LaunchpadSDK.setWallet (src/tools/utils/setWallet.ts:31); @gala-chain/gala-core-sdk::address (src/tools/utils/setWallet.ts:36); @gala-chain/gala-core-sdk::createWallet (src/tools/utils/setWallet.ts:30); @gala-chain/gala-core-sdk::privateKey (src/tools/utils/setWallet.ts:31); @gala-chain/launchpad-sdk::hasWallet (src/tools/utils/setWallet.ts:37); +1 more | session state (wallet identity, environment, versions), served by the server session on gala-core-sdk | | `gala_launchpad_get_environment` | core | src/toolsets/core/tools/session/getEnvironment.ts:11 | server::param (src/tools/utils/getEnvironment.ts:14) | session state (wallet identity, environment, versions), served by the server session on gala-core-sdk | | `gala_launchpad_switch_environment` | core | src/toolsets/core/tools/session/switchEnvironment.ts:13 | server::param (src/tools/utils/switchEnvironment.ts:29) | session state (wallet identity, environment, versions), served by the server session on gala-core-sdk | | `gala_launchpad_cleanup` | launchpad | src/toolsets/launchpad/tools/utils/cleanup.ts:12 | LaunchpadSDK.cleanup (src/tools/utils/cleanup.ts:19 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_platform_status` | launchpad | src/toolsets/launchpad/tools/utils/getPlatformStatus.ts:13 | LaunchpadSDK.getPlatformStats (src/tools/utils/getPlatformStatus.ts:27 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_explain_websocket_events` | launchpad | src/toolsets/launchpad/tools/utils/explainWebSocketEvents.ts:13 | | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_event_schema` | launchpad | src/toolsets/launchpad/tools/utils/getEventSchema.ts:13 | | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_estimate_bridge_fee` | core | src/toolsets/core/tools/bridge/index.ts:32 | LaunchpadSDK.estimateBridgeFee (src/tools/bridge/index.ts:67 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_bridge_out` | core | src/toolsets/core/tools/bridge/index.ts:54 | LaunchpadSDK.bridgeOut (src/tools/bridge/index.ts:97 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_bridge_in` | core | src/toolsets/core/tools/bridge/index.ts:86 | LaunchpadSDK.bridgeIn (src/tools/bridge/index.ts:125 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_get_bridge_status` | core | src/toolsets/core/tools/bridge/index.ts:113 | LaunchpadSDK.getBridgeStatus (src/tools/bridge/index.ts:146 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_get_supported_bridge_tokens` | core | src/toolsets/core/tools/bridge/index.ts:137 | LaunchpadSDK.getSupportedBridgeTokens (src/tools/bridge/index.ts:171 (dispatched by name)); @gala-chain/gala-core-sdk::supportedChains (src/tools/bridge/index.ts:178) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_ethereum_wallet_token_balance` | core | src/toolsets/core/tools/bridge/helpers/external-chain-balance-tools.ts:44 | | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_ethereum_wallet_native_balance` | core | src/toolsets/core/tools/bridge/helpers/external-chain-balance-tools.ts:82 | | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_ethereum_wallet_all_balances` | core | src/toolsets/core/tools/bridge/helpers/external-chain-balance-tools.ts:117 | | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_solana_wallet_token_balance` | core | src/toolsets/core/tools/bridge/helpers/external-chain-balance-tools.ts:44 | | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_solana_wallet_native_balance` | core | src/toolsets/core/tools/bridge/helpers/external-chain-balance-tools.ts:82 | | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_solana_wallet_all_balances` | core | src/toolsets/core/tools/bridge/helpers/external-chain-balance-tools.ts:117 | | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_bridgeable_tokens_by_network` | core | src/toolsets/core/tools/bridge/index.ts:194 | LaunchpadSDK.fetchBridgeableTokensByNetwork (src/tools/bridge/index.ts:238 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_all_bridgeable_tokens_by_network` | core | src/toolsets/core/tools/bridge/index.ts:227 | LaunchpadSDK.fetchAllBridgeableTokensByNetwork (src/tools/bridge/index.ts:261 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_all_tokens_bridgeable_to_ethereum` | core | src/toolsets/core/tools/bridge/index.ts:247 | LaunchpadSDK.fetchAllTokensBridgeableToEthereum (src/tools/bridge/index.ts:275 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_all_tokens_bridgeable_to_solana` | core | src/toolsets/core/tools/bridge/index.ts:259 | LaunchpadSDK.fetchAllTokensBridgeableToSolana (src/tools/bridge/index.ts:287 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_is_token_bridgeable_to_network` | core | src/toolsets/core/tools/bridge/index.ts:271 | LaunchpadSDK.isTokenBridgeableToNetwork (src/tools/bridge/index.ts:306 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_is_token_bridgeable_to_ethereum` | core | src/toolsets/core/tools/bridge/index.ts:293 | LaunchpadSDK.isTokenBridgeableToEthereum (src/tools/bridge/index.ts:324 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_is_token_bridgeable_to_solana` | core | src/toolsets/core/tools/bridge/index.ts:310 | LaunchpadSDK.isTokenBridgeableToSolana (src/tools/bridge/index.ts:341 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_request_solana_devnet_airdrop` | core | src/toolsets/core/tools/bridge/index.ts:327 | LaunchpadSDK.requestSolanaDevnetAirdrop (src/tools/bridge/index.ts:369 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_get_solana_transaction_status` | core | src/toolsets/core/tools/bridge/index.ts:361 | LaunchpadSDK.getSolanaTransactionStatus (src/tools/bridge/index.ts:401 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_get_ethereum_transaction_status` | core | src/toolsets/core/tools/bridge/index.ts:387 | LaunchpadSDK.getEthereumTransactionStatus (src/tools/bridge/index.ts:430 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_wrappable_tokens` | core | src/toolsets/core/tools/bridge/index.ts:424 | LaunchpadSDK.fetchWrappableTokens (src/tools/bridge/index.ts:464 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_fetch_all_wrappable_tokens` | core | src/toolsets/core/tools/bridge/index.ts:452 | LaunchpadSDK.fetchAllWrappableTokens (src/tools/bridge/index.ts:482 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_get_wrappable_token` | core | src/toolsets/core/tools/bridge/index.ts:466 | LaunchpadSDK.getWrappableToken (src/tools/bridge/index.ts:504 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_get_wrap_counterpart` | core | src/toolsets/core/tools/bridge/index.ts:490 | LaunchpadSDK.getWrapCounterpart (src/tools/bridge/index.ts:528 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_is_token_wrappable` | core | src/toolsets/core/tools/bridge/index.ts:514 | LaunchpadSDK.isTokenWrappable (src/tools/bridge/index.ts:552 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_wrap_token` | core | src/toolsets/core/tools/bridge/index.ts:542 | LaunchpadSDK.wrapToken (src/tools/bridge/index.ts:573 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_unwrap_token` | core | src/toolsets/core/tools/bridge/index.ts:557 | LaunchpadSDK.unwrapToken (src/tools/bridge/index.ts:588 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_estimate_wrap_fee` | core | src/toolsets/core/tools/bridge/index.ts:572 | LaunchpadSDK.estimateWrapFee (src/tools/bridge/index.ts:611 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_estimate_unwrap_fee` | core | src/toolsets/core/tools/bridge/index.ts:598 | LaunchpadSDK.estimateUnwrapFee (src/tools/bridge/index.ts:637 (dispatched by name)) | gala-core-sdk ./bridge service (LaunchpadSDK method was a pass-through) | | `gala_launchpad_start_stream` | launchpad | src/toolsets/launchpad/tools/streaming/index.ts:39 | LaunchpadSDK.startStream (src/tools/streaming/index.ts:56 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_stop_stream` | launchpad | src/toolsets/launchpad/tools/streaming/index.ts:63 | LaunchpadSDK.stopStream (src/tools/streaming/index.ts:78 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_set_stream_enabled` | launchpad | src/toolsets/launchpad/tools/streaming/index.ts:88 | LaunchpadSDK.disableStream (src/tools/streaming/index.ts:109 (dispatched by name)); LaunchpadSDK.enableStream (src/tools/streaming/index.ts:109 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_reset_stream_key` | launchpad | src/toolsets/launchpad/tools/streaming/index.ts:116 | LaunchpadSDK.resetStreamKey (src/tools/streaming/index.ts:132 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_set_next_live_stream_countdown` | launchpad | src/toolsets/launchpad/tools/streaming/setNextLiveStreamCountdown.ts:29 | LaunchpadSDK.setNextLiveStreamCountdown (src/tools/streaming/setNextLiveStreamCountdown.ts:58 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_global_streaming_status` | launchpad | src/toolsets/launchpad/tools/streaming/index.ts:144 | LaunchpadSDK.getGlobalStreamingStatus (src/tools/streaming/index.ts:156 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_set_global_streaming_enabled` | launchpad | src/toolsets/launchpad/tools/streaming/index.ts:163 | LaunchpadSDK.setGlobalStreamingEnabled (src/tools/streaming/index.ts:182 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_stream_role` | launchpad | src/toolsets/launchpad/tools/streaming/index.ts:195 | LaunchpadSDK.getStreamRole (src/tools/streaming/index.ts:211 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_available_roles` | launchpad | src/toolsets/launchpad/tools/streaming/index.ts:226 | LaunchpadSDK.getAvailableRoles (src/tools/streaming/index.ts:264 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_token_access` | launchpad | src/toolsets/launchpad/tools/streaming/index.ts:277 | LaunchpadSDK.getTokenAccess (src/tools/streaming/index.ts:318 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_stream_recordings` | launchpad | src/toolsets/launchpad/tools/recordings/index.ts:52 | LaunchpadSDK.getStreamRecordings (src/tools/recordings/index.ts:69 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_recording_download` | launchpad | src/toolsets/launchpad/tools/recordings/index.ts:78 | LaunchpadSDK.getRecordingDownload (src/tools/recordings/index.ts:94 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_delete_recording` | launchpad | src/toolsets/launchpad/tools/recordings/index.ts:103 | LaunchpadSDK.deleteRecording (src/tools/recordings/index.ts:119 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_simulcast_targets` | launchpad | src/toolsets/launchpad/tools/simulcasts/index.ts:80 | LaunchpadSDK.getSimulcastTargets (src/tools/simulcasts/index.ts:95 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_add_simulcast_target` | launchpad | src/toolsets/launchpad/tools/simulcasts/index.ts:102 | LaunchpadSDK.addSimulcastTarget (src/tools/simulcasts/index.ts:121 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_remove_simulcast_target` | launchpad | src/toolsets/launchpad/tools/simulcasts/index.ts:136 | LaunchpadSDK.removeSimulcastTarget (src/tools/simulcasts/index.ts:152 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_chat_status` | launchpad | src/toolsets/launchpad/tools/chat/index.ts:40 | LaunchpadSDK.getTokenConfig (src/tools/chat/index.ts:56 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_set_chat_enabled` | launchpad | src/toolsets/launchpad/tools/chat/index.ts:67 | LaunchpadSDK.disableChat (src/tools/chat/index.ts:93 (dispatched by name)); LaunchpadSDK.enableChat (src/tools/chat/index.ts:93 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_set_slow_mode` | launchpad | src/toolsets/launchpad/tools/chat/index.ts:102 | LaunchpadSDK.setSlowMode (src/tools/chat/index.ts:128 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_connect_stream_websocket` | launchpad | src/toolsets/launchpad/tools/chat/index.ts:144 | LaunchpadSDK.connectStreamWebSocket (src/tools/chat/index.ts:161 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_subscribe_to_stream` | launchpad | src/toolsets/launchpad/tools/chat/index.ts:171 | LaunchpadSDK.subscribeToStream (src/tools/chat/index.ts:189 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_send_stream_chat_via_web_socket` | launchpad | src/toolsets/launchpad/tools/chat/index.ts:198 | LaunchpadSDK.sendStreamChatViaWebSocket (src/tools/chat/index.ts:219 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_send_stream_reaction` | launchpad | src/toolsets/launchpad/tools/chat/index.ts:235 | LaunchpadSDK.sendStreamReaction (src/tools/chat/index.ts:268 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_send_typing_indicator` | launchpad | src/toolsets/launchpad/tools/chat/index.ts:291 | LaunchpadSDK.sendTypingStart (src/tools/chat/index.ts:320 (dispatched by name)); LaunchpadSDK.sendTypingStop (src/tools/chat/index.ts:320 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_login` | launchpad | src/toolsets/launchpad/tools/auth/index.ts:41 | LaunchpadSDK.login (src/tools/auth/index.ts:49 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_logout` | launchpad | src/toolsets/launchpad/tools/auth/index.ts:60 | LaunchpadSDK.logout (src/tools/auth/index.ts:67 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_refresh_token` | launchpad | src/toolsets/launchpad/tools/auth/index.ts:73 | LaunchpadSDK.refreshToken (src/tools/auth/index.ts:81 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_session` | launchpad | src/toolsets/launchpad/tools/auth/index.ts:92 | LaunchpadSDK.getSession (src/tools/auth/index.ts:100 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_is_authenticated` | launchpad | src/toolsets/launchpad/tools/auth/index.ts:113 | LaunchpadSDK.isAuthenticated (src/tools/auth/index.ts:121 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_should_refresh_token` | launchpad | src/toolsets/launchpad/tools/auth/index.ts:130 | LaunchpadSDK.shouldRefreshToken (src/tools/auth/index.ts:144 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_access_token` | launchpad | src/toolsets/launchpad/tools/auth/index.ts:153 | LaunchpadSDK.getAccessToken (src/tools/auth/index.ts:161 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_ensure_valid_token` | launchpad | src/toolsets/launchpad/tools/auth/index.ts:171 | LaunchpadSDK.ensureValidToken (src/tools/auth/index.ts:186); @gala-chain/launchpad-sdk::ensureValidToken (src/tools/auth/index.ts:186) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_create_ban` | launchpad | src/toolsets/launchpad/tools/ban/index.ts:38 | LaunchpadSDK.createBan (src/tools/ban/index.ts:66 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_remove_ban` | launchpad | src/toolsets/launchpad/tools/ban/index.ts:78 | LaunchpadSDK.removeBan (src/tools/ban/index.ts:97 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_list_bans` | launchpad | src/toolsets/launchpad/tools/ban/index.ts:104 | LaunchpadSDK.listBans (src/tools/ban/index.ts:138 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_ban_status` | launchpad | src/toolsets/launchpad/tools/ban/index.ts:154 | LaunchpadSDK.getBanStatus (src/tools/ban/index.ts:173 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_active_users` | launchpad | src/toolsets/launchpad/tools/ban/index.ts:180 | LaunchpadSDK.getActiveUsers (src/tools/ban/index.ts:212 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_on_ban_enforcement` | launchpad | src/toolsets/launchpad/tools/ban/onBanEnforcement.ts:12 | LaunchpadSDK.watchBanEnforcement (src/tools/ban/onBanEnforcement.ts:29 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_create_api_key` | launchpad | src/toolsets/launchpad/tools/api-keys/index.ts:61 | LaunchpadSDK.createApiKey (src/tools/api-keys/index.ts:91 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_list_api_keys` | launchpad | src/toolsets/launchpad/tools/api-keys/index.ts:104 | LaunchpadSDK.listApiKeys (src/tools/api-keys/index.ts:121 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_api_key` | launchpad | src/toolsets/launchpad/tools/api-keys/index.ts:131 | LaunchpadSDK.getApiKey (src/tools/api-keys/index.ts:146 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_api_key` | launchpad | src/toolsets/launchpad/tools/api-keys/index.ts:153 | LaunchpadSDK.updateApiKey (src/tools/api-keys/index.ts:184 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_revoke_api_key` | launchpad | src/toolsets/launchpad/tools/api-keys/index.ts:209 | LaunchpadSDK.revokeApiKey (src/tools/api-keys/index.ts:225 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_api_key_roles` | launchpad | src/toolsets/launchpad/tools/api-keys/index.ts:232 | LaunchpadSDK.getApiKeyRoles (src/tools/api-keys/index.ts:253 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_create_moderator_invite` | launchpad | src/toolsets/launchpad/tools/moderators/index.ts:54 | LaunchpadSDK.createModeratorInvite (src/tools/moderators/index.ts:86 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_claim_moderator_invite` | launchpad | src/toolsets/launchpad/tools/moderators/index.ts:99 | LaunchpadSDK.claimModeratorInvite (src/tools/moderators/index.ts:121 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_moderated_tokens` | launchpad | src/toolsets/launchpad/tools/moderators/index.ts:132 | LaunchpadSDK.getModeratedTokens (src/tools/moderators/index.ts:150 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_list_moderator_invites` | launchpad | src/toolsets/launchpad/tools/moderators/index.ts:162 | LaunchpadSDK.listModeratorInvites (src/tools/moderators/index.ts:183 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_revoke_moderator_invite` | launchpad | src/toolsets/launchpad/tools/moderators/index.ts:195 | LaunchpadSDK.revokeModeratorInvite (src/tools/moderators/index.ts:212 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_moderator_invite_role` | launchpad | src/toolsets/launchpad/tools/moderators/index.ts:222 | LaunchpadSDK.updateModeratorInviteRole (src/tools/moderators/index.ts:246 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_moderator_invite` | launchpad | src/toolsets/launchpad/tools/moderators/index.ts:285 | LaunchpadSDK.updateModeratorInvite (src/tools/moderators/index.ts:308 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_moderator_invite` | launchpad | src/toolsets/launchpad/tools/moderators/index.ts:256 | LaunchpadSDK.getModeratorInviteByCode (src/tools/moderators/index.ts:278 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_on_moderator_changed` | launchpad | src/toolsets/launchpad/tools/moderators/onModeratorChanged.ts:12 | LaunchpadSDK.watchModeratorChanged (src/tools/moderators/onModeratorChanged.ts:28 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_active_moderators` | launchpad | src/toolsets/launchpad/tools/moderators/getActiveModerators.ts:18 | LaunchpadSDK.getActiveModerators (src/tools/moderators/getActiveModerators.ts:39 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_create_flag` | launchpad | src/toolsets/launchpad/tools/content-flags/index.ts:162 | LaunchpadSDK.createFlag (src/tools/content-flags/index.ts:192 (dispatched by name)); @gala-chain/launchpad-sdk::ContentType (src/tools/content-flags/index.ts:194); @gala-chain/launchpad-sdk::FlagReason (src/tools/content-flags/index.ts:197) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_list_flags` | launchpad | src/toolsets/launchpad/tools/content-flags/index.ts:206 | LaunchpadSDK.listFlags (src/tools/content-flags/index.ts:233 (dispatched by name)); @gala-chain/launchpad-sdk::ContentType (src/tools/content-flags/index.ts:62); @gala-chain/launchpad-sdk::FlagReason (src/tools/content-flags/index.ts:64); @gala-chain/launchpad-sdk::FlagStatus (src/tools/content-flags/index.ts:63) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_list_global_flags` | launchpad | src/toolsets/launchpad/tools/content-flags/index.ts:240 | LaunchpadSDK.listGlobalFlags (src/tools/content-flags/index.ts:267 (dispatched by name)); @gala-chain/launchpad-sdk::ContentType (src/tools/content-flags/index.ts:62); @gala-chain/launchpad-sdk::FlagReason (src/tools/content-flags/index.ts:64); @gala-chain/launchpad-sdk::FlagStatus (src/tools/content-flags/index.ts:63) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_dismiss_flag` | launchpad | src/toolsets/launchpad/tools/content-flags/index.ts:274 | LaunchpadSDK.dismissFlag (src/tools/content-flags/index.ts:290 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_action_flag` | launchpad | src/toolsets/launchpad/tools/content-flags/index.ts:299 | LaunchpadSDK.actionFlag (src/tools/content-flags/index.ts:320 (dispatched by name)); @gala-chain/launchpad-sdk::FlagAction (src/tools/content-flags/index.ts:322) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_create_overseer_invite` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:99 | LaunchpadSDK.createOverseerInvite (src/tools/overseers/index.ts:119 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_list_overseer_invites` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:131 | LaunchpadSDK.listOverseerInvites (src/tools/overseers/index.ts:148 (dispatched by name)); @gala-chain/launchpad-sdk::OVERSEER_INVITE_STATUS (src/tools/overseers/index.ts:72) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_overseer_invite` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:159 | LaunchpadSDK.getOverseerInviteByCode (src/tools/overseers/index.ts:180 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_claim_overseer_invite` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:187 | LaunchpadSDK.claimOverseerInvite (src/tools/overseers/index.ts:207 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_revoke_overseer_invite` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:214 | LaunchpadSDK.revokeOverseerInvite (src/tools/overseers/index.ts:231 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_list_overseers` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:247 | LaunchpadSDK.listOverseers (src/tools/overseers/index.ts:264 (dispatched by name)); @gala-chain/launchpad-sdk::OVERSEER_STATUS (src/tools/overseers/index.ts:85) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_create_overseer_direct` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:280 | LaunchpadSDK.createOverseerDirect (src/tools/overseers/index.ts:303 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_revoke_overseer` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:313 | LaunchpadSDK.revokeOverseer (src/tools/overseers/index.ts:332 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_my_overseer_status` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:342 | LaunchpadSDK.getMyOverseerStatus (src/tools/overseers/index.ts:356 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_overseer_summary` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:363 | LaunchpadSDK.getOverseerSummary (src/tools/overseers/index.ts:384 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_ban_stats` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:395 | LaunchpadSDK.getBanStats (src/tools/overseers/index.ts:408 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_token_ban_stats` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:415 | LaunchpadSDK.getTokenBanStats (src/tools/overseers/index.ts:428 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_invite_stats` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:435 | LaunchpadSDK.getInviteStats (src/tools/overseers/index.ts:448 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_flag_stats` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:455 | LaunchpadSDK.getFlagStats (src/tools/overseers/index.ts:468 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_user_stats` | launchpad | src/toolsets/launchpad/tools/overseers/index.ts:476 | LaunchpadSDK.getUserStats (src/tools/overseers/index.ts:489 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_list_overseer_users` | launchpad | src/toolsets/launchpad/tools/overseers/listOverseerUsers.ts:38 | LaunchpadSDK.listOverseerUsers (src/tools/overseers/listOverseerUsers.ts:75 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_overseer_user_summary` | launchpad | src/toolsets/launchpad/tools/overseers/getOverseerUserSummary.ts:19 | LaunchpadSDK.getOverseerUserSummary (src/tools/overseers/getOverseerUserSummary.ts:38 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_flush_cache_by_address` | launchpad | src/toolsets/launchpad/tools/overseers/cache-management.ts:34 | LaunchpadSDK.flushCacheByAddress (src/tools/overseers/cache-management.ts:65 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_flush_cache_by_token` | launchpad | src/toolsets/launchpad/tools/overseers/cache-management.ts:72 | LaunchpadSDK.flushCacheByToken (src/tools/overseers/cache-management.ts:105 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_flush_all_cache` | launchpad | src/toolsets/launchpad/tools/overseers/cache-management.ts:112 | LaunchpadSDK.flushAllCache (src/tools/overseers/cache-management.ts:146 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_flush_cache_wallet_aliases` | launchpad | src/toolsets/launchpad/tools/overseers/cache-management.ts:153 | LaunchpadSDK.flushWalletAliasCache (src/tools/overseers/cache-management.ts:186 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_ban_token` | launchpad | src/toolsets/launchpad/tools/token-ban/index.ts:37 | LaunchpadSDK.banToken (src/tools/token-ban/index.ts:63 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_unban_token` | launchpad | src/toolsets/launchpad/tools/token-ban/index.ts:73 | LaunchpadSDK.unbanToken (src/tools/token-ban/index.ts:93 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_list_token_bans` | launchpad | src/toolsets/launchpad/tools/token-ban/index.ts:102 | LaunchpadSDK.listTokenBans (src/tools/token-ban/index.ts:123 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_token_ban` | launchpad | src/toolsets/launchpad/tools/token-ban/index.ts:134 | LaunchpadSDK.getTokenBan (src/tools/token-ban/index.ts:150 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_is_token_banned` | launchpad | src/toolsets/launchpad/tools/token-ban/index.ts:159 | LaunchpadSDK.isTokenBanned (src/tools/token-ban/index.ts:175 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_on_token_ban_changed` | launchpad | src/toolsets/launchpad/tools/token-ban/onTokenBanChanged.ts:12 | LaunchpadSDK.watchTokenBanChanged (src/tools/token-ban/onTokenBanChanged.ts:26 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_messages` | launchpad | src/toolsets/launchpad/tools/messages/fetchMessages.ts:35 | LaunchpadSDK.fetchMessages (src/tools/messages/fetchMessages.ts:87 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_create_message` | launchpad | src/toolsets/launchpad/tools/messages/createMessage.ts:41 | LaunchpadSDK.createMessage (src/tools/messages/createMessage.ts:75 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_message` | launchpad | src/toolsets/launchpad/tools/messages/updateMessage.ts:30 | LaunchpadSDK.updateMessage (src/tools/messages/updateMessage.ts:54 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_delete_message` | launchpad | src/toolsets/launchpad/tools/messages/deleteMessage.ts:20 | LaunchpadSDK.deleteMessage (src/tools/messages/deleteMessage.ts:43 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_pinned_message` | launchpad | src/toolsets/launchpad/tools/messages/getPinnedMessage.ts:19 | LaunchpadSDK.getPinnedMessage (src/tools/messages/getPinnedMessage.ts:40 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_pin_message` | launchpad | src/toolsets/launchpad/tools/messages/pinMessage.ts:19 | LaunchpadSDK.pinMessage (src/tools/messages/pinMessage.ts:43 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_unpin_message` | launchpad | src/toolsets/launchpad/tools/messages/unpinMessage.ts:19 | LaunchpadSDK.unpinMessage (src/tools/messages/unpinMessage.ts:42 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_message_stats` | launchpad | src/toolsets/launchpad/tools/messages/getMessageStats.ts:19 | LaunchpadSDK.getMessageStats (src/tools/messages/getMessageStats.ts:45 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_restricted_names` | launchpad | src/toolsets/launchpad/tools/restricted-names/getRestrictedNames.ts:19 | LaunchpadSDK.getRestrictedNames (src/tools/restricted-names/getRestrictedNames.ts:37 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_restricted_names` | launchpad | src/toolsets/launchpad/tools/restricted-names/updateRestrictedNames.ts:19 | LaunchpadSDK.updateRestrictedNames (src/tools/restricted-names/updateRestrictedNames.ts:39 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_add_content_reaction` | launchpad | src/toolsets/launchpad/tools/content-reactions/index.ts:27 | LaunchpadSDK.addContentReaction (src/tools/content-reactions/index.ts:38 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_remove_content_reaction` | launchpad | src/toolsets/launchpad/tools/content-reactions/index.ts:45 | LaunchpadSDK.removeContentReaction (src/tools/content-reactions/index.ts:55 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_add_reaction_to_chat_message` | launchpad | src/toolsets/launchpad/tools/content-reactions/index.ts:66 | LaunchpadSDK.addReactionToChatMessage (src/tools/content-reactions/index.ts:75 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_remove_reaction_from_chat_message` | launchpad | src/toolsets/launchpad/tools/content-reactions/index.ts:82 | LaunchpadSDK.removeReactionFromChatMessage (src/tools/content-reactions/index.ts:91 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_add_reaction_to_comment` | launchpad | src/toolsets/launchpad/tools/content-reactions/index.ts:102 | LaunchpadSDK.addReactionToComment (src/tools/content-reactions/index.ts:111 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_remove_reaction_from_comment` | launchpad | src/toolsets/launchpad/tools/content-reactions/index.ts:118 | LaunchpadSDK.removeReactionFromComment (src/tools/content-reactions/index.ts:127 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_trades` | launchpad | src/toolsets/launchpad/tools/trades/index.ts:49 | LaunchpadSDK.getTrades (src/tools/trades/index.ts:117 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_on_trade_executed` | launchpad | src/toolsets/launchpad/tools/trades/onTradeExecuted.ts:12 | LaunchpadSDK.watchTradeExecuted (src/tools/trades/onTradeExecuted.ts:26 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_recent_trades` | launchpad | src/toolsets/launchpad/tools/trades/getRecentTrades.ts:25 | LaunchpadSDK.getRecentTrades (src/tools/trades/getRecentTrades.ts:58 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_holder_rank` | launchpad | src/toolsets/launchpad/tools/holders/index.ts:34 | LaunchpadSDK.fetchTokenDistribution (src/tools/holders/index.ts:56); @gala-chain/launchpad-sdk::balance (src/tools/holders/index.ts:73); @gala-chain/launchpad-sdk::fetchTokenDistribution (src/tools/holders/index.ts:56); @gala-chain/launchpad-sdk::holders (src/tools/holders/index.ts:63); @gala-chain/launchpad-sdk::totalHolders (src/tools/holders/index.ts:74) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_top_holders` | launchpad | src/toolsets/launchpad/tools/holders/index.ts:86 | LaunchpadSDK.fetchTokenDistribution (src/tools/holders/index.ts:113); @gala-chain/launchpad-sdk::fetchTokenDistribution (src/tools/holders/index.ts:113); @gala-chain/launchpad-sdk::holders (src/tools/holders/index.ts:120) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_holder_count` | launchpad | src/toolsets/launchpad/tools/holders/index.ts:135 | LaunchpadSDK.fetchTokenDistribution (src/tools/holders/index.ts:153); @gala-chain/launchpad-sdk::fetchTokenDistribution (src/tools/holders/index.ts:153); @gala-chain/launchpad-sdk::totalHolders (src/tools/holders/index.ts:161); @gala-chain/launchpad-sdk::totalSupply (src/tools/holders/index.ts:162) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_holders_by_balance` | launchpad | src/toolsets/launchpad/tools/holders/index.ts:174 | LaunchpadSDK.fetchTokenDistribution (src/tools/holders/index.ts:215); @gala-chain/launchpad-sdk::fetchTokenDistribution (src/tools/holders/index.ts:215); @gala-chain/launchpad-sdk::holders (src/tools/holders/index.ts:230) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_holder_history` | launchpad | src/toolsets/launchpad/tools/holders/index.ts:244 | LaunchpadSDK.getTrades (src/tools/holders/index.ts:278); @gala-chain/launchpad-sdk::getTrades (src/tools/holders/index.ts:278) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_global_feed_reference` | launchpad | src/toolsets/launchpad/tools/global-feed/subscribeToGlobalFeed.ts:22 | | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_unsubscribe_from_global_feed_reference` | launchpad | src/toolsets/launchpad/tools/global-feed/unsubscribeFromGlobalFeed.ts:21 | | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_global_feed_status_reference` | launchpad | src/toolsets/launchpad/tools/global-feed/getGlobalFeedStatus.ts:21 | | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_monitor_global_feed_events_reference` | launchpad | src/toolsets/launchpad/tools/global-feed/monitorGlobalFeedEvents.ts:21 | | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_site_config_state_reference` | launchpad | src/toolsets/launchpad/tools/global-feed/getSiteConfigState.ts:21 | | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_trade_executed` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitTradeExecuted.ts:28 | LaunchpadSDK.emitTradeExecuted (src/tools/websocket-admin/emitTradeExecuted.ts:58 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_balance_updated` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitBalanceUpdated.ts:19 | LaunchpadSDK.emitBalanceUpdated (src/tools/websocket-admin/emitBalanceUpdated.ts:56 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_stream_status` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitStreamStatus.ts:28 | LaunchpadSDK.emitStreamStatus (src/tools/websocket-admin/emitStreamStatus.ts:55 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_viewer_count` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitViewerCount.ts:19 | LaunchpadSDK.emitViewerCount (src/tools/websocket-admin/emitViewerCount.ts:45 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_stream_countdown` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitStreamCountdown.ts:19 | LaunchpadSDK.emitStreamCountdown (src/tools/websocket-admin/emitStreamCountdown.ts:49 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_chat_message` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitChatMessage.ts:19 | LaunchpadSDK.emitChatMessage (src/tools/websocket-admin/emitChatMessage.ts:50 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_chat_status` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitChatStatus.ts:19 | LaunchpadSDK.emitChatStatus (src/tools/websocket-admin/emitChatStatus.ts:48 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_typing_indicator` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitTypingIndicator.ts:19 | LaunchpadSDK.emitTypingIndicator (src/tools/websocket-admin/emitTypingIndicator.ts:51 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_token_banned` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitTokenBanned.ts:19 | LaunchpadSDK.emitTokenBanned (src/tools/websocket-admin/emitTokenBanned.ts:53 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_token_unbanned` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitTokenUnbanned.ts:19 | LaunchpadSDK.emitTokenUnbanned (src/tools/websocket-admin/emitTokenUnbanned.ts:48 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_moderator_added` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitModeratorAdded.ts:28 | LaunchpadSDK.emitModeratorAdded (src/tools/websocket-admin/emitModeratorAdded.ts:58 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_moderator_removed` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitModeratorRemoved.ts:19 | LaunchpadSDK.emitModeratorRemoved (src/tools/websocket-admin/emitModeratorRemoved.ts:48 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_user_profile_updated` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitUserProfileUpdated.ts:19 | LaunchpadSDK.emitUserProfileUpdated (src/tools/websocket-admin/emitUserProfileUpdated.ts:51 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_site_config_changed` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitSiteConfigChanged.ts:18 | LaunchpadSDK.emitSiteConfigChanged (src/tools/websocket-admin/emitSiteConfigChanged.ts:48 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_feature_status` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitFeatureStatus.ts:18 | LaunchpadSDK.emitFeatureStatus (src/tools/websocket-admin/emitFeatureStatus.ts:54 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_recording_status` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitRecordingStatus.ts:19 | LaunchpadSDK.emitRecordingStatus (src/tools/websocket-admin/emitRecordingStatus.ts:66 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_recordings_count_updated` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitRecordingsCountUpdated.ts:19 | LaunchpadSDK.emitRecordingsCountUpdated (src/tools/websocket-admin/emitRecordingsCountUpdated.ts:48 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_download_ready` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitDownloadReady.ts:19 | LaunchpadSDK.emitDownloadReady (src/tools/websocket-admin/emitDownloadReady.ts:65 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_emit_websocket_event` | launchpad | src/toolsets/launchpad/tools/websocket-admin/emitWebSocketEvent.ts:44 | LaunchpadSDK.emitWebSocketEvent (src/tools/websocket-admin/emitWebSocketEvent.ts:91 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_connected_clients` | launchpad | src/toolsets/launchpad/tools/websocket-admin/getConnectedClients.ts:19 | LaunchpadSDK.getConnectedClients (src/tools/websocket-admin/getConnectedClients.ts:103 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_is_user_online` | launchpad | src/toolsets/launchpad/tools/websocket-admin/isUserOnline.ts:18 | LaunchpadSDK.isUserOnline (src/tools/websocket-admin/isUserOnline.ts:45 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_online_users` | launchpad | src/toolsets/launchpad/tools/websocket-admin/getOnlineUsers.ts:18 | LaunchpadSDK.getOnlineUsers (src/tools/websocket-admin/getOnlineUsers.ts:47 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_token_viewers` | launchpad | src/toolsets/launchpad/tools/websocket-admin/getTokenViewers.ts:19 | LaunchpadSDK.getTokenViewers (src/tools/websocket-admin/getTokenViewers.ts:52 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_online_overseers` | launchpad | src/toolsets/launchpad/tools/websocket-admin/getOnlineOverseers.ts:18 | LaunchpadSDK.getOnlineOverseers (src/tools/websocket-admin/getOnlineOverseers.ts:37 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_ai_moderation_settings` | launchpad | src/toolsets/launchpad/tools/ai-moderation/index.ts:60 | LaunchpadSDK.getAIModerationSettings (src/tools/ai-moderation/index.ts:77 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_ai_moderation_settings` | launchpad | src/toolsets/launchpad/tools/ai-moderation/index.ts:84 | LaunchpadSDK.updateAIModerationSettings (src/tools/ai-moderation/index.ts:102 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_ai_moderation_result` | launchpad | src/toolsets/launchpad/tools/ai-moderation/index.ts:113 | LaunchpadSDK.getAIModeration (src/tools/ai-moderation/index.ts:133 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_trigger_ai_moderation` | launchpad | src/toolsets/launchpad/tools/ai-moderation/index.ts:142 | LaunchpadSDK.triggerAIModeration (src/tools/ai-moderation/index.ts:163 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_ai_moderation_status` | launchpad | src/toolsets/launchpad/tools/ai-moderation/index.ts:172 | LaunchpadSDK.getAIModerationStatus (src/tools/ai-moderation/index.ts:191 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_weekly_challenge_leaderboard` | launchpad | src/toolsets/launchpad/tools/weekly-challenge/index.ts:45 | LaunchpadSDK.getWeeklyChallengeLeaderboard (src/tools/weekly-challenge/index.ts:61 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_token_weekly_history` | launchpad | src/toolsets/launchpad/tools/weekly-challenge/index.ts:70 | LaunchpadSDK.getTokenWeeklyHistory (src/tools/weekly-challenge/index.ts:86 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_home_oembed` | launchpad | src/toolsets/launchpad/tools/oembed/index.ts:42 | LaunchpadSDK.getHomeOEmbed (src/tools/oembed/index.ts:56 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_pool_oembed` | launchpad | src/toolsets/launchpad/tools/oembed/index.ts:63 | LaunchpadSDK.getPoolOEmbed (src/tools/oembed/index.ts:79 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_profile_oembed` | launchpad | src/toolsets/launchpad/tools/oembed/index.ts:88 | LaunchpadSDK.getProfileOEmbed (src/tools/oembed/index.ts:104 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_platform_stats` | launchpad | src/toolsets/launchpad/tools/platform-stats/index.ts:24 | LaunchpadSDK.getPlatformStats (src/tools/platform-stats/index.ts:41 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_register_push_token` | launchpad | src/toolsets/launchpad/tools/notifications/index.ts:26 | LaunchpadSDK.registerPushToken (src/tools/notifications/index.ts:59 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_unregister_push_token` | launchpad | src/toolsets/launchpad/tools/notifications/index.ts:70 | LaunchpadSDK.unregisterPushToken (src/tools/notifications/index.ts:91 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_notification_preferences` | launchpad | src/toolsets/launchpad/tools/notifications/index.ts:98 | LaunchpadSDK.fetchNotificationPreferences (src/tools/notifications/index.ts:111 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_notification_preferences` | launchpad | src/toolsets/launchpad/tools/notifications/index.ts:118 | LaunchpadSDK.updateNotificationPreferences (src/tools/notifications/index.ts:154 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_fetch_client_flags` | launchpad | src/toolsets/launchpad/tools/notifications/index.ts:168 | LaunchpadSDK.fetchClientFlags (src/tools/notifications/index.ts:182 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_comments` | launchpad | src/toolsets/launchpad/tools/comments/index.ts:56 | LaunchpadSDK.getComments (src/tools/comments/index.ts:90 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_create_comment` | launchpad | src/toolsets/launchpad/tools/comments/index.ts:102 | LaunchpadSDK.createComment (src/tools/comments/index.ts:123 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_comment` | launchpad | src/toolsets/launchpad/tools/comments/index.ts:132 | LaunchpadSDK.updateComment (src/tools/comments/index.ts:150 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_delete_comment` | launchpad | src/toolsets/launchpad/tools/comments/index.ts:159 | LaunchpadSDK.deleteComment (src/tools/comments/index.ts:175 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_on_comment_created` | launchpad | src/toolsets/launchpad/tools/comments/onCommentCreated.ts:12 | LaunchpadSDK.watchCommentCreated (src/tools/comments/onCommentCreated.ts:29 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_get_chat_messages` | launchpad | src/toolsets/launchpad/tools/chat-messages/index.ts:39 | LaunchpadSDK.getChatMessages (src/tools/chat-messages/index.ts:71 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_send_chat_message` | launchpad | src/toolsets/launchpad/tools/chat-messages/index.ts:81 | LaunchpadSDK.sendChatMessage (src/tools/chat-messages/index.ts:108 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_update_chat_message` | launchpad | src/toolsets/launchpad/tools/chat-messages/index.ts:115 | LaunchpadSDK.updateChatMessage (src/tools/chat-messages/index.ts:140 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | | `gala_launchpad_delete_chat_message` | launchpad | src/toolsets/launchpad/tools/chat-messages/index.ts:147 | LaunchpadSDK.deleteChatMessage (src/tools/chat-messages/index.ts:167 (dispatched by name)) | launchpad-sdk (launchpad backend, bundler or websocket) | ## Prompts (286) Group = the toolset module that defines the prompt. A prompt is offered only when every tool its text names is registered in the selection (tools named over all argument variants: `src/manifests/prompts-manifest.ts`, checked by rendering in `groups.test.ts`). | prompt | group | toolsets of the tools it names | | --- | --- | --- | | `galachain-launchpad:discover-bridgeable-tokens` | core | core | | `galachain-launchpad:bridge-status` | core | core | | `galachain-launchpad:estimate-fee` | core | core | | `galachain-launchpad:version` | core | core | | `galachain-launchpad:switch-environment` | core | core | | `galachain-launchpad:create-wallet` | core | core | | `galachain-launchpad:get-address` | core | core | | `galachain-launchpad:get-ethereum-address` | core | core | | `galachain-launchpad:get-public-key-from-private-key` | core | core | | `galachain-launchpad:get-ethereum-address-from-private-key` | core | core | | `galachain-launchpad:explain-sdk-usage` | core | core | | `galachain-launchpad:has-wallet` | core | core | | `galachain-launchpad:get-wallet` | core | core | | `galachain-launchpad:set-wallet` | core | core | | `galachain-launchpad:get-environment` | core | core | | `galachain-launchpad:bridge-fee` | core | core | | `galachain-launchpad:bridge-out` | core | core | | `galachain-launchpad:bridge-in` | core | core | | `galachain-launchpad:eth-token-balance` | core | core | | `galachain-launchpad:eth-native-balance` | core | core | | `galachain-launchpad:sol-token-balance` | core | core | | `galachain-launchpad:sol-native-balance` | core | core | | `galachain-launchpad:eth-all-balances` | core | core | | `galachain-launchpad:sol-all-balances` | core | core | | `galachain-launchpad:create-solana-wallet` | core | core | | `galachain-launchpad:my-address` | core | core | | `galachain-launchpad:derive-address` | core | core | | `galachain-launchpad:wallet-status` | core | core | | `galachain-launchpad:fetch-gala-balance` | core | core | | `galachain-launchpad:transfer-gala` | core | core | | `galachain-launchpad:fetch-pool-details` | launchpad | launchpad | | `galachain-launchpad:analyze-token` | launchpad | launchpad | | `galachain-launchpad:fetch-token-distribution` | launchpad | launchpad | | `galachain-launchpad:fetch-volume-data` | launchpad | launchpad | | `galachain-launchpad:bridge-tokens` | launchpad | core, launchpad | | `galachain-launchpad:launch-token` | launchpad | - (names no tool) | | `galachain-launchpad:graduate-token` | launchpad | - (names no tool) | | `galachain-launchpad:token-lifecycle` | launchpad | - (names no tool) | | `galachain-launchpad:transfer-assets` | launchpad | - (names no tool) | | `galachain-launchpad:stake-tokens` | launchpad | - (names no tool) | | `galachain-launchpad:manage-assets` | launchpad | - (names no tool) | | `galachain-launchpad:setup-account` | launchpad | - (names no tool) | | `galachain-launchpad:customize-profile` | launchpad | - (names no tool) | | `galachain-launchpad:account-management` | launchpad | - (names no tool) | | `galachain-launchpad:invite-moderators` | launchpad | - (names no tool) | | `galachain-launchpad:manage-moderators` | launchpad | - (names no tool) | | `galachain-launchpad:moderate-comments` | launchpad | - (names no tool) | | `galachain-launchpad:ban-users` | launchpad | - (names no tool) | | `galachain-launchpad:post-comments` | launchpad | - (names no tool) | | `galachain-launchpad:react-to-content` | launchpad | - (names no tool) | | `galachain-launchpad:monitor-community` | launchpad | - (names no tool) | | `galachain-launchpad:manage-streams` | launchpad | - (names no tool) | | `galachain-launchpad:manage-recordings` | launchpad | - (names no tool) | | `galachain-launchpad:manage-simulcast` | launchpad | - (names no tool) | | `galachain-launchpad:buy-tokens` | launchpad | launchpad | | `galachain-launchpad:sell-tokens` | launchpad | launchpad | | `galachain-launchpad:burn-tokens` | launchpad | launchpad | | `galachain-launchpad:get-trades` | launchpad | launchpad | | `galachain-launchpad:tokens-held` | launchpad | launchpad | | `galachain-launchpad:tokens-created` | launchpad | launchpad | | `galachain-launchpad:profile` | launchpad | core, launchpad | | `galachain-launchpad:compare-tokens` | launchpad | launchpad | | `galachain-launchpad:graduation-status` | launchpad | launchpad | | `galachain-launchpad:pool-details` | launchpad | launchpad | | `galachain-launchpad:trade-history` | launchpad | launchpad | | `galachain-launchpad:create-token` | launchpad | core, launchpad | | `galachain-launchpad:claim-nft-collection` | launchpad | - (names no tool) | | `galachain-launchpad:mint-nft` | launchpad | - (names no tool) | | `galachain-launchpad:manage-nft-collections` | launchpad | - (names no tool) | | `galachain-launchpad:create-nft-token-class` | launchpad | - (names no tool) | | `galachain-launchpad:estimate-nft-operations` | launchpad | - (names no tool) | | `galachain-launchpad:discover-tokens` | launchpad | launchpad | | `galachain-launchpad:fetch-pools` | launchpad | launchpad | | `galachain-launchpad:fetch-pool-details-for-calculation` | launchpad | launchpad | | `galachain-launchpad:fetch-token-details` | launchpad | launchpad | | `galachain-launchpad:check-token-name` | launchpad | launchpad | | `galachain-launchpad:check-token-symbol` | launchpad | launchpad | | `galachain-launchpad:resolve-vault-address` | launchpad | launchpad | | `galachain-launchpad:resolve-token-class-key` | launchpad | launchpad | | `galachain-launchpad:calculate-buy-amount` | launchpad | launchpad | | `galachain-launchpad:calculate-sell-amount` | launchpad | launchpad | | `galachain-launchpad:fetch-trades` | launchpad | launchpad | | `galachain-launchpad:calculate-initial-buy` | launchpad | launchpad | | `galachain-launchpad:get-bundler-transaction-result` | launchpad | launchpad | | `galachain-launchpad:calculate-graduation-cost` | launchpad | launchpad | | `galachain-launchpad:calculate-buy-amount-local` | launchpad | launchpad | | `galachain-launchpad:calculate-buy-amount-external` | launchpad | launchpad | | `galachain-launchpad:calculate-sell-amount-local` | launchpad | launchpad | | `galachain-launchpad:calculate-sell-amount-external` | launchpad | launchpad | | `galachain-launchpad:is-token-graduated` | launchpad | launchpad | | `galachain-launchpad:fetch-token-balance` | launchpad | launchpad | | `galachain-launchpad:fetch-tokens-created` | launchpad | launchpad | | `galachain-launchpad:update-profile` | launchpad | launchpad | | `galachain-launchpad:upload-profile-image` | launchpad | launchpad | | `galachain-launchpad:upload-token-image` | launchpad | launchpad | | `galachain-launchpad:fetch-launch-token-fee` | launchpad | launchpad | | `galachain-launchpad:transfer-token` | launchpad | launchpad | | `galachain-launchpad:lock-token` | launchpad | launchpad | | `galachain-launchpad:unlock-token` | launchpad | launchpad | | `galachain-launchpad:get-config` | launchpad | launchpad | | `galachain-launchpad:get-url-by-token-name` | launchpad | launchpad | | `galachain-launchpad:get-cache-info` | launchpad | launchpad | | `galachain-launchpad:clear-cache` | launchpad | launchpad | | `galachain-launchpad:cleanup` | launchpad | launchpad | | `galachain-launchpad:watch-token-launches` | launchpad | launchpad | | `galachain-launchpad:create-moderator-invite` | launchpad | launchpad | | `galachain-launchpad:claim-moderator-invite` | launchpad | launchpad | | `galachain-launchpad:list-moderator-invites` | launchpad | launchpad | | `galachain-launchpad:show-moderator-invite` | launchpad | launchpad | | `galachain-launchpad:revoke-moderator-invite` | launchpad | launchpad | | `galachain-launchpad:get-moderated-tokens` | launchpad | launchpad | | `galachain-launchpad:create-ban` | launchpad | launchpad | | `galachain-launchpad:remove-ban` | launchpad | launchpad | | `galachain-launchpad:list-bans` | launchpad | launchpad | | `galachain-launchpad:check-ban-status` | launchpad | launchpad | | `galachain-launchpad:get-active-users` | launchpad | launchpad | | `galachain-launchpad:create-api-key` | launchpad | launchpad | | `galachain-launchpad:list-api-keys` | launchpad | launchpad | | `galachain-launchpad:get-api-key` | launchpad | launchpad | | `galachain-launchpad:update-api-key` | launchpad | launchpad | | `galachain-launchpad:revoke-api-key` | launchpad | launchpad | | `galachain-launchpad:get-api-key-roles` | launchpad | launchpad | | `galachain-launchpad:create-overseer-invite` | launchpad | launchpad | | `galachain-launchpad:claim-overseer-invite` | launchpad | launchpad | | `galachain-launchpad:list-overseer-invites` | launchpad | launchpad | | `galachain-launchpad:show-overseer-invite` | launchpad | launchpad | | `galachain-launchpad:revoke-overseer-invite` | launchpad | launchpad | | `galachain-launchpad:list-overseers` | launchpad | launchpad | | `galachain-launchpad:revoke-overseer` | launchpad | launchpad | | `galachain-launchpad:my-overseer-status` | launchpad | launchpad | | `galachain-launchpad:start-stream` | launchpad | launchpad | | `galachain-launchpad:stop-stream` | launchpad | launchpad | | `galachain-launchpad:reset-stream-key` | launchpad | launchpad | | `galachain-launchpad:get-stream-recordings` | launchpad | launchpad | | `galachain-launchpad:get-recording-download` | launchpad | launchpad | | `galachain-launchpad:delete-recording` | launchpad | launchpad | | `galachain-launchpad:get-simulcast-targets` | launchpad | launchpad | | `galachain-launchpad:add-simulcast-target` | launchpad | launchpad | | `galachain-launchpad:remove-simulcast-target` | launchpad | launchpad | | `galachain-launchpad:get-global-streaming-status` | launchpad | launchpad | | `galachain-launchpad:set-global-streaming-enabled` | launchpad | launchpad | | `galachain-launchpad:disable-stream` | launchpad | launchpad | | `galachain-launchpad:enable-stream` | launchpad | launchpad | | `galachain-launchpad:get-stream-role` | launchpad | launchpad | | `galachain-launchpad:get-available-roles` | launchpad | launchpad | | `galachain-launchpad:get-token-access` | launchpad | launchpad | | `galachain-launchpad:get-chat-status` | launchpad | launchpad | | `galachain-launchpad:enable-chat` | launchpad | launchpad | | `galachain-launchpad:disable-chat` | launchpad | launchpad | | `galachain-launchpad:connect-stream-websocket` | launchpad | launchpad | | `galachain-launchpad:subscribe-to-stream` | launchpad | launchpad | | `galachain-launchpad:send-stream-chat-websocket` | launchpad | launchpad | | `galachain-launchpad:send-stream-reaction` | launchpad | launchpad | | `galachain-launchpad:send-typing-indicator` | launchpad | launchpad | | `galachain-launchpad:get-chat-messages` | launchpad | launchpad | | `galachain-launchpad:send-chat-message` | launchpad | launchpad | | `galachain-launchpad:delete-chat-message` | launchpad | launchpad | | `galachain-launchpad:add-content-reaction` | launchpad | launchpad | | `galachain-launchpad:remove-content-reaction` | launchpad | launchpad | | `galachain-launchpad:add-reaction-to-chat-message` | launchpad | launchpad | | `galachain-launchpad:remove-reaction-from-chat-message` | launchpad | launchpad | | `galachain-launchpad:add-reaction-to-comment` | launchpad | launchpad | | `galachain-launchpad:remove-reaction-from-comment` | launchpad | launchpad | | `galachain-launchpad:get-comments` | launchpad | launchpad | | `galachain-launchpad:create-comment` | launchpad | launchpad | | `galachain-launchpad:update-comment` | launchpad | launchpad | | `galachain-launchpad:delete-comment` | launchpad | launchpad | | `galachain-launchpad:fetch-referral-url` | launchpad | launchpad | | `galachain-launchpad:fetch-referrals` | launchpad | launchpad | | `galachain-launchpad:fetch-all-referrals` | launchpad | launchpad | | `galachain-launchpad:fetch-referrals-summary` | launchpad | launchpad | | `galachain-launchpad:subscribe-token-creations` | launchpad | launchpad | | `galachain-launchpad:login` | launchpad | launchpad | | `galachain-launchpad:logout` | launchpad | launchpad | | `galachain-launchpad:session-status` | launchpad | launchpad | | `galachain-launchpad:refresh-token` | launchpad | launchpad | | `galachain-launchpad:ensure-valid-token` | launchpad | launchpad | | `galachain-launchpad:flag-content` | launchpad | launchpad | | `galachain-launchpad:list-flags` | launchpad | launchpad | | `galachain-launchpad:dismiss-flag` | launchpad | launchpad | | `galachain-launchpad:action-flag` | launchpad | launchpad | | `galachain-launchpad:list-global-flags` | launchpad | launchpad | | `galachain-launchpad:my-trades` | launchpad | core, launchpad | | `galachain-launchpad:token-trade-activity` | launchpad | launchpad | | `galachain-launchpad:update-chat-message` | launchpad | launchpad | | `galachain-launchpad:token-chat` | launchpad | launchpad | | `galachain-launchpad:ban-token` | launchpad | launchpad | | `galachain-launchpad:unban-token` | launchpad | launchpad | | `galachain-launchpad:list-token-bans` | launchpad | launchpad | | `galachain-launchpad:check-token-banned` | launchpad | launchpad | | `galachain-launchpad:get-token-ban` | launchpad | launchpad | | `galachain-launchpad:burn-tokens-batch` | launchpad | launchpad | | `galachain-launchpad:get-managed-tokens` | launchpad | launchpad | | `galachain-launchpad:get-ai-moderation-settings` | launchpad | launchpad | | `galachain-launchpad:update-ai-moderation-settings` | launchpad | launchpad | | `galachain-launchpad:get-ai-moderation-result` | launchpad | launchpad | | `galachain-launchpad:trigger-ai-moderation` | launchpad | launchpad | | `galachain-launchpad:get-ai-moderation-status` | launchpad | launchpad | | `galachain-launchpad:weekly-challenge-leaderboard` | launchpad | launchpad | | `galachain-launchpad:token-weekly-history` | launchpad | launchpad | | `galachain-launchpad:platform-stats` | launchpad | launchpad | | `galachain-launchpad:get-restricted-names` | launchpad | launchpad | | `galachain-launchpad:update-restricted-names` | launchpad | launchpad | | `galachain-launchpad:get-connected-clients` | launchpad | launchpad | | `galachain-launchpad:is-user-online` | launchpad | launchpad | | `galachain-launchpad:get-online-users` | launchpad | launchpad | | `galachain-launchpad:get-token-viewers` | launchpad | launchpad | | `galachain-launchpad:get-online-overseers` | launchpad | launchpad | | `galachain-launchpad:emit-trade-executed` | launchpad | launchpad | | `galachain-launchpad:emit-balance-updated` | launchpad | launchpad | | `galachain-launchpad:emit-stream-status` | launchpad | launchpad | | `galachain-launchpad:emit-viewer-count` | launchpad | launchpad | | `galachain-launchpad:emit-stream-countdown` | launchpad | launchpad | | `galachain-launchpad:emit-chat-message` | launchpad | launchpad | | `galachain-launchpad:emit-chat-status` | launchpad | launchpad | | `galachain-launchpad:emit-typing-indicator` | launchpad | launchpad | | `galachain-launchpad:emit-token-banned` | launchpad | launchpad | | `galachain-launchpad:emit-token-unbanned` | launchpad | launchpad | | `galachain-launchpad:emit-moderator-added` | launchpad | launchpad | | `galachain-launchpad:emit-moderator-removed` | launchpad | launchpad | | `galachain-launchpad:emit-user-profile-updated` | launchpad | launchpad | | `galachain-launchpad:emit-site-config-changed` | launchpad | launchpad | | `galachain-launchpad:emit-feature-status` | launchpad | launchpad | | `galachain-launchpad:emit-websocket-event` | launchpad | launchpad | | `galachain-launchpad:home-oembed` | launchpad | launchpad | | `galachain-launchpad:pool-oembed` | launchpad | launchpad | | `galachain-launchpad:profile-oembed` | launchpad | launchpad | | `galachain-launchpad:fetch-messages` | launchpad | launchpad | | `galachain-launchpad:create-message` | launchpad | launchpad | | `galachain-launchpad:update-message` | launchpad | launchpad | | `galachain-launchpad:delete-message` | launchpad | launchpad | | `galachain-launchpad:get-pinned-message` | launchpad | launchpad | | `galachain-launchpad:pin-message` | launchpad | launchpad | | `galachain-launchpad:unpin-message` | launchpad | launchpad | | `galachain-launchpad:message-stats` | launchpad | launchpad | | `galachain-launchpad:get-holder-rank` | launchpad | launchpad | | `galachain-launchpad:get-top-holders` | launchpad | launchpad | | `galachain-launchpad:get-holder-count` | launchpad | launchpad | | `galachain-launchpad:get-holders-by-balance` | launchpad | launchpad | | `galachain-launchpad:get-holder-history` | launchpad | launchpad | | `galachain-launchpad:global-feed-subscribe` | launchpad | launchpad | | `galachain-launchpad:global-feed-status` | launchpad | launchpad | | `galachain-launchpad:monitor-global-feed` | launchpad | launchpad | | `galachain-launchpad:discover-pools` | gswap | gswap | | `galachain-launchpad:fetch-all-pools` | gswap | gswap | | `galachain-launchpad:check-leaderboard` | gswap | gswap | | `galachain-launchpad:manage-liquidity` | gswap | gswap | | `galachain-launchpad:add-liquidity-by-price` | gswap | gswap | | `galachain-launchpad:collect-fees` | gswap | gswap | | `galachain-launchpad:remove-liquidity` | gswap | gswap | | `galachain-launchpad:optimize-liquidity` | gswap | - (names no tool) | | `galachain-launchpad:advanced-positions` | gswap | - (names no tool) | | `galachain-launchpad:liquidity-strategy` | gswap | - (names no tool) | | `galachain-launchpad:fetch-available-dex-tokens` | gswap | gswap | | `galachain-launchpad:dex-swap` | gswap | gswap | | `galachain-launchpad:get-all-swap-user-assets` | gswap | gswap | | `galachain-launchpad:fetch-composite-pool-data` | gswap | gswap | | `galachain-launchpad:calculate-dex-pool-quote` | gswap | gswap | | `galachain-launchpad:fetch-dex-pools` | gswap | gswap | | `galachain-launchpad:fetch-all-dex-pools` | gswap | gswap | | `galachain-launchpad:my-positions` | gswap | gswap | | `galachain-launchpad:add-liquidity` | gswap | gswap | | `galachain-launchpad:get-all-liquidity-positions` | gswap | gswap | | `galachain-launchpad:estimate-remove-liquidity` | gswap | gswap | | `galachain-launchpad:fetch-position-direct` | gswap | gswap | | `galachain-launchpad:fetch-gala-spot-price` | gswap | gswap | | `galachain-launchpad:watch-dex-pools` | gswap | gswap | | `galachain-launchpad:fetch-all-dex-seasons` | gswap | gswap | | `galachain-launchpad:fetch-current-dex-season` | gswap | gswap | | `galachain-launchpad:fetch-dex-leaderboard-by-season-id` | gswap | gswap | | `galachain-launchpad:fetch-current-dex-leaderboard` | gswap | gswap | | `galachain-launchpad:fetch-dex-aggregated-volume-summary` | gswap | gswap | | `galachain-launchpad:subscribe-dex-liquidity-added` | gswap | gswap | | `galachain-launchpad:subscribe-dex-liquidity-changed` | gswap | gswap | | `galachain-launchpad:subscribe-dex-liquidity-removed` | gswap | gswap | | `galachain-launchpad:subscribe-dex-pool-added` | gswap | gswap | | `galachain-launchpad:subscribe-dex-swap-executed` | gswap | gswap | | `galachain-launchpad:price-trends` | composite | composite | | `galachain-launchpad:fetch-price-history` | composite | composite | | `galachain-launchpad:fetch-current-price` | composite | composite | | `galachain-launchpad:fetch-all-price-history` | composite | composite | | `galachain-launchpad:portfolio` | composite | core, gswap, launchpad | | `galachain-launchpad:balance` | composite | core, gswap, launchpad | | `galachain-launchpad:spot-prices` | composite | gswap, launchpad | | `galachain-launchpad:fetch-token-spot-price` | composite | composite | | `galachain-launchpad:subscribe-to-event` | composite | gswap, launchpad | ## explain_sdk_usage topics (68) The tool is in `core`; a topic is offered only when every tool it names is registered. | topic | group | toolsets of the tools it names | | --- | --- | --- | | `advanced-dex-analysis` | gswap | gswap | | `ai-moderation` | launchpad | launchpad | | `api-key-management` | launchpad | launchpad | | `balances` | launchpad | core, launchpad | | `ban-management` | launchpad | launchpad | | `bridge-operations` | core | core | | `buy-tokens` | launchpad | launchpad | | `chat-messages` | launchpad | launchpad | | `comments` | launchpad | launchpad | | `content-flag-management` | launchpad | launchpad | | `content-reactions` | launchpad | launchpad | | `dex-token-discovery` | gswap | gswap | | `dex-trading` | gswap | gswap | | `error-handling` | launchpad | launchpad | | `event-subscriptions` | launchpad | launchpad | | `events-tracking` | launchpad | core, launchpad | | `fetch-all-dex-seasons` | gswap | gswap | | `fetch-current-dex-leaderboard` | gswap | gswap | | `fetch-current-dex-season` | gswap | gswap | | `fetch-dex-aggregated-volume-summary` | gswap | gswap | | `fetch-dex-leaderboard-by-season-id` | gswap | gswap | | `fetch-dex-pools` | gswap | gswap | | `fetch-pools` | composite | composite, launchpad | | `global-bans` | launchpad | launchpad | | `global-feed-subscription` | launchpad | launchpad | | `graduation-detection` | launchpad | launchpad | | `holders` | launchpad | launchpad | | `installation` | launchpad | core, launchpad | | `liquidity-positions` | gswap | gswap | | `local-calculations` | launchpad | launchpad | | `locks` | launchpad | launchpad | | `mcp-to-sdk-mapping` | launchpad | core, launchpad | | `messages` | launchpad | launchpad | | `moderator-invites` | launchpad | launchpad | | `multi-wallet` | core | core | | `nft-collection-management` | launchpad | launchpad | | `notifications` | launchpad | launchpad | | `oembed` | launchpad | launchpad | | `overseer-invites` | launchpad | launchpad | | `platform-stats` | launchpad | launchpad | | `pool-graduation` | launchpad | launchpad | | `price-history` | composite | composite | | `profile-management` | launchpad | launchpad | | `queued-swap-recovery` | gswap | gswap | | `recent-trades` | launchpad | launchpad | | `referral-system` | launchpad | launchpad | | `restricted-names` | launchpad | launchpad | | `sell-tokens` | launchpad | launchpad | | `session-auth` | launchpad | launchpad | | `spot-prices-smart-routing` | composite | composite, gswap | | `stream-chat` | launchpad | launchpad | | `streaming` | launchpad | launchpad | | `token-ban-management` | launchpad | launchpad | | `token-creation` | launchpad | launchpad | | `token-details` | launchpad | launchpad | | `token-distribution` | launchpad | launchpad | | `token-identification` | composite | composite, launchpad | | `token-status` | launchpad | launchpad | | `trade-history` | launchpad | launchpad | | `trading-analytics` | launchpad | launchpad | | `trading-quotes` | launchpad | launchpad | | `transfers` | launchpad | core, launchpad | | `utilities-and-helpers` | launchpad | launchpad | | `utilities-system` | launchpad | core, launchpad | | `wallet-connect` | core | core | | `websocket-admin` | launchpad | launchpad | | `weekly-challenge` | launchpad | launchpad | | `wrap-unwrap-operations` | core | core | --- # core toolset: tools and prompts The `core` toolset of `@gala-chain/gala-mcp-server` 1.0.0-rc.9 provides wallet and key management, GALA balance and transfer, cross-chain bridging, wrap and unwrap, session and cache tools, and the SDK-usage and docs-search tools. It defines 47 tools and 30 prompts. A prompt is offered only when every tool it names is registered by the selection. The same data, with every parameter's type and description, is at `/mcp/core/tools.json`. `*` marks a required parameter. Tools whose description says they need authentication need a wallet in full-access mode. ## Tools ### create | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_create_wallet` | Create a new wallet with a random private key | no | - | | `gala_launchpad_create_solana_wallet` | Create a new Solana wallet with a random keypair | no | - | ### get | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_get_address` | Get the GalaChain address format (eth\|...) for the authenticated wallet | no | - | | `gala_launchpad_get_ethereum_address` | Get the standard Ethereum address format (0x...) for the authenticated wallet | no | - | | `gala_launchpad_get_public_key_from_private_key` | Derive public key from private key using secp256k1 | no | `privateKey`* | | `gala_launchpad_get_ethereum_address_from_private_key` | Derive Ethereum address from private key | no | `privateKey`* | | `gala_launchpad_get_version` | Get SDK and MCP server version information | no | - | | `gala_launchpad_get_wallet` | Get the wallet instance currently configured in the SDK | no | - | | `gala_launchpad_get_environment` | Get the current environment (`prod` or `stage`) that the MCP server is using | no | - | | `gala_launchpad_get_bridge_status` | Get the status of a bridge transaction by transaction hash | no | `transactionHash`* | | `gala_launchpad_get_supported_bridge_tokens` | Get list of tokens supported for bridging, optionally filtered by chain | no | `chain` | | `gala_launchpad_get_solana_transaction_status` | Get the status of a Solana transaction by signature | no | `signature`* | | `gala_launchpad_get_ethereum_transaction_status` | Get the status of an Ethereum transaction by hash | no | `transactionHash`* | | `gala_launchpad_get_wrappable_token` | Get a wrappable token by its tokenId | no | `tokenId`* | | `gala_launchpad_get_wrap_counterpart` | Get the wrap counterpart for a token | no | `tokenId`* | ### has | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_has_wallet` | Check if wallet is configured in the SDK | no | - | ### set | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_set_wallet` | Configure a wallet for signing operations | no | `privateKey`* | ### switch | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_switch_environment` | Dynamically switch the MCP server to `prod` or `stage` | no | `environment`* | ### fetch | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_fetch_gala_balance` | Get GALA balance for a wallet | no | `address` | | `gala_launchpad_fetch_ethereum_wallet_token_balance` | Get a single ERC-20 token balance on Ethereum (GALA, GWETH, GUSDC, GUSDT, GWTRX, GWBTC) | no | `symbol`*, `address` | | `gala_launchpad_fetch_ethereum_wallet_native_balance` | Get native ETH balance on Ethereum | no | `address` | | `gala_launchpad_fetch_ethereum_wallet_all_balances` | Get ALL supported token balances on Ethereum for a wallet (ETH, GALA, GWETH, GUSDC, GUSDT, GWTRX, GWBTC) | no | `address` | | `gala_launchpad_fetch_solana_wallet_token_balance` | Get a single SPL token balance on Solana (GALA, GSOL) | no | `symbol`*, `address` | | `gala_launchpad_fetch_solana_wallet_native_balance` | Get native SOL balance on Solana | no | `address` | | `gala_launchpad_fetch_solana_wallet_all_balances` | Get ALL supported token balances on Solana for a wallet (SOL, GALA, GSOL) | no | `address` | | `gala_launchpad_fetch_bridgeable_tokens_by_network` | Fetch bridgeable tokens for a specific network with pagination | no | `network`*, `cursor`, `pageSize` | | `gala_launchpad_fetch_all_bridgeable_tokens_by_network` | Fetch ALL bridgeable tokens for a network with auto-pagination | no | `network`* | | `gala_launchpad_fetch_all_tokens_bridgeable_to_ethereum` | Fetch all tokens that can be bridged to Ethereum | no | - | | `gala_launchpad_fetch_all_tokens_bridgeable_to_solana` | Fetch all tokens that can be bridged to Solana | no | - | | `gala_launchpad_fetch_wrappable_tokens` | Fetch wrappable tokens with pagination | no | `cursor`, `pageSize` | | `gala_launchpad_fetch_all_wrappable_tokens` | Fetch ALL wrappable tokens with auto-pagination | no | - | ### transfer | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_transfer_gala` | Transfer GALA tokens via GalaChain | no | `recipientAddress`*, `amount`*, `uniqueKey`, `privateKey` | ### estimate | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_estimate_bridge_fee` | Estimate bridge fees for transferring tokens between GalaChain and an external chain | no | `tokenId`*, `destinationChain`* | | `gala_launchpad_estimate_wrap_fee` | Estimate fees for wrapping a token to the asset channel | no | `tokenId`*, `amount`* | | `gala_launchpad_estimate_unwrap_fee` | Estimate fees for unwrapping a token back to its native channel | no | `tokenId`*, `amount`* | ### bridge | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_bridge_out` | Bridge tokens from GalaChain to an external chain (Ethereum or Solana) | no | `tokenId`*, `amount`*, `destinationChain`*, `recipientAddress`* | | `gala_launchpad_bridge_in` | Bridge tokens from an external chain (Ethereum or Solana) to GalaChain | no | `tokenId`*, `amount`*, `sourceChain`* | ### is | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_is_token_bridgeable_to_network` | Check if a token is bridgeable to a specific network | no | `tokenId`*, `network`* | | `gala_launchpad_is_token_bridgeable_to_ethereum` | Check if a token is bridgeable to Ethereum | no | `tokenId`* | | `gala_launchpad_is_token_bridgeable_to_solana` | Check if a token is bridgeable to Solana | no | `tokenId`* | | `gala_launchpad_is_token_wrappable` | Check if a token is wrappable | no | `tokenId`* | ### request | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_request_solana_devnet_airdrop` | Request SOL airdrop from Solana devnet faucet | no | `amount`, `address` | ### wrap | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_wrap_token` | Wrap a token to its asset-channel counterpart (e.g., MUSIC → GMUSIC) | no | `tokenId`*, `amount`*, `recipient` | ### unwrap | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_unwrap_token` | Unwrap a token back to its native channel (e.g., GMUSIC → MUSIC) | no | `tokenId`*, `amount`*, `recipient` | ### search | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_search_gala_docs` | Search the Gala SDK documentation (gala-core-sdk, gswap-sdk, launchpad-sdk, gala-mcp-server) and get the pages to read, with their raw markdown urls and a matching snippet | no | `query`*, `package`, `limit` | ### describe | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_describe_endpoint` | Describe an HTTP endpoint from the published OpenAPI references | no | `service`, `operationId`, `path`, `method`, `query` | ### explain | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_explain_sdk_usage` | Get detailed SDK code examples for 324 MCP tools across 68 composite v7 SDK topics, including flat LaunchpadSDK methods, the gswap-sdk GSwap client, queued swap recovery, streaming, moderation, comments, chat messages, and notifications | no | `topic`* | ## Prompts | Prompt | Tier | What it does | Arguments | Tools it names | | --- | --- | --- | --- | --- | | `galachain-launchpad:discover-bridgeable-tokens` | legacy | Find which tokens can bridge to Ethereum or Solana | `network`* | `gala_launchpad_estimate_bridge_fee`, `gala_launchpad_fetch_all_tokens_bridgeable_to_ethereum` | | `galachain-launchpad:bridge-status` | legacy | Check the status of an ongoing bridge transaction | `txId`* | `gala_launchpad_get_bridge_status` | | `galachain-launchpad:estimate-fee` | legacy | Calculate bridge or wrap/unwrap fees before executing | `operation`*, `network`, `tokenId`*, `amount`* | `gala_launchpad_estimate_bridge_fee`, `gala_launchpad_estimate_unwrap_fee`, `gala_launchpad_estimate_wrap_fee`, `gala_launchpad_fetch_gala_balance` | | `galachain-launchpad:version` | legacy | Get SDK and MCP server version information | - | `gala_launchpad_get_version` | | `galachain-launchpad:switch-environment` | legacy | Switch the MCP server to a different environment (`prod` or `stage`) | `environment` | `gala_launchpad_get_environment`, `gala_launchpad_switch_environment` | | `galachain-launchpad:create-wallet` | legacy | Generate a new wallet with random private key | - | `gala_launchpad_create_wallet` | | `galachain-launchpad:get-address` | legacy | Get the GalaChain address format of authenticated wallet | - | `gala_launchpad_get_address` | | `galachain-launchpad:get-ethereum-address` | legacy | Get the standard Ethereum address format of authenticated wallet | - | `gala_launchpad_get_ethereum_address` | | `galachain-launchpad:get-public-key-from-private-key` | legacy | Derive public key from private key using secp256k1 elliptic curve | `privateKey`* | `gala_launchpad_get_public_key_from_private_key` | | `galachain-launchpad:get-ethereum-address-from-private-key` | legacy | Derive Ethereum and GalaChain addresses from a private key | `privateKey`* | `gala_launchpad_get_ethereum_address_from_private_key` | | `galachain-launchpad:explain-sdk-usage` | legacy | Get detailed SDK usage examples for a topic | `topic`* | `gala_launchpad_explain_sdk_usage` | | `galachain-launchpad:has-wallet` | legacy | Check if a wallet is configured in the MCP server | - | `gala_launchpad_has_wallet` | | `galachain-launchpad:get-wallet` | legacy | Get the currently configured wallet instance | - | `gala_launchpad_get_wallet` | | `galachain-launchpad:set-wallet` | legacy | Configure a wallet for signing operations | `privateKey`* | `gala_launchpad_set_wallet` | | `galachain-launchpad:get-environment` | legacy | Get the current MCP server environment | - | `gala_launchpad_get_environment` | | `galachain-launchpad:bridge-fee` | legacy | Estimate fees for bridging tokens to Ethereum or Solana | `tokenSymbol`*, `destinationChain`*, `amount` | `gala_launchpad_estimate_bridge_fee` | | `galachain-launchpad:bridge-out` | legacy | Bridge tokens from GalaChain to Ethereum or Solana | `tokenSymbol`*, `amount`*, `destinationChain`*, `recipientAddress`* | `gala_launchpad_bridge_out` | | `galachain-launchpad:bridge-in` | legacy | Bridge tokens from Ethereum or Solana to GalaChain | `tokenSymbol`*, `amount`*, `sourceChain`* | `gala_launchpad_bridge_in` | | `galachain-launchpad:eth-token-balance` | legacy | Get single ERC-20 token balance on Ethereum (GALA, GWETH, GUSDC, GUSDT, GWTRX, GWBTC) | `address`, `symbol`* | `gala_launchpad_fetch_ethereum_wallet_token_balance` | | `galachain-launchpad:eth-native-balance` | legacy | Get native ETH balance on Ethereum | `address` | `gala_launchpad_fetch_ethereum_wallet_native_balance` | | `galachain-launchpad:sol-token-balance` | legacy | Get single SPL token balance on Solana (GALA, GSOL) | `address`, `symbol`* | `gala_launchpad_fetch_solana_wallet_token_balance` | | `galachain-launchpad:sol-native-balance` | legacy | Get native SOL balance on Solana | `address` | `gala_launchpad_fetch_solana_wallet_native_balance` | | `galachain-launchpad:eth-all-balances` | legacy | Get ALL supported token balances on Ethereum (ETH + GALA, GWETH, GUSDC, GUSDT, GWTRX, GWBTC) | `address` | `gala_launchpad_fetch_ethereum_wallet_all_balances` | | `galachain-launchpad:sol-all-balances` | legacy | Get ALL supported token balances on Solana (SOL + GALA, GSOL) | `address` | `gala_launchpad_fetch_solana_wallet_all_balances` | | `galachain-launchpad:create-solana-wallet` | legacy | Create a new Solana wallet with a random keypair | - | `gala_launchpad_create_solana_wallet` | | `galachain-launchpad:my-address` | legacy | Get the wallet address configured in the SDK | - | `gala_launchpad_get_address`, `gala_launchpad_get_ethereum_address` | | `galachain-launchpad:derive-address` | legacy | Derive wallet address and public key from a private key | `privateKey`* | `gala_launchpad_get_ethereum_address_from_private_key`, `gala_launchpad_get_public_key_from_private_key` | | `galachain-launchpad:wallet-status` | legacy | Check if a wallet is configured for signing operations | - | `gala_launchpad_get_wallet`, `gala_launchpad_has_wallet` | | `galachain-launchpad:fetch-gala-balance` | legacy | Get GALA balance for a wallet | `address` | `gala_launchpad_fetch_gala_balance` | | `galachain-launchpad:transfer-gala` | legacy | Transfer GALA tokens to another wallet | `recipientAddress`*, `amount`* | `gala_launchpad_transfer_gala` | --- # launchpad toolset: tools and prompts The `launchpad` toolset of `@gala-chain/gala-mcp-server` 1.0.0-rc.9 provides Launchpad pools, bonding-curve trading, token creation, holders, streaming, chat, moderation, overseers and the rest of the Launchpad backend. It defines 242 tools and 213 prompts. A prompt is offered only when every tool it names is registered by the selection. The same data, with every parameter's type and description, is at `/mcp/launchpad/tools.json`. `*` marks a required parameter. Tools whose description says they need authentication need a wallet in full-access mode. ## Tools ### fetch | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_fetch_pools` | Fetch token pools from Gala Launchpad with filtering and pagination | no | `type`, `creatorAddress`, `isGraduated`, `hasUpcomingShows`, `language`, `recentlyStreamed`, `hasRecordings`, `streamStatus`, `cursor`, `pageSize` | | `gala_launchpad_fetch_all_pools` | Fetch all available pools with automatic pagination | no | `tokenName`, `type`, `creatorAddress`, `isGraduated`, `hasUpcomingShows`, `language`, `recentlyStreamed`, `hasRecordings`, `streamStatus` | | `gala_launchpad_fetch_pool_details` | Get detailed pool state from GalaChain bonding curve | no | `tokenName`* | | `gala_launchpad_fetch_pool_details_for_calculation` | Get optimized pool details for local bonding curve calculations | no | `tokenName`* | | `gala_launchpad_fetch_token_details` | Fetch comprehensive token details from DEX API platform | no | `tokenId`* | | `gala_launchpad_fetch_token_distribution` | Get holder distribution and supply metrics | no | `tokenName`* | | `gala_launchpad_fetch_user_holder_context` | Get a user's holder context for a specific token | no | `tokenName`*, `userAddress`* | | `gala_launchpad_fetch_volume_data` | Get OHLCV (candlestick) data for charting | no | `tokenName`*, `from`, `to`, `resolution` | | `gala_launchpad_fetch_launchpad_token_spot_price` | ⚠️ **DEPRECATED** - Use gala_launchpad_fetch_token_spot_price with { tokenName } instead | no | `tokenName`*, `calculateAmountMode`, `currentSupply` | | `gala_launchpad_fetch_token_classes_with_supply` | Fetch supply metrics for multiple token classes in a single batch query | no | `tokenClasses`* | | `gala_launchpad_fetch_trades` | Get trade history with optional filtering and pagination | no | `tokenName`, `tradeType`, `userAddress`, `cursor`, `pageSize`, `startDate`, `endDate`, `sortOrder` | | `gala_launchpad_fetch_launchpad_fee` | Fetch the current launchpad fee via backend proxy (cached 1 hour) | no | - | | `gala_launchpad_fetch_sale_details` | Fetch sale details (supply, status) for a token via backend proxy (cached 10s) | no | `tokenName`* | | `gala_launchpad_fetch_token_balance` | Get token balance for a specific token | no | `tokenName`*, `address`* | | `gala_launchpad_fetch_locked_tokens` | Get locked token details including all active locks, lock authorities, and expiration times | no | `tokenName`*, `address`*, `withExpired` | | `gala_launchpad_fetch_tokens_held` | Get tokens held by a wallet with optional filtering | no | `address`*, `cursor`, `pageSize`, `tokenName`, `search` | | `gala_launchpad_fetch_tokens_created` | Get tokens created by a wallet with optional filtering | no | `address`*, `cursor`, `pageSize`, `tokenName`, `search` | | `gala_launchpad_fetch_profile` | Get user profile data including full name, profile image, wallet address, and join date | no | `address` | | `gala_launchpad_fetch_available_balance` | Get available (unlocked) token balance for a wallet | no | `tokenName`*, `address`* | | `gala_launchpad_fetch_referral_url` | Fetch the authenticated user's unique referral URL for sharing | no | - | | `gala_launchpad_fetch_referrals` | Fetch paginated list of users who signed up using this wallet's referral link using cursor-based pagination | no | `address`, `cursor`, `pageSize`, `sortBy`, `sortDir` | | `gala_launchpad_fetch_all_referrals` | Fetch all referrals for a wallet address with automatic pagination | no | `address`, `sortBy`, `sortDir` | | `gala_launchpad_fetch_referrals_summary` | Fetch referral program summary statistics including total referral count and reward totals (past day, past month, all-time) | no | `address` | | `gala_launchpad_fetch_launch_token_fee` | Fetch the current GALA fee required to launch a new token on the launchpad | no | - | | `gala_launchpad_fetch_nft_collections` | Fetch all NFT collections authorized to a wallet address | no | `walletAddress`* | | `gala_launchpad_fetch_nft_token_classes` | Fetch token classes for a collection with supply information | no | `collection`*, `type`, `category` | | `gala_launchpad_fetch_nft_balances` | Fetch NFT balances for an owner, optionally filtered by collection | no | `ownerAddress`*, `collectionFilter` | | `gala_launchpad_fetch_messages` | Query messages with type/tokenName/userAddress filters | yes | `type`, `tokenName`, `userAddress`, `search`, `cursor`, `pageSize` | | `gala_launchpad_fetch_notification_preferences` | Get notification preferences for the authenticated user | no | - | | `gala_launchpad_fetch_client_flags` | Get client feature flags for the native mobile app | no | - | ### check | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_check_token_name` | Check if token name is available | no | `tokenName`* | | `gala_launchpad_check_token_symbol` | Check if token symbol is available | no | `symbol`* | | `gala_launchpad_check_pool_exists` | Check if a pool exists for a token | no | `tokenName`, `symbol` | | `gala_launchpad_check_nft_collection_available` | Check if an NFT collection name is available for claiming | no | `collectionName`* | ### validate | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_validate_token` | Validate if token name and/or symbol are available for use | no | `tokenName`, `symbol` | ### resolve | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_resolve_vault_address` | **DO NOT GUESS** - Resolve a launchpad token name to its GalaChain vault address | no | `tokenName`* | | `gala_launchpad_resolve_token_class_key` | **MANDATORY** - Convert a launchpad token name to its GalaChain TokenClassKey | no | `tokenName`* | ### on | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_on_launchpad_token_creation` | Watch for new launchpad token creation events in real-time | no | `creatorAddress`, `intervalMs`, `durationSeconds` | | `gala_launchpad_on_pool_updated` | Watch for pool metadata updates in real-time | no | `tokenName`*, `updateType`, `intervalMs`, `durationSeconds` | | `gala_launchpad_on_holder_count_changed` | Watch for token holder count changes in real-time | no | `tokenName`*, `minThreshold`, `intervalMs`, `durationSeconds` | | `gala_launchpad_on_ban_enforcement` | Watch for user ban enforcement events in real-time | no | `userAddress`, `actionType`, `tokenName`, `reason`, `intervalMs`, `durationSeconds` | | `gala_launchpad_on_moderator_changed` | Watch for moderator management events in real-time | no | `tokenName`*, `eventType`, `moderatorAddress`, `intervalMs`, `durationSeconds` | | `gala_launchpad_on_token_ban_changed` | Watch for token ban and unban events in real-time | no | `tokenName`*, `banStatus`, `intervalMs`, `durationSeconds` | | `gala_launchpad_on_trade_executed` | Watch for new trade execution events in real-time | no | `tokenName`*, `tradeType`, `minAmount`, `userAddress`, `intervalMs`, `durationSeconds` | | `gala_launchpad_on_comment_created` | Watch for new pool comments in real-time | no | `tokenName`*, `authorAddress`, `minLength`, `intervalMs`, `durationSeconds` | ### get | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_get_pool_realtime_state` | Get a combined real-time snapshot of a pool | no | `tokenName`* | | `gala_launchpad_get_bundler_transaction_result` | Get bundle transaction result by ID via HTTP (not WebSocket) | no | `transactionId`* | | `gala_launchpad_get_trade_quote` | Calculate trade quote via backend using local bonding curve math (no chain call) | no | `tokenName`*, `amount`*, `type`*, `method`* | | `gala_launchpad_get_premint_quote` | Calculate pre-mint token output for a given GALA amount (supply = 0 assumed) | no | `amount`* | | `gala_launchpad_get_managed_tokens` | Fetch all tokens the authenticated user can manage (owned tokens + moderated tokens + overseer status) | no | `cursor`, `pageSize` | | `gala_launchpad_get_nft_collection_claim_fee` | Get the fee required to claim an NFT collection name | no | - | | `gala_launchpad_get_nft_token_class_create_fee` | Get the fee required to create a token class | no | - | | `gala_launchpad_get_config` | Get the current SDK configuration including environment, base URLs, timeouts, feature flags, effective slippage tolerance factors, GalaChain gas fee (fixed at 1 GALA), and current MCP server environment state | no | - | | `gala_launchpad_get_url_by_token_name` | Get the launchpad frontend URL for a specific token | no | `tokenName`* | | `gala_launchpad_get_cache_info` | Get unified cache statistics for all token caches: launchpad metadata (totalTokens, cacheSize, oldestEntry) and bridgeable tokens by network (ETHEREUM, SOLANA counts) | no | - | | `gala_launchpad_get_platform_status` | Get platform-wide trading volume and token count | no | - | | `gala_launchpad_get_event_schema` | Get detailed schema/interface for a specific WebSocket event | no | `eventName`*, `format`, `includeExample` | | `gala_launchpad_get_global_streaming_status` | Get global streaming status | no | - | | `gala_launchpad_get_stream_role` | Get the authenticated user's role for a token's stream with associated permissions | no | `tokenName`* | | `gala_launchpad_get_available_roles` | Get all available roles and permissions for token delegation | no | - | | `gala_launchpad_get_token_access` | Check if the authenticated user has Studio access for a token | no | `tokenName`* | | `gala_launchpad_get_stream_recordings` | Get recordings for a stream | no | `tokenName`*, `cursor`, `pageSize` | | `gala_launchpad_get_recording_download` | Get a signed download URL for a recording | no | `tokenName`*, `assetId`* | | `gala_launchpad_get_simulcast_targets` | Get simulcast targets for a stream | no | `tokenName`* | | `gala_launchpad_get_chat_status` | Get chat status for a stream | no | `tokenName`* | | `gala_launchpad_get_session` | Get current session information from backend | no | - | | `gala_launchpad_get_access_token` | Check whether an access token is available | no | - | | `gala_launchpad_get_ban_status` | Check if a specific user is banned on a token | no | `tokenName`*, `userAddress`* | | `gala_launchpad_get_active_users` | Get currently active users on a token's stream | no | `tokenName`*, `type`, `search`, `name`, `userAddress` | | `gala_launchpad_get_api_key` | Get a single API key by ID | no | `id`* | | `gala_launchpad_get_api_key_roles` | Get all valid API key roles | no | - | | `gala_launchpad_get_moderated_tokens` | Get all tokens the current user moderates | no | `cursor`, `pageSize` | | `gala_launchpad_get_moderator_invite` | Get invite details by code (public endpoint) | no | `inviteCode`* | | `gala_launchpad_get_active_moderators` | Get the roster of active (already-accepted) moderators for a specific token | no | `tokenName`* | | `gala_launchpad_get_overseer_invite` | Get overseer invite details by code (public endpoint) | no | `inviteCode`* | | `gala_launchpad_get_my_overseer_status` | Check your own overseer status | no | - | | `gala_launchpad_get_overseer_summary` | Get platform summary for CCTV dashboard | no | - | | `gala_launchpad_get_ban_stats` | Get global user ban statistics | no | - | | `gala_launchpad_get_token_ban_stats` | Get token ban (delisted tokens) statistics | no | - | | `gala_launchpad_get_invite_stats` | Get overseer invite statistics | no | - | | `gala_launchpad_get_flag_stats` | Get content flag statistics | no | - | | `gala_launchpad_get_user_stats` | Get user management statistics | no | - | | `gala_launchpad_get_overseer_user_summary` | Get comprehensive user summary (Admin/Overseer only) | no | `userAddress`* | | `gala_launchpad_get_token_ban` | Get ban details for a specific token (overseer only) | no | `tokenName`* | | `gala_launchpad_get_pinned_message` | Get the currently pinned message for a token | no | `tokenName`* | | `gala_launchpad_get_message_stats` | Get platform-wide message statistics | no | - | | `gala_launchpad_get_restricted_names` | Get the restricted token names content | no | - | | `gala_launchpad_get_trades` | Query trades with flexible filtering options | yes | `tokenName`, `userAddress`, `search`, `cursor`, `pageSize`, `txnType`, `startDate`, `endDate`, `minAmount`, `maxAmount` | | `gala_launchpad_get_recent_trades` | Get the most recently executed trades with optional filtering | no | `tokenName`, `userAddress`, `tradeType`, `limit` | | `gala_launchpad_get_holder_rank` | Get a user's holder rank and balance for a token | yes | `tokenName`*, `userAddress`* | | `gala_launchpad_get_top_holders` | Get top token holders by balance | yes | `tokenName`*, `limit` | | `gala_launchpad_get_holder_count` | Get holder statistics for a token | yes | `tokenName`* | | `gala_launchpad_get_holders_by_balance` | Query holders by balance range | yes | `tokenName`*, `minBalance`, `maxBalance`, `limit` | | `gala_launchpad_get_holder_history` | Get recent trade history for a specific holder | yes | `tokenName`*, `userAddress`*, `limit`, `cursor` | | `gala_launchpad_get_connected_clients` | List currently connected WebSocket clients with optional filtering | yes | `room`, `tokenName`, `userAddress`, `userAddresses`, `authenticated`, `isOverseer`, `minConnectionSeconds`, `offset`, `limit` | | `gala_launchpad_get_online_users` | Batch check which users from a list are currently online | no | `userAddresses`* | | `gala_launchpad_get_token_viewers` | Get list of users currently viewing a specific token | no | `tokenName`*, `authenticated`, `limit` | | `gala_launchpad_get_online_overseers` | Get list of currently online overseers and admins | no | - | | `gala_launchpad_get_ai_moderation_settings` | Get current AI moderation settings | no | - | | `gala_launchpad_get_ai_moderation_result` | Get AI moderation result for a specific content flag | no | `flagId`* | | `gala_launchpad_get_ai_moderation_status` | Get AI system status | no | - | | `gala_launchpad_get_weekly_challenge_leaderboard` | Get the weekly challenge leaderboard | no | `limit` | | `gala_launchpad_get_token_weekly_history` | Get weekly snapshot history for a specific token | no | `vaultAddress`* | | `gala_launchpad_get_home_oembed` | Get oEmbed metadata for the home page | no | - | | `gala_launchpad_get_pool_oembed` | Get oEmbed metadata for a pool/token page | no | `tokenName`* | | `gala_launchpad_get_profile_oembed` | Get oEmbed metadata for a user profile page | no | `address`* | | `gala_launchpad_get_platform_stats` | Get platform-wide statistics | no | - | | `gala_launchpad_get_comments` | Query comments with tokenName/userAddress filters | yes | `tokenName`, `userAddress`, `cursor`, `pageSize` | | `gala_launchpad_get_chat_messages` | Query chat messages with tokenName/userAddress filters | yes | `tokenName`, `userAddress`, `cursor`, `pageSize` | ### update | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_update_token_config` | Update token configuration (messages, comments, and social links) | no | `tokenName`*, `messagesEnabled`, `commentsEnabled`, `streamingEnabled`, `streamLanguage`, `nextLiveStreamAt`, `websiteUrl`, `telegramUrl`, `twitterUrl`, `instagramUrl`, `facebookUrl`, `redditUrl`, `tiktokUrl` | | `gala_launchpad_update_profile` | Update user profile (fullName and profileImage) | no | `fullName`*, `profileImage`*, `address`*, `privateKey` | | `gala_launchpad_update_api_key` | Update an API key's metadata and permissions | no | `id`*, `role`, `description`, `delegateAllTokens`, `tokenNames`, `expiresAt` | | `gala_launchpad_update_moderator_invite_role` | Update the role of a moderator invite | no | `inviteId`*, `role`* | | `gala_launchpad_update_moderator_invite` | Update a moderator invite's role and/or description | no | `inviteId`*, `role`, `description` | | `gala_launchpad_update_message` | Update a message's content | no | `id`*, `content`* | | `gala_launchpad_update_restricted_names` | Update the restricted token names content | no | `content`* | | `gala_launchpad_update_ai_moderation_settings` | Update AI moderation settings | no | `enabled`, `mode`, `provider` | | `gala_launchpad_update_notification_preferences` | Update notification preferences for the authenticated user | no | `tradesEnabled`, `streamsEnabled`, `chatEnabled`, `systemEnabled` | | `gala_launchpad_update_comment` | Update a comment's content | no | `id`*, `content`* | | `gala_launchpad_update_chat_message` | Update a chat message's content (author only) | no | `id`*, `content`* | ### calculate | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_calculate_buy_amount` | Calculate token amounts for buying with fee breakdown | no | `tokenName`*, `amount`*, `type`* | | `gala_launchpad_calculate_sell_amount` | Calculate GALA amounts for selling tokens | no | `tokenName`*, `amount`*, `type`* | | `gala_launchpad_calculate_initial_buy` | Calculate amounts for initial token purchase during creation (pre-mint phase) | no | `amount`* | | `gala_launchpad_calculate_buy_amount_for_graduation` | Calculate amount needed to graduate a token pool | no | `tokenName`*, `calculateAmountMode`, `currentSupply` | | `gala_launchpad_calculate_buy_amount_local` | Calculate buy amounts using LOCAL bonding curve formulas (instant, no network call) | no | `tokenName`*, `amount`*, `type`* | | `gala_launchpad_calculate_buy_amount_external` | Calculate buy amounts using EXTERNAL GalaChain network call (real-time) | no | `tokenName`*, `amount`*, `type`* | | `gala_launchpad_calculate_sell_amount_local` | Calculate sell amounts using LOCAL bonding curve formulas (instant, no network call) | no | `tokenName`*, `amount`*, `type`*, `maxSupply`*, `reverseBondingCurveMinFeeFactor`*, `reverseBondingCurveMaxFeeFactor`* | | `gala_launchpad_calculate_sell_amount_external` | Calculate sell amounts using EXTERNAL GalaChain network call (real-time) | no | `tokenName`*, `amount`*, `type`* | ### buy | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_buy` | Execute token purchase with slippage protection | no | `tokenName`*, `amount`*, `type`*, `expectedAmount`*, `maxAcceptableReverseBondingCurveFee`, `maxAcceptableReverseBondingCurveFeeSlippageFactor`, `slippageToleranceFactor`*, `privateKey` | ### sell | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_sell` | Execute token sale with slippage protection | no | `tokenName`*, `amount`*, `type`*, `expectedAmount`*, `maxAcceptableReverseBondingCurveFee`, `maxAcceptableReverseBondingCurveFeeSlippageFactor`, `slippageToleranceFactor`*, `privateKey` | ### graduate | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_graduate_token` | Graduate a token pool by buying all remaining tokens in one transaction | no | `tokenName`*, `maxAcceptableReverseBondingCurveFeeSlippageFactor`, `slippageToleranceFactor`, `privateKey`, `calculateAmountMode`, `currentSupply` | ### launch | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_launch_token` | Create a new token on the launchpad | no | `tokenName`*, `tokenSymbol`*, `tokenDescription`*, `tokenImage`*, `preBuyQuantity`, `websiteUrl`, `telegramUrl`, `twitterUrl`, `tokenCategory`, `tokenCollection`, `reverseBondingCurveConfiguration`, `saleStartTime`, `privateKey` | ### upload | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_upload_token_image` | Upload token image from filesystem (Node.js only) | no | `tokenName`*, `imagePath`*, `privateKey` | | `gala_launchpad_upload_profile_image` | Upload profile image from filesystem (Node.js only) | no | `imagePath`*, `address`, `privateKey` | ### estimate | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_estimate_nft_mint_fee` | Estimate the dynamic fee to mint NFTs via DryRun | no | `collection`*, `type`*, `category`*, `quantity`*, `ownerAddress`* | | `gala_launchpad_estimate_nft_operation_fees` | Calculate total fees for multiple NFT operations | no | `claimCollection`, `createTokenClasses` | ### claim | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_claim_nft_collection` | Claim an NFT collection name | no | `collectionName`* | | `gala_launchpad_claim_moderator_invite` | Claim a moderator invite | no | `inviteCode`* | | `gala_launchpad_claim_overseer_invite` | Claim an overseer invite | no | `inviteCode`* | ### create | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_create_nft_token_class` | Create a token class within an NFT collection | no | `collection`*, `type`*, `category`*, `name`, `description`, `image`, `symbol`, `rarity`, `maxSupply`, `maxCapacity`, `additionalKey` | | `gala_launchpad_create_ban` | Create a ban for a user on a token | no | `tokenName`*, `userAddress`*, `reason`, `durationSeconds` | | `gala_launchpad_create_api_key` | Create a new API key for delegating permissions | no | `role`*, `description`, `delegateAllTokens`, `tokenNames`, `expiresAt` | | `gala_launchpad_create_moderator_invite` | Create a moderator invite for a token or all tokens | no | `inviteScope`, `tokenName`, `role`*, `description`, `expiresAt` | | `gala_launchpad_create_flag` | Create a content flag/report | no | `tokenName`*, `contentType`*, `contentId`*, `reportedUserAddress`*, `reason`, `details` | | `gala_launchpad_create_overseer_invite` | Create an overseer invite | no | `description`, `expiresAt` | | `gala_launchpad_create_overseer_direct` | Create an overseer directly (bypassing invite flow) | no | `userAddress`*, `description` | | `gala_launchpad_create_message` | Create a new message on a token pool | no | `type`*, `tokenName`*, `content`* | | `gala_launchpad_create_comment` | Create a new comment on a token pool | no | `tokenName`*, `content`* | ### mint | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_mint_nft` | Mint NFTs from a token class | no | `collection`*, `type`*, `category`*, `quantity`*, `ownerAddress`*, `additionalKey` | ### transfer | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_transfer_token` | Transfer launchpad tokens via GalaChain | no | `to`*, `tokenName`*, `amount`*, `uniqueKey`, `privateKey` | ### lock | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_lock_tokens` | Lock one or more token types on GalaChain in a single transaction | no | `tokens`*, `uniqueKey`, `privateKey` | ### unlock | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_unlock_tokens` | Unlock one or more previously locked token types on GalaChain in a single transaction | no | `tokens`*, `uniqueKey`, `privateKey` | ### burn | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_burn_tokens` | Permanently burn (destroy) one or more token types on GalaChain in a single transaction | no | `tokens`*, `uniqueKey`, `privateKey` | ### is | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_is_token_graduated` | Check if a token has completed the bonding curve phase and graduated to full DEX trading | no | `tokenName`* | | `gala_launchpad_is_authenticated` | Check if user is authenticated with valid (non-expired) JWT token | no | - | | `gala_launchpad_is_token_banned` | Check if a token is banned (overseer only) | no | `tokenName`* | | `gala_launchpad_is_user_online` | Check if a specific user is currently connected via WebSocket | no | `userAddress`* | ### clear | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_clear_cache` | Clear token caches | no | `tokenName` | ### cleanup | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_cleanup` | Clean up SDK resources (HTTP interceptors, WebSocket connections) | no | - | ### explain | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_explain_websocket_events` | Get comprehensive documentation of all WebSocket events | no | `category`, `format` | ### start | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_start_stream` | Start a live stream for a token | no | `tokenName`* | ### stop | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_stop_stream` | Stop a live stream for a token | no | `tokenName`* | ### set | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_set_stream_enabled` | Enable or disable streaming for a specific token (Admin only) | no | `tokenName`*, `enabled`* | | `gala_launchpad_set_next_live_stream_countdown` | Set the next live stream countdown time for a token | no | `tokenName`*, `nextLiveStreamAt`* | | `gala_launchpad_set_global_streaming_enabled` | Enable or disable streaming globally (Admin only) | no | `enabled`* | | `gala_launchpad_set_chat_enabled` | Enable or disable chat for a specific token | no | `tokenName`*, `enabled`* | | `gala_launchpad_set_slow_mode` | Set slow mode interval for a stream chat | no | `tokenName`*, `slowModeSeconds`* | ### reset | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_reset_stream_key` | Reset the stream key for a token | no | `tokenName`* | ### delete | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_delete_recording` | Delete a stream recording | no | `tokenName`*, `assetId`* | | `gala_launchpad_delete_message` | Delete a message | no | `id`* | | `gala_launchpad_delete_comment` | Delete a comment | no | `id`* | | `gala_launchpad_delete_chat_message` | Delete a chat message | no | `id`* | ### add | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_add_simulcast_target` | Add a simulcast target to a stream | no | `tokenName`*, `platform`*, `rtmpUrl`*, `streamKey`*, `name` | | `gala_launchpad_add_content_reaction` | Add a reaction to a pool message (chat or comment) | yes | `tokenName`, `messageId`*, `reactionType`* | | `gala_launchpad_add_reaction_to_chat_message` | Add a reaction to a chat message | no | `tokenName`, `messageId`*, `reactionType`* | | `gala_launchpad_add_reaction_to_comment` | Add a reaction to a comment | no | `tokenName`, `messageId`*, `reactionType`* | ### remove | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_remove_simulcast_target` | Remove a simulcast target from a stream | no | `tokenName`*, `targetId`* | | `gala_launchpad_remove_ban` | Remove a ban for a user on a token | no | `tokenName`*, `userAddress`* | | `gala_launchpad_remove_content_reaction` | Remove a reaction from a pool message | yes | `tokenName`, `messageId`*, `reactionType`* | | `gala_launchpad_remove_reaction_from_chat_message` | Remove a reaction from a chat message | no | `tokenName`, `messageId`*, `reactionType`* | | `gala_launchpad_remove_reaction_from_comment` | Remove a reaction from a comment | no | `tokenName`, `messageId`*, `reactionType`* | ### connect | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_connect_stream_websocket` | Connect to the stream WebSocket server | yes | - | ### subscribe | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_subscribe_to_stream` | Subscribe to a stream's real-time events | no | `tokenName`* | ### send | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_send_stream_chat_via_web_socket` | Send a chat message via WebSocket | yes | `tokenName`*, `content`* | | `gala_launchpad_send_stream_reaction` | Send an ephemeral emoji reaction to a live stream | yes | `tokenName`*, `emoji`*, `streamTime` | | `gala_launchpad_send_typing_indicator` | Send a typing indicator to a stream chat | yes | `tokenName`*, `isTyping`* | | `gala_launchpad_send_chat_message` | Send a new chat message on a token pool | no | `tokenName`*, `content`* | ### login | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_login` | Authenticate with wallet signature to get JWT token | no | - | ### logout | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_logout` | Clear JWT token and end session | no | - | ### refresh | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_refresh_token` | Refresh JWT token before it expires | no | - | ### should | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_should_refresh_token` | Check if JWT token should be refreshed (expires within threshold) | no | `thresholdMs` | ### ensure | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_ensure_valid_token` | Ensure valid token exists, refreshing if necessary | no | `thresholdMs` | ### list | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_list_bans` | List all banned users for a token | no | `tokenName`*, `cursor`, `pageSize`, `search`, `name`, `userAddress` | | `gala_launchpad_list_api_keys` | List all API keys for the authenticated user | no | `cursor`, `pageSize` | | `gala_launchpad_list_moderator_invites` | List moderator invites | no | `tokenName`, `status`, `cursor`, `pageSize` | | `gala_launchpad_list_flags` | List flags for a specific token with pagination and filtering | no | `tokenName`*, `contentType`, `status`, `reason`, `reporterAddress`, `reportedUserAddress`, `cursor`, `pageSize` | | `gala_launchpad_list_global_flags` | List ALL flags globally across all tokens with pagination and filtering | no | `tokenName`, `contentType`, `status`, `reason`, `reporterAddress`, `reportedUserAddress`, `cursor`, `pageSize` | | `gala_launchpad_list_overseer_invites` | List all overseer invites with cursor-based pagination and filtering | no | `status`, `cursor`, `pageSize` | | `gala_launchpad_list_overseers` | List all overseers with cursor-based pagination and filtering | no | `status`, `cursor`, `pageSize` | | `gala_launchpad_list_overseer_users` | List users with pagination and sorting (Overseer/Admin only) | no | `search`, `sortBy`, `sortOrder`, `cursor`, `pageSize` | | `gala_launchpad_list_token_bans` | List all banned tokens (overseer only) | no | `cursor`, `pageSize`, `search` | ### revoke | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_revoke_api_key` | Revoke an API key | no | `id`* | | `gala_launchpad_revoke_moderator_invite` | Revoke a moderator invite | no | `inviteId`* | | `gala_launchpad_revoke_overseer_invite` | Revoke an overseer invite | no | `inviteId`* | | `gala_launchpad_revoke_overseer` | Revoke an overseer's access | no | `address`* | ### dismiss | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_dismiss_flag` | Dismiss a flag (no action taken) | no | `flagId`* | ### action | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_action_flag` | Take action on a flag | no | `flagId`*, `action`* | ### flush | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_flush_cache_by_address` | Flush all cache entries for a wallet address | no | `address`* | | `gala_launchpad_flush_cache_by_token` | Flush all cache entries for a token | no | `tokenName`* | | `gala_launchpad_flush_all_cache` | ⚠️ NUCLEAR OPTION: Flush ALL Launchpad cache | no | `confirm`* | | `gala_launchpad_flush_cache_wallet_aliases` | Flush wallet-alias cache entries (eth\| → client\| resolution cache) | no | `address` | ### ban | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_ban_token` | Ban a token from the platform (overseer only) | no | `tokenName`*, `reason` | ### unban | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_unban_token` | Remove a ban from a token (overseer only) | no | `tokenName`* | ### pin | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_pin_message` | Pin a message to a token's chat | no | `id`* | ### unpin | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_unpin_message` | Unpin a message from a token's chat | no | `id`* | ### global | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_global_feed_reference` | Reference: Subscribe to the global feed for real-time updates | no | - | | `gala_launchpad_global_feed_status_reference` | Reference: Check global feed subscription status | no | - | ### unsubscribe | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_unsubscribe_from_global_feed_reference` | Reference: Unsubscribe from the global feed | no | - | ### monitor | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_monitor_global_feed_events_reference` | Reference: Monitor and filter global feed events | no | - | ### site | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_site_config_state_reference` | Reference: Access site configuration state from global feed | no | - | ### emit | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_emit_trade_executed` | Emit a trade execution event to token subscribers | no | `tokenName`*, `tradeType`*, `inputAmount`*, `outputAmount`* | | `gala_launchpad_emit_balance_updated` | Emit a balance update event to a specific user | no | `userAddress`*, `tokenName`*, `galaBalance`*, `tokenBalance`*, `changeReason` | | `gala_launchpad_emit_stream_status` | Emit a stream status change event | no | `tokenName`*, `status`* | | `gala_launchpad_emit_viewer_count` | Emit a viewer count update event | no | `tokenName`*, `viewerCount`* | | `gala_launchpad_emit_stream_countdown` | Emit a stream countdown event | no | `tokenName`*, `nextLiveStreamAt`*, `secondsUntilLive` | | `gala_launchpad_emit_chat_message` | Emit a chat message event to token chat subscribers | no | `tokenName`*, `content`*, `userAddress`* | | `gala_launchpad_emit_chat_status` | Emit a chat status change event (enabled/disabled) | no | `tokenName`*, `enabled`*, `reason` | | `gala_launchpad_emit_typing_indicator` | Emit a typing indicator event | no | `tokenName`*, `typingUsers`*, `count` | | `gala_launchpad_emit_token_banned` | Emit a token banned event | no | `tokenName`*, `reason`*, `bannedBy`, `nextLiveStreamAt` | | `gala_launchpad_emit_token_unbanned` | Emit a token unbanned event | no | `tokenName`*, `reason`, `unbannedBy` | | `gala_launchpad_emit_moderator_added` | Emit a moderator added event | no | `tokenName`*, `userAddress`*, `role`*, `reason` | | `gala_launchpad_emit_moderator_removed` | Emit a moderator removed event | no | `tokenName`*, `userAddress`*, `reason` | | `gala_launchpad_emit_user_profile_updated` | Emit a user profile updated event | no | `userAddress`*, `updatedFields`, `summary` | | `gala_launchpad_emit_site_config_changed` | Emit a site configuration changed event | no | `key`*, `value`, `description` | | `gala_launchpad_emit_feature_status` | Emit a feature status changed event | no | `feature`*, `enabled`*, `reason`, `nextLiveStreamAt` | | `gala_launchpad_emit_recording_status` | Emit a recording status change event | no | `tokenName`*, `status`*, `assetId`, `playbackId`, `duration`, `playbackUrl` | | `gala_launchpad_emit_recordings_count_updated` | Emit a recordings count updated event | no | `tokenName`*, `count`*, `previousCount` | | `gala_launchpad_emit_download_ready` | Emit a download ready event | no | `tokenName`*, `assetId`*, `recordingId`*, `downloadUrl`, `fileSize`, `duration`, `readyAt`* | | `gala_launchpad_emit_websocket_event` | Emit a generic WebSocket event (advanced/custom use) | no | `action`*, `tokenName`, `userAddress`, `broadcast`, `payload` | ### trigger | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_trigger_ai_moderation` | Trigger AI moderation for a content flag | no | `flagId`* | ### register | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_register_push_token` | Register a push notification device token | no | `token`*, `platform`*, `deviceId` | ### unregister | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_unregister_push_token` | Unregister a push notification device token | no | `token`* | ## Prompts | Prompt | Tier | What it does | Arguments | Tools it names | | --- | --- | --- | --- | --- | | `galachain-launchpad:fetch-pool-details` | legacy | Get comprehensive bonding curve pool analytics - supply metrics, fees, and trading history | `tokenName`* | `gala_launchpad_fetch_pool_details_for_calculation` | | `galachain-launchpad:analyze-token` | legacy | Perform comprehensive due diligence on a token - distribution analysis, whale detection, volume trends, and key metrics | `tokenName`* | `gala_launchpad_fetch_token_details`, `gala_launchpad_fetch_token_distribution`, `gala_launchpad_fetch_volume_data` | | `galachain-launchpad:fetch-token-distribution` | legacy | Get complete token holder distribution - identify whales and analyze concentration risk | `tokenName`* | `gala_launchpad_fetch_token_distribution` | | `galachain-launchpad:fetch-volume-data` | legacy | Analyze token trading volume trends - 24h, 7d, 30d metrics for activity assessment | `tokenName`* | `gala_launchpad_fetch_volume_data` | | `galachain-launchpad:bridge-tokens` | legacy | Transfer tokens across chains - GalaChain ↔ Ethereum/Solana, wrap/unwrap, fee estimation, and status tracking | `action`*, `network`, `tokenId`, `amount`, `txId` | `gala_launchpad_bridge_out`, `gala_launchpad_estimate_bridge_fee`, `gala_launchpad_estimate_unwrap_fee`, `gala_launchpad_estimate_wrap_fee`, `gala_launchpad_fetch_token_balance`, `gala_launchpad_fetch_wrappable_tokens`, `gala_launchpad_get_bridge_status`, `gala_launchpad_is_token_bridgeable_to_network`, `gala_launchpad_unwrap_token`, `gala_launchpad_wrap_token` | | `galachain-launchpad:launch-token` | legacy | Create a new token on the launchpad with custom bonding curve, metadata, and optional pre-buy | `tokenName`*, `tokenSymbol`*, `description`*, `imageUrl`*, `minFeePortion`, `maxFeePortion`, `preBuyAmount`, `websiteUrl`, `twitterUrl`, `telegramUrl` | - | | `galachain-launchpad:graduate-token` | legacy | Graduate a token pool by buying all remaining tokens and transitioning to full DEX trading | `tokenName`*, `slippageTolerance` | - | | `galachain-launchpad:token-lifecycle` | tier2 | Complete token lifecycle - from launch through bonding curve to DEX graduation | `action`*, `tokenName`* | - | | `galachain-launchpad:transfer-assets` | legacy | Transfer tokens or GALA to another wallet address with confirmation and verification | `assetType`*, `recipientAddress`*, `amount`* | - | | `galachain-launchpad:stake-tokens` | legacy | Lock tokens for staking, vesting, or escrow with optional expiration dates | `tokenName`*, `amount`*, `lockType`, `expiresAt`, `lockName` | - | | `galachain-launchpad:manage-assets` | legacy | Complete asset management - transfers, staking, locking, and portfolio monitoring | `action`*, `tokenName`* | - | | `galachain-launchpad:setup-account` | legacy | Register account, configure wallet, and prepare for trading and token creation | `action`* | - | | `galachain-launchpad:customize-profile` | legacy | Update profile information, upload avatar, and customize your public profile | `fullName`, `profileImageUrl` | - | | `galachain-launchpad:account-management` | legacy | Complete account management - registration, authentication, profile customization, and settings | `task`* | - | | `galachain-launchpad:invite-moderators` | legacy | Create and send moderator invitations with role assignment and permissions | `tokenName`*, `role`, `expiryDays` | - | | `galachain-launchpad:manage-moderators` | legacy | View active moderators, revoke access, reassign roles, and manage permissions | `tokenName`*, `action`*, `moderatorAddress` | - | | `galachain-launchpad:moderate-comments` | legacy | Delete, pin, hide, or manage comments on token pools and streams | `tokenName`*, `action`*, `reason` | - | | `galachain-launchpad:ban-users` | legacy | Ban users temporarily or permanently with reason documentation | `tokenName`*, `userAddress`*, `banDuration`*, `reason` | - | | `galachain-launchpad:post-comments` | legacy | Post comments on token pools, manage comment threads, and engage with community | `tokenName`*, `content`*, `parentCommentId` | - | | `galachain-launchpad:react-to-content` | legacy | Add reactions (likes, emojis) to comments and engage with content | `contentType`*, `contentId`*, `reaction`* | - | | `galachain-launchpad:monitor-community` | legacy | Track community engagement, sentiment, and health metrics | `tokenName`*, `timeframe`, `metricType` | - | | `galachain-launchpad:manage-streams` | legacy | Start, stop, reset stream keys, and manage live stream operations | `tokenName`*, `action`* | - | | `galachain-launchpad:manage-recordings` | legacy | Upload, download, delete, and manage stream recordings and VODs | `tokenName`*, `action`* | - | | `galachain-launchpad:manage-simulcast` | legacy | Configure simulcast targets to stream simultaneously to YouTube, Twitch, and more | `tokenName`*, `action`*, `platform` | - | | `galachain-launchpad:buy-tokens` | legacy | Guide user through buying tokens with slippage protection and cost breakdown | `tokenName`*, `galaAmount`*, `slippage` | `gala_launchpad_buy`, `gala_launchpad_calculate_buy_amount` | | `galachain-launchpad:sell-tokens` | legacy | Guide user through selling tokens with slippage protection | `tokenName`*, `tokenAmount`*, `slippage` | `gala_launchpad_calculate_sell_amount`, `gala_launchpad_fetch_token_balance`, `gala_launchpad_sell` | | `galachain-launchpad:burn-tokens` | legacy | Permanently burn (destroy) tokens on GalaChain (IRREVERSIBLE) | `tokenName`*, `amount`* | `gala_launchpad_burn_tokens` | | `galachain-launchpad:get-trades` | legacy | Query trade history with tokenName/userAddress filters | `tokenName`, `userAddress`, `txnType`, `startDate`, `endDate`, `page`, `limit` | `gala_launchpad_get_trades` | | `galachain-launchpad:tokens-held` | legacy | List all Launchpad tokens currently held with balances | `search`, `limit` | `gala_launchpad_fetch_tokens_held` | | `galachain-launchpad:tokens-created` | legacy | List all Launchpad tokens created by the user with their current status | `search`, `limit` | `gala_launchpad_fetch_pool_details`, `gala_launchpad_fetch_tokens_created`, `gala_launchpad_get_url_by_token_name`, `gala_launchpad_is_token_graduated` | | `galachain-launchpad:profile` | legacy | Show user profile information and activity summary | - | `gala_launchpad_fetch_gala_balance`, `gala_launchpad_fetch_profile`, `gala_launchpad_fetch_tokens_created`, `gala_launchpad_fetch_tokens_held`, `gala_launchpad_get_address`, `gala_launchpad_get_ethereum_address` | | `galachain-launchpad:compare-tokens` | legacy | Compare two Launchpad tokens side-by-side with detailed metrics | `token1`*, `token2`* | `gala_launchpad_calculate_buy_amount_for_graduation`, `gala_launchpad_fetch_launchpad_token_spot_price`, `gala_launchpad_fetch_pool_details`, `gala_launchpad_fetch_pool_details_for_calculation`, `gala_launchpad_fetch_token_distribution`, `gala_launchpad_is_token_graduated` | | `galachain-launchpad:graduation-status` | legacy | Check graduation status and readiness for multiple tokens | `tokens`* | `gala_launchpad_calculate_buy_amount_for_graduation`, `gala_launchpad_fetch_pool_details`, `gala_launchpad_fetch_pool_details_for_calculation`, `gala_launchpad_is_token_graduated` | | `galachain-launchpad:pool-details` | legacy | Get comprehensive pool information including distribution and holder metrics | `tokenName`* | `gala_launchpad_fetch_pool_details`, `gala_launchpad_fetch_token_distribution`, `gala_launchpad_fetch_volume_data`, `gala_launchpad_get_url_by_token_name`, `gala_launchpad_is_token_graduated` | | `galachain-launchpad:trade-history` | legacy | View recent trades for a token or user with filtering options | `tokenName`, `userAddress`, `tradeType`, `limit` | `gala_launchpad_fetch_trades` | | `galachain-launchpad:create-token` | legacy | Guide user through creating a new token on Gala Launchpad with metadata, image upload, and optional pre-buy | `tokenName`*, `tokenSymbol`*, `description`*, `websiteUrl`, `twitterUrl`, `telegramUrl`, `imagePath`, `preBuyGala` | `gala_launchpad_calculate_initial_buy`, `gala_launchpad_check_token_name`, `gala_launchpad_check_token_symbol`, `gala_launchpad_fetch_gala_balance`, `gala_launchpad_fetch_launch_token_fee`, `gala_launchpad_get_url_by_token_name`, `gala_launchpad_launch_token`, `gala_launchpad_upload_token_image` | | `galachain-launchpad:claim-nft-collection` | legacy | Claim a new NFT collection on GalaChain and optionally create your first token class (rarity tier) | `collectionName`*, `description`*, `firstTokenClassName`, `tokenClassDescription`, `maxSupply` | - | | `galachain-launchpad:mint-nft` | legacy | Estimate fees and mint NFT instances from a token class to a wallet address | `collectionName`*, `tokenClassName`*, `quantity`*, `recipientAddress` | - | | `galachain-launchpad:manage-nft-collections` | legacy | View your owned NFT collections, token classes, and check supply information | `collectionName` | - | | `galachain-launchpad:create-nft-token-class` | legacy | Create a new token class (rarity tier) within an existing NFT collection | `collectionName`*, `tokenClassName`*, `description`*, `maxSupply`* | - | | `galachain-launchpad:estimate-nft-operations` | legacy | Estimate fees for a bundle of NFT operations to plan your collection strategy | `operationType`*, `estimatedMintQuantity` | - | | `galachain-launchpad:discover-tokens` | legacy | Discover new opportunities on Gala Launchpad - find recently launched tokens, popular tokens, or tokens near graduation | `type`, `limit`, `minProgress`, `maxPrice` | `gala_launchpad_fetch_all_pools`, `gala_launchpad_fetch_launchpad_token_spot_price` | | `galachain-launchpad:fetch-pools` | legacy | Fetch token pools with pagination and optional filters | `type`, `page`, `limit` | `gala_launchpad_fetch_pools` | | `galachain-launchpad:fetch-pool-details-for-calculation` | legacy | Get optimized pool details for local bonding curve calculations | `tokenName`* | `gala_launchpad_fetch_pool_details_for_calculation` | | `galachain-launchpad:fetch-token-details` | legacy | Fetch comprehensive token metadata from DEX API | `tokenId`* | `gala_launchpad_fetch_token_details` | | `galachain-launchpad:check-token-name` | legacy | Check if a token name is available | `tokenName`* | `gala_launchpad_check_token_name` | | `galachain-launchpad:check-token-symbol` | legacy | Check if a token symbol is available | `symbol`* | `gala_launchpad_check_token_symbol` | | `galachain-launchpad:resolve-vault-address` | legacy | Get GalaChain vault address for a token | `tokenName`* | `gala_launchpad_resolve_vault_address` | | `galachain-launchpad:resolve-token-class-key` | legacy | Get GalaChain TokenClassKey for a launchpad token | `tokenName`* | `gala_launchpad_resolve_token_class_key` | | `galachain-launchpad:calculate-buy-amount` | legacy | Calculate token amounts and fees for buying | `tokenName`*, `amount`*, `type`* | `gala_launchpad_calculate_buy_amount` | | `galachain-launchpad:calculate-sell-amount` | legacy | Calculate GALA amounts and fees for selling | `tokenName`*, `amount`*, `type`* | `gala_launchpad_calculate_sell_amount` | | `galachain-launchpad:fetch-trades` | legacy | Query your trading history with optional filters | `tokenName`, `tradeType`, `page`, `limit` | `gala_launchpad_fetch_trades` | | `galachain-launchpad:calculate-initial-buy` | legacy | Calculate pre-buy amounts during token creation | `amount`* | `gala_launchpad_calculate_initial_buy` | | `galachain-launchpad:get-bundler-transaction-result` | legacy | Check bundler transaction status by ID | `transactionId`* | `gala_launchpad_get_bundler_transaction_result` | | `galachain-launchpad:calculate-graduation-cost` | legacy | Calculate cost to graduate a token pool to DEX | `tokenName`* | `gala_launchpad_calculate_buy_amount_for_graduation` | | `galachain-launchpad:calculate-buy-amount-local` | legacy | Calculate buy amount using LOCAL bonding curve (instant, no network) | `tokenName`*, `amount`* | `gala_launchpad_calculate_buy_amount_local` | | `galachain-launchpad:calculate-buy-amount-external` | legacy | Calculate buy amount using EXTERNAL GalaChain call (real-time) | `tokenName`*, `amount`* | `gala_launchpad_calculate_buy_amount_external` | | `galachain-launchpad:calculate-sell-amount-local` | legacy | Calculate sell amount using LOCAL bonding curve (instant) | `tokenName`*, `amount`* | `gala_launchpad_calculate_sell_amount_local` | | `galachain-launchpad:calculate-sell-amount-external` | legacy | Calculate sell amount using EXTERNAL GalaChain call (real-time) | `tokenName`*, `amount`* | `gala_launchpad_calculate_sell_amount_external` | | `galachain-launchpad:is-token-graduated` | legacy | Check if a token has completed bonding curve and graduated to DEX | `tokenName`* | `gala_launchpad_is_token_graduated` | | `galachain-launchpad:fetch-token-balance` | legacy | Get balance for a specific token | `tokenName`*, `address`* | `gala_launchpad_fetch_token_balance` | | `galachain-launchpad:fetch-tokens-created` | legacy | Get tokens created by a wallet | `address`*, `page`, `limit`, `tokenName`, `search` | `gala_launchpad_fetch_tokens_created` | | `galachain-launchpad:update-profile` | legacy | Update user profile information | `fullName`*, `profileImage`*, `address` | `gala_launchpad_update_profile` | | `galachain-launchpad:upload-profile-image` | legacy | Upload profile image from filesystem | `imagePath`*, `address` | `gala_launchpad_upload_profile_image` | | `galachain-launchpad:upload-token-image` | legacy | Upload token image from filesystem (Node.js only) | `tokenName`*, `imagePath`* | `gala_launchpad_upload_token_image` | | `galachain-launchpad:fetch-launch-token-fee` | legacy | Get the current GALA fee required to launch a new token | - | `gala_launchpad_fetch_launch_token_fee` | | `galachain-launchpad:transfer-token` | legacy | Transfer launchpad tokens to another wallet | `to`*, `tokenName`*, `amount`* | `gala_launchpad_transfer_token` | | `galachain-launchpad:lock-token` | legacy | Lock tokens on GalaChain (for staking, escrow, vesting) | `tokenName`*, `amount`*, `lockAuthority`, `expires`, `name` | `gala_launchpad_lock_tokens` | | `galachain-launchpad:unlock-token` | legacy | Unlock previously locked tokens on GalaChain | `tokenName`*, `amount`*, `name` | `gala_launchpad_unlock_tokens` | | `galachain-launchpad:get-config` | legacy | View current SDK and MCP server configuration | - | `gala_launchpad_get_config` | | `galachain-launchpad:get-url-by-token-name` | legacy | Get the launchpad frontend URL for a token | `tokenName`* | `gala_launchpad_get_url_by_token_name` | | `galachain-launchpad:get-cache-info` | legacy | Get token metadata cache statistics | - | `gala_launchpad_get_cache_info` | | `galachain-launchpad:clear-cache` | legacy | Clear token metadata cache | `tokenName` | `gala_launchpad_clear_cache` | | `galachain-launchpad:cleanup` | legacy | Clean up SDK resources (HTTP interceptors, WebSocket connections) to prevent memory leaks | - | `gala_launchpad_cleanup` | | `galachain-launchpad:watch-token-launches` | legacy | Watch for new tokens being launched on the platform in real-time via WebSocket | `duration`, `creatorAddress` | `gala_launchpad_on_launchpad_token_creation` | | `galachain-launchpad:create-moderator-invite` | legacy | Create a magic link invite to delegate moderator access to another user | `tokenName`*, `role`*, `description`, `expiresAt` | `gala_launchpad_create_moderator_invite` | | `galachain-launchpad:claim-moderator-invite` | legacy | Claim a moderator invite using the code from a magic link | `inviteCode`* | `gala_launchpad_claim_moderator_invite` | | `galachain-launchpad:list-moderator-invites` | legacy | List all moderator invites for a token (owner only) | `tokenName`*, `status` | `gala_launchpad_list_moderator_invites` | | `galachain-launchpad:show-moderator-invite` | legacy | Get public details about a moderator invite (no auth required) | `inviteCode`* | `gala_launchpad_get_moderator_invite` | | `galachain-launchpad:revoke-moderator-invite` | legacy | Revoke a moderator invite (prevents claiming or removes existing access) | `inviteId`* | `gala_launchpad_revoke_moderator_invite` | | `galachain-launchpad:get-moderated-tokens` | legacy | Get all tokens where you have moderator access (studio dashboard) | - | `gala_launchpad_get_moderated_tokens` | | `galachain-launchpad:create-ban` | legacy | Ban user from a token stream | `tokenName`*, `userAddress`*, `reason`, `durationSeconds` | `gala_launchpad_create_ban` | | `galachain-launchpad:remove-ban` | legacy | Remove a ban (unban) | `tokenName`*, `userAddress`* | `gala_launchpad_remove_ban` | | `galachain-launchpad:list-bans` | legacy | List all banned users for a token | `tokenName`*, `search` | `gala_launchpad_list_bans` | | `galachain-launchpad:check-ban-status` | legacy | Check if a specific user is banned on a token | `tokenName`*, `userAddress`* | `gala_launchpad_get_ban_status` | | `galachain-launchpad:get-active-users` | legacy | Get currently active viewers or chat participants on a stream | `tokenName`*, `type`, `search` | `gala_launchpad_get_active_users` | | `galachain-launchpad:create-api-key` | legacy | Create a new API key for delegating permissions to third-party services | `role`*, `description`, `delegateAllTokens`, `tokenNames`, `expiresAt` | `gala_launchpad_create_api_key` | | `galachain-launchpad:list-api-keys` | legacy | List all your API keys | - | `gala_launchpad_list_api_keys` | | `galachain-launchpad:get-api-key` | legacy | Get details of a specific API key | `id`* | `gala_launchpad_get_api_key` | | `galachain-launchpad:update-api-key` | legacy | Update an API key's permissions or metadata | `id`*, `role`, `description`, `delegateAllTokens`, `tokenNames` | `gala_launchpad_update_api_key` | | `galachain-launchpad:revoke-api-key` | legacy | Revoke an API key (immediately disables it) | `id`* | `gala_launchpad_revoke_api_key` | | `galachain-launchpad:get-api-key-roles` | legacy | Get all valid API key roles and their permissions | - | `gala_launchpad_get_api_key_roles` | | `galachain-launchpad:create-overseer-invite` | legacy | Create a magic link invite to delegate overseer access | `description`, `expiresAt` | `gala_launchpad_create_overseer_invite` | | `galachain-launchpad:claim-overseer-invite` | legacy | Claim a overseer invite using the code from a magic link | `inviteCode`* | `gala_launchpad_claim_overseer_invite` | | `galachain-launchpad:list-overseer-invites` | legacy | List all overseer invites with optional filtering | `status`, `page`, `limit` | `gala_launchpad_list_overseer_invites` | | `galachain-launchpad:show-overseer-invite` | legacy | Get public details about a overseer invite (no auth required) | `inviteCode`* | `gala_launchpad_get_overseer_invite` | | `galachain-launchpad:revoke-overseer-invite` | legacy | Revoke a overseer invite (prevents claiming or removes existing access) | `inviteId`* | `gala_launchpad_revoke_overseer_invite` | | `galachain-launchpad:list-overseers` | legacy | List all platform overseers with optional filtering | `status`, `page`, `limit` | `gala_launchpad_list_overseers` | | `galachain-launchpad:revoke-overseer` | legacy | Revoke an overseer's global platform access by wallet address | `address`* | `gala_launchpad_revoke_overseer` | | `galachain-launchpad:my-overseer-status` | legacy | Check if you are currently an overseer and get your status details | - | `gala_launchpad_get_my_overseer_status` | | `galachain-launchpad:start-stream` | legacy | Start a live stream for a token and get streaming credentials | `tokenName`* | `gala_launchpad_start_stream` | | `galachain-launchpad:stop-stream` | legacy | Stop a live stream for a token | `tokenName`* | `gala_launchpad_stop_stream` | | `galachain-launchpad:reset-stream-key` | legacy | Reset the stream key for a token (invalidates the old key) | `tokenName`* | `gala_launchpad_reset_stream_key` | | `galachain-launchpad:get-stream-recordings` | legacy | Get list of recordings for a stream | `tokenName`*, `page`, `limit` | `gala_launchpad_get_stream_recordings` | | `galachain-launchpad:get-recording-download` | legacy | Get a signed download URL for a recording | `tokenName`*, `assetId`* | `gala_launchpad_get_recording_download` | | `galachain-launchpad:delete-recording` | legacy | Permanently delete a stream recording (cannot be undone) | `tokenName`*, `assetId`* | `gala_launchpad_delete_recording` | | `galachain-launchpad:get-simulcast-targets` | legacy | Get list of simulcast targets for a stream | `tokenName`* | `gala_launchpad_get_simulcast_targets` | | `galachain-launchpad:add-simulcast-target` | legacy | Add a simulcast target to rebroadcast to YouTube, Twitch, or other platforms | `tokenName`*, `platform`*, `rtmpUrl`*, `streamKey`*, `name` | `gala_launchpad_add_simulcast_target` | | `galachain-launchpad:remove-simulcast-target` | legacy | Remove a simulcast target from a stream | `tokenName`*, `targetId`* | `gala_launchpad_remove_simulcast_target` | | `galachain-launchpad:get-global-streaming-status` | legacy | Get streaming status (Admin only) | - | `gala_launchpad_get_global_streaming_status` | | `galachain-launchpad:set-global-streaming-enabled` | legacy | Enable or disable streaming (Admin only) | `enabled`* | `gala_launchpad_set_global_streaming_enabled` | | `galachain-launchpad:disable-stream` | legacy | Disable streaming for a specific token (Admin only) | `tokenName`* | `gala_launchpad_set_stream_enabled` | | `galachain-launchpad:enable-stream` | legacy | Enable streaming for a specific token (Admin only) | `tokenName`* | `gala_launchpad_set_stream_enabled` | | `galachain-launchpad:get-stream-role` | legacy | Get the authenticated user's role for a token stream | `tokenName`* | `gala_launchpad_get_stream_role` | | `galachain-launchpad:get-available-roles` | legacy | Get all available roles and permissions for token delegation | - | `gala_launchpad_get_available_roles` | | `galachain-launchpad:get-token-access` | legacy | Check if the authenticated user has Studio access for a token | `tokenName`* | `gala_launchpad_get_token_access` | | `galachain-launchpad:get-chat-status` | legacy | Get chat status for a token stream | `tokenName`* | `gala_launchpad_get_chat_status` | | `galachain-launchpad:enable-chat` | legacy | Enable chat for a token stream | `tokenName`* | `gala_launchpad_set_chat_enabled` | | `galachain-launchpad:disable-chat` | legacy | Disable chat for a token stream | `tokenName`* | `gala_launchpad_set_chat_enabled` | | `galachain-launchpad:connect-stream-websocket` | legacy | Connect to the stream WebSocket server for real-time events | - | `gala_launchpad_connect_stream_websocket` | | `galachain-launchpad:subscribe-to-stream` | legacy | Subscribe to a stream's real-time events via WebSocket | `tokenName`* | `gala_launchpad_subscribe_to_stream` | | `galachain-launchpad:send-stream-chat-websocket` | legacy | Send a chat message via WebSocket (low latency) | `tokenName`*, `content`* | `gala_launchpad_send_stream_chat_via_web_socket` | | `galachain-launchpad:send-stream-reaction` | legacy | Send an ephemeral emoji reaction to a live stream | `tokenName`*, `emoji`*, `streamTime` | `gala_launchpad_send_stream_reaction` | | `galachain-launchpad:send-typing-indicator` | legacy | Send typing indicator to stream chat | `tokenName`*, `isTyping`* | `gala_launchpad_send_typing_indicator` | | `galachain-launchpad:get-chat-messages` | legacy | Query chat messages with tokenName/userAddress filters | `tokenName`, `userAddress`, `page`, `limit` | `gala_launchpad_get_chat_messages` | | `galachain-launchpad:send-chat-message` | legacy | Send a chat message via REST API | `tokenName`*, `content`* | `gala_launchpad_login`, `gala_launchpad_send_chat_message` | | `galachain-launchpad:delete-chat-message` | legacy | Delete a chat message (author, owner, or moderator) | `id`* | `gala_launchpad_delete_chat_message` | | `galachain-launchpad:add-content-reaction` | legacy | Add a reaction to a pool message (chat or comment) | `messageId`*, `reactionType`*, `tokenName` | `gala_launchpad_add_content_reaction` | | `galachain-launchpad:remove-content-reaction` | legacy | Remove a reaction from a pool message (chat or comment) | `messageId`*, `reactionType`*, `tokenName` | `gala_launchpad_remove_content_reaction` | | `galachain-launchpad:add-reaction-to-chat-message` | legacy | Add a reaction to a chat message | `messageId`*, `reactionType`*, `tokenName` | `gala_launchpad_add_reaction_to_chat_message` | | `galachain-launchpad:remove-reaction-from-chat-message` | legacy | Remove a reaction from a chat message | `messageId`*, `reactionType`*, `tokenName` | `gala_launchpad_remove_reaction_from_chat_message` | | `galachain-launchpad:add-reaction-to-comment` | legacy | Add a reaction to a comment | `messageId`*, `reactionType`*, `tokenName` | `gala_launchpad_add_reaction_to_comment` | | `galachain-launchpad:remove-reaction-from-comment` | legacy | Remove a reaction from a comment | `messageId`*, `reactionType`*, `tokenName` | `gala_launchpad_remove_reaction_from_comment` | | `galachain-launchpad:get-comments` | legacy | Query comments with tokenName/userAddress filters | `tokenName`, `userAddress`, `page`, `limit` | `gala_launchpad_get_comments` | | `galachain-launchpad:create-comment` | legacy | Create a new comment on a token pool | `tokenName`*, `content`* | `gala_launchpad_create_comment`, `gala_launchpad_login` | | `galachain-launchpad:update-comment` | legacy | Update a comment's content (author only) | `id`*, `content`* | `gala_launchpad_update_comment` | | `galachain-launchpad:delete-comment` | legacy | Delete a comment (author, owner, or moderator) | `id`* | `gala_launchpad_delete_comment` | | `galachain-launchpad:fetch-referral-url` | legacy | Get your unique referral URL for sharing | - | `gala_launchpad_fetch_referral_url` | | `galachain-launchpad:fetch-referrals` | legacy | Get paginated list of users who signed up using your referral link | `address`, `page`, `limit`, `sortBy`, `sortDir` | `gala_launchpad_fetch_referrals` | | `galachain-launchpad:fetch-all-referrals` | legacy | Fetch all referrals with automatic pagination | `address`, `sortBy`, `sortDir` | `gala_launchpad_fetch_all_referrals` | | `galachain-launchpad:fetch-referrals-summary` | legacy | Get referral program summary statistics | `address` | `gala_launchpad_fetch_referrals_summary` | | `galachain-launchpad:subscribe-token-creations` | legacy | Subscribe to real-time token creation events on Launchpad via WebSocket | `duration`, `creatorAddress` | `gala_launchpad_on_launchpad_token_creation` | | `galachain-launchpad:login` | legacy | Authenticate with wallet signature to get JWT token | - | `gala_launchpad_login` | | `galachain-launchpad:logout` | legacy | Clear JWT token and end session | - | `gala_launchpad_logout` | | `galachain-launchpad:session-status` | legacy | Check current authentication status and session details | - | `gala_launchpad_is_authenticated` | | `galachain-launchpad:refresh-token` | legacy | Refresh JWT token before it expires | - | `gala_launchpad_refresh_token` | | `galachain-launchpad:ensure-valid-token` | legacy | Ensure valid token exists, auto-refreshing if needed | - | `gala_launchpad_ensure_valid_token` | | `galachain-launchpad:flag-content` | legacy | Flag/report inappropriate content (chat, comment, or stream) | `tokenName`*, `contentType`*, `contentId`*, `reportedUserAddress`*, `reason`, `details` | `gala_launchpad_create_flag` | | `galachain-launchpad:list-flags` | legacy | List content flags for a specific token | `tokenName`*, `status`, `contentType` | `gala_launchpad_list_flags` | | `galachain-launchpad:dismiss-flag` | legacy | Dismiss a flag (reviewed, no action needed) | `flagId`* | `gala_launchpad_dismiss_flag` | | `galachain-launchpad:action-flag` | legacy | Take action on a content flag (delete/ban) | `flagId`*, `action`* | `gala_launchpad_action_flag` | | `galachain-launchpad:list-global-flags` | legacy | List all flags across the platform (admin/overseer) | `status`, `contentType` | `gala_launchpad_list_global_flags` | | `galachain-launchpad:my-trades` | legacy | Get trade history for the configured wallet | `tokenName`, `txnType` | `gala_launchpad_fetch_trades`, `gala_launchpad_get_address` | | `galachain-launchpad:token-trade-activity` | legacy | Get recent trade activity for a token | `tokenName`*, `limit` | `gala_launchpad_fetch_trades` | | `galachain-launchpad:update-chat-message` | legacy | Update a chat message you sent | `messageId`*, `content`* | `gala_launchpad_login`, `gala_launchpad_update_chat_message` | | `galachain-launchpad:token-chat` | legacy | View recent chat for a token | `tokenName`* | `gala_launchpad_get_chat_messages` | | `galachain-launchpad:ban-token` | legacy | Ban a platform (OVERSEER ONLY) | `tokenName`*, `reason` | `gala_launchpad_ban_token` | | `galachain-launchpad:unban-token` | legacy | Remove a platform-wide token ban (OVERSEER ONLY) (unban) | `tokenName`* | `gala_launchpad_unban_token` | | `galachain-launchpad:list-token-bans` | legacy | List all banned tokens on the platform (OVERSEER ONLY) | `page`, `limit` | `gala_launchpad_list_token_bans` | | `galachain-launchpad:check-token-banned` | legacy | Check if a token is currently banned on the platform | `tokenName`* | `gala_launchpad_is_token_banned` | | `galachain-launchpad:get-token-ban` | legacy | Get ban details for a specific token (OVERSEER ONLY) | `tokenName`* | `gala_launchpad_get_token_ban` | | `galachain-launchpad:burn-tokens-batch` | legacy | Permanently burn multiple token types in one transaction (IRREVERSIBLE - CANNOT BE UNDONE) | `tokens`*, `uniqueKey` | `gala_launchpad_burn_tokens`, `gala_launchpad_fetch_token_balance` | | `galachain-launchpad:get-managed-tokens` | legacy | Get all tokens the user owns or has moderator access to | `address` | `gala_launchpad_get_managed_tokens` | | `galachain-launchpad:get-ai-moderation-settings` | tier3 | Get current AI moderation settings and configuration | - | `gala_launchpad_get_ai_moderation_settings` | | `galachain-launchpad:update-ai-moderation-settings` | tier3 | Update AI moderation configuration (Admin/Overseer only) | `enabled`, `mode`, `provider` | `gala_launchpad_update_ai_moderation_settings` | | `galachain-launchpad:get-ai-moderation-result` | tier3 | Get AI moderation result for a specific content flag | `flagId`* | `gala_launchpad_get_ai_moderation_result`, `gala_launchpad_trigger_ai_moderation` | | `galachain-launchpad:trigger-ai-moderation` | tier3 | Queue flagged content for AI moderation analysis | `flagId`* | `gala_launchpad_get_ai_moderation_result`, `gala_launchpad_trigger_ai_moderation` | | `galachain-launchpad:get-ai-moderation-status` | tier3 | Check if AI moderation system is operational | - | `gala_launchpad_get_ai_moderation_status` | | `galachain-launchpad:weekly-challenge-leaderboard` | legacy | Get this week's token challenge leaderboard ranked by market cap increase | `limit` | `gala_launchpad_get_weekly_challenge_leaderboard` | | `galachain-launchpad:token-weekly-history` | legacy | Get the last 4 weeks of weekly snapshot data for a specific token | `vaultAddress`* | `gala_launchpad_get_token_weekly_history` | | `galachain-launchpad:platform-stats` | legacy | Get platform-wide GALA trading volume and token count statistics | - | `gala_launchpad_get_platform_stats` | | `galachain-launchpad:get-restricted-names` | legacy | Get the list of restricted token names (Overseer only) | - | `gala_launchpad_get_restricted_names` | | `galachain-launchpad:update-restricted-names` | legacy | Update the restricted token names list (Overseer only) | `content`* | `gala_launchpad_update_restricted_names` | | `galachain-launchpad:get-connected-clients` | legacy | Query active WebSocket connections with optional filtering | `tokenName`, `userAddress` | `gala_launchpad_get_connected_clients` | | `galachain-launchpad:is-user-online` | legacy | Check if a specific user is currently connected via WebSocket | `userAddress`* | `gala_launchpad_is_user_online` | | `galachain-launchpad:get-online-users` | legacy | Check which users from a list are currently online | `userAddresses`* | `gala_launchpad_get_online_users` | | `galachain-launchpad:get-token-viewers` | legacy | Get all WebSocket clients currently viewing a token | `tokenName`* | `gala_launchpad_get_token_viewers` | | `galachain-launchpad:get-online-overseers` | legacy | Get currently online platform admins/overseers | - | `gala_launchpad_get_online_overseers` | | `galachain-launchpad:emit-trade-executed` | legacy | Broadcast a trade execution event to all token subscribers | `tokenName`*, `tradeType`*, `amount` | `gala_launchpad_emit_trade_executed` | | `galachain-launchpad:emit-balance-updated` | legacy | Notify a user of their updated balance | `userAddress`*, `tokenName` | `gala_launchpad_emit_balance_updated` | | `galachain-launchpad:emit-stream-status` | legacy | Broadcast stream status change (live/offline) to all token subscribers | `tokenName`*, `isLive`* | `gala_launchpad_emit_stream_status` | | `galachain-launchpad:emit-viewer-count` | legacy | Broadcast updated viewer count to all token subscribers | `tokenName`*, `count`* | `gala_launchpad_emit_viewer_count` | | `galachain-launchpad:emit-stream-countdown` | legacy | Broadcast an upcoming stream countdown announcement | `tokenName`*, `startsAt`* | `gala_launchpad_emit_stream_countdown` | | `galachain-launchpad:emit-chat-message` | legacy | Broadcast an admin/system chat message to a token's chat | `tokenName`*, `content`* | `gala_launchpad_emit_chat_message` | | `galachain-launchpad:emit-chat-status` | legacy | Broadcast chat enabled/disabled status change | `tokenName`*, `enabled`* | `gala_launchpad_emit_chat_status` | | `galachain-launchpad:emit-typing-indicator` | legacy | Broadcast typing indicator to show who is typing in chat | `tokenName`*, `userAddress`*, `isTyping`* | `gala_launchpad_emit_typing_indicator` | | `galachain-launchpad:emit-token-banned` | legacy | Broadcast token ban event to all platform subscribers | `tokenName`* | `gala_launchpad_emit_token_banned` | | `galachain-launchpad:emit-token-unbanned` | legacy | Broadcast token unban event to all platform subscribers | `tokenName`* | `gala_launchpad_emit_token_unbanned` | | `galachain-launchpad:emit-moderator-added` | legacy | Broadcast that a moderator was added to a token | `tokenName`*, `moderatorAddress`* | `gala_launchpad_emit_moderator_added` | | `galachain-launchpad:emit-moderator-removed` | legacy | Broadcast that a moderator was removed from a token | `tokenName`*, `moderatorAddress`* | `gala_launchpad_emit_moderator_removed` | | `galachain-launchpad:emit-user-profile-updated` | legacy | Notify a user that their profile was updated | `userAddress`* | `gala_launchpad_emit_user_profile_updated` | | `galachain-launchpad:emit-site-config-changed` | legacy | Broadcast platform configuration changes to all connected clients | - | `gala_launchpad_emit_site_config_changed` | | `galachain-launchpad:emit-feature-status` | legacy | Broadcast feature availability changes to all connected clients | `feature`*, `enabled`* | `gala_launchpad_emit_feature_status` | | `galachain-launchpad:emit-websocket-event` | legacy | Emit a custom WebSocket event with arbitrary payload (advanced use) | `event`*, `payload`*, `room` | `gala_launchpad_emit_websocket_event` | | `galachain-launchpad:home-oembed` | legacy | Get oEmbed metadata for the Launchpad home page (social media previews) | - | `gala_launchpad_get_home_oembed` | | `galachain-launchpad:pool-oembed` | legacy | Get oEmbed metadata for a token's buy/sell page | `tokenName`* | `gala_launchpad_get_pool_oembed` | | `galachain-launchpad:profile-oembed` | legacy | Get oEmbed metadata for a user profile page | `address`* | `gala_launchpad_get_profile_oembed` | | `galachain-launchpad:fetch-messages` | legacy | Query chat messages or comments for a token or user | `type`, `tokenName`, `userAddress`, `search`, `pageSize` | `gala_launchpad_fetch_messages` | | `galachain-launchpad:create-message` | legacy | Create a chat message or comment for a token | `type`*, `tokenName`*, `content`* | `gala_launchpad_create_message` | | `galachain-launchpad:update-message` | legacy | Update the content of a message (author only) | `messageId`*, `content`* | `gala_launchpad_update_message` | | `galachain-launchpad:delete-message` | legacy | Delete a message (author, token owner, or moderator) | `messageId`* | `gala_launchpad_delete_message` | | `galachain-launchpad:get-pinned-message` | legacy | Get the pinned message for a token | `tokenName`* | `gala_launchpad_get_pinned_message` | | `galachain-launchpad:pin-message` | legacy | Pin a chat message for a token (owner/moderator only) | `tokenName`*, `messageId`* | `gala_launchpad_pin_message` | | `galachain-launchpad:unpin-message` | legacy | Unpin the pinned message for a token (owner/moderator only) | `tokenName`* | `gala_launchpad_unpin_message` | | `galachain-launchpad:message-stats` | legacy | Get platform-wide message statistics (Admin/Overseer only) | - | `gala_launchpad_get_message_stats` | | `galachain-launchpad:get-holder-rank` | legacy | Check where a wallet address ranks among all holders of a token | - | `gala_launchpad_get_holder_rank` | | `galachain-launchpad:get-top-holders` | legacy | Get the top N token holders ranked by balance for whale analysis | - | `gala_launchpad_get_top_holders` | | `galachain-launchpad:get-holder-count` | legacy | Get total number of holders and distribution health statistics for a token | - | `gala_launchpad_get_holder_count` | | `galachain-launchpad:get-holders-by-balance` | legacy | Get holders within a specific balance range (e.g., all wallets holding 1000-10000 tokens) | - | `gala_launchpad_get_holders_by_balance` | | `galachain-launchpad:get-holder-history` | legacy | Get historical holder count data to see if a token is gaining or losing holders over time | - | `gala_launchpad_get_holder_history` | | `galachain-launchpad:global-feed-subscribe` | legacy | Get instructions for subscribing to the global real-time event feed covering all token activities | - | `gala_launchpad_global_feed_reference` | | `galachain-launchpad:global-feed-status` | legacy | Check the current status and configuration of the global WebSocket feed | - | `gala_launchpad_global_feed_status_reference` | | `galachain-launchpad:monitor-global-feed` | legacy | Get monitoring instructions for capturing and logging global feed events in real-time | - | `gala_launchpad_monitor_global_feed_events_reference` | --- # gswap toolset: tools and prompts The `gswap` toolset of `@gala-chain/gala-mcp-server` 1.0.0-rc.9 provides GSwap DEX quotes, swaps, pools, liquidity positions, fees, market prices and the leaderboard. It defines 32 tools and 34 prompts. A prompt is offered only when every tool it names is registered by the selection. The same data, with every parameter's type and description, is at `/mcp/gswap/tools.json`. `*` marks a required parameter. Tools whose description says they need authentication need a wallet in full-access mode. ## Tools ### get | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_get_swap_quote_exact_input` | Get a v6 GSwap quote for an exact input amount through gswap-sdk (gSwap.quoting.quoteExactInput) | no | `fromToken`*, `toToken`*, `amount`*, `fee` | | `gala_launchpad_get_swap_quote_exact_output` | Get a v6 GSwap quote for an exact output amount through gswap-sdk (gSwap.quoting.quoteExactOutput) | no | `fromToken`*, `toToken`*, `amount`*, `fee` | | `gala_launchpad_get_swap_result` | Resolve the outcome of a previously queued GSwap swap by its uniqueKey through gswap-sdk (gSwap.swaps.confirmSwap), without resubmitting | no | `uniqueKey`*, `timeoutMs` | | `gala_launchpad_get_swap_user_assets` | Get one page of GSwap assets for a wallet through gswap-sdk (gSwap.assets.getUserAssets) | no | `walletAddress`* | | `gala_launchpad_get_all_swap_user_assets` | Fetch all GSwap assets for a wallet through gswap-sdk (gSwap.assets.getUserAssets) | no | `walletAddress`* | | `gala_launchpad_get_swap_pool_info` | Get current-contract GSwap pool information for a token pair | no | `tokenA`*, `tokenB`* | | `gala_launchpad_get_swap_pool_price` | Get current-contract GSwap price state through gswap-sdk (gSwap.pools.getSlot0) | no | `token0`*, `token1`*, `fee`* | | `gala_launchpad_get_user_liquidity_positions` | Get current-contract GSwap liquidity positions owned by an address | no | `ownerAddress`* | | `gala_launchpad_get_all_user_liquidity_positions` | Get all current-contract GSwap liquidity positions owned by an address | no | `ownerAddress`* | | `gala_launchpad_get_liquidity_position_by_id` | Get one current-contract GSwap position by its pair, fee, owner, and tick range | no | `token0`*, `token1`*, `fee`*, `tickLower`*, `tickUpper`*, `ownerAddress`* | | `gala_launchpad_get_liquidity_position` | Get one current-contract GSwap position by pair, owner, and tick range | no | `token0`*, `token1`*, `fee`*, `tickLower`*, `tickUpper`*, `ownerAddress`* | ### calculate | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_calculate_dex_pool_quote_local` | Calculate a DEX quote through the v6 GSwap quoting service | no | `token0`*, `token1`*, `fee`*, `fromToken`*, `toToken`*, `amount`* | | `gala_launchpad_calculate_dex_pool_quote_external` | Calculate a server-backed DEX quote through the v6 GSwap quoting service | no | `token0`*, `token1`*, `fee`*, `fromToken`*, `toToken`*, `amount`* | ### execute | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_execute_swap` | Execute a GSwap trade through gswap-sdk (gSwap.swaps.swap) and return its confirmation result | no | `fromToken`*, `toToken`*, `inputAmount`*, `estimatedOutput`*, `feeTier`*, `slippageTolerance` | ### fetch | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_fetch_dex_pools` | Fetch current-contract GSwap pools through gswap-sdk (gSwap.pools.getPools) | no | `search`, `sortBy`, `sortOrder`, `cursor`, `pageSize` | | `gala_launchpad_fetch_all_dex_pools` | Fetch all current-contract GSwap pools through gswap-sdk (gSwap.pools.getPools) | no | `search`, `sortBy`, `sortOrder`, `withPrices` | | `gala_launchpad_fetch_composite_pool_data` | Fetch a current-contract GSwap composite pool snapshot through gswap-sdk (gSwap.pools.getCompositePool) | no | `token0`*, `token1`*, `fee`* | | `gala_launchpad_fetch_available_dex_tokens` | List registered GSwap trading symbols through gswap-sdk (gSwap.symbols.list) | no | `search`, `pageSize`, `cursor` | | `gala_launchpad_fetch_all_available_dex_tokens` | List all registered GSwap trading symbols through gswap-sdk (gSwap.symbols.list) | no | `search` | | `gala_launchpad_fetch_swap_position_direct` | Fetch one current-contract GSwap position by its compound pair and tick key | no | `token0`*, `token1`*, `fee`*, `tickLower`*, `tickUpper`*, `ownerAddress`* | | `gala_launchpad_fetch_all_dex_seasons` | Fetch all DEX leaderboard seasons - returns complete list of seasons with dates and rules | no | - | | `gala_launchpad_fetch_current_dex_season` | Fetch current active DEX leaderboard season - returns null if no season is active | no | - | | `gala_launchpad_fetch_dex_leaderboard_by_season_id` | Fetch DEX leaderboard for a specific season - returns rankings with XP metrics and achievements | no | `seasonId`* | | `gala_launchpad_fetch_current_dex_leaderboard` | Fetch current DEX leaderboard for active season - returns null if no active season | no | - | | `gala_launchpad_fetch_dex_aggregated_volume_summary` | Fetch DEX aggregated volume summary with 1d/7d/30d volume (USD) and deltas (fraction of the previous period: -0.11 is 11% less) | no | - | | `gala_launchpad_fetch_gala_spot_price` | Fetch current GALA USD spot price (convenience method) | no | - | ### estimate | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_estimate_remove_liquidity` | Estimate token amounts released by a current-contract GSwap liquidity withdrawal | no | `token0`*, `token1`*, `fee`*, `tickLower`*, `tickUpper`*, `liquidity`*, `ownerAddress`* | ### add | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_add_liquidity_by_price` | Add liquidity through gswap-sdk (gSwap.positions.addLiquidityByPrice) and return confirm() output | no | `token0`*, `token1`*, `fee`*, `minPrice`*, `maxPrice`*, `amount0Desired`*, `amount1Desired`*, `amount0Min`, `amount1Min`, `amountIsToken0` | | `gala_launchpad_add_liquidity_by_ticks` | Add liquidity through gswap-sdk (gSwap.positions.addLiquidityByTicks) and return confirm() output | no | `token0`*, `token1`*, `fee`*, `tickLower`*, `tickUpper`*, `amount0Desired`*, `amount1Desired`*, `amount0Min`, `amount1Min`, `amountIsToken0` | ### remove | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_remove_liquidity` | Remove current-contract GSwap liquidity and return confirm() output | no | `token0`*, `token1`*, `fee`*, `tickLower`*, `tickUpper`*, `ownerAddress`*, `liquidity`, `amount0`, `amount1` | ### collect | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_collect_position_fees` | Collect current-contract GSwap position fees and return confirm() output | no | `token0`*, `token1`*, `fee`*, `tickLower`*, `tickUpper`*, `ownerAddress`* | ### on | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_on_dex_pool_creation` | Watch for new DEX pool creation by polling, not a real-time push event | no | `minTVL`, `tokens`, `intervalMs`, `durationSeconds` | ## Prompts | Prompt | Tier | What it does | Arguments | Tools it names | | --- | --- | --- | --- | --- | | `galachain-launchpad:discover-pools` | legacy | Discover DEX liquidity pools with filtering and analysis - find hot pools, high TVL, or high volume trading opportunities | `search`, `sortBy`, `sortOrder`, `minTvl`, `minVolume`, `page`, `limit` | `gala_launchpad_fetch_dex_pools` | | `galachain-launchpad:fetch-all-pools` | legacy | Fetch ALL DEX liquidity pools with auto-pagination for comprehensive analysis | `sortBy`, `sortOrder` | `gala_launchpad_fetch_all_dex_pools` | | `galachain-launchpad:check-leaderboard` | legacy | View top DEX pools ranked by TVL, volume, or APR | `metric`, `limit` | `gala_launchpad_fetch_current_dex_leaderboard` | | `galachain-launchpad:manage-liquidity` | legacy | Complete liquidity provider workflow - deposit liquidity, monitor positions, collect fees, and manage LP strategies | `action`*, `token0`, `token1`, `feeTier`, `minPrice`, `maxPrice` | `gala_launchpad_add_liquidity_by_price`, `gala_launchpad_collect_position_fees`, `gala_launchpad_estimate_remove_liquidity`, `gala_launchpad_get_swap_pool_price`, `gala_launchpad_get_swap_user_assets`, `gala_launchpad_get_user_liquidity_positions`, `gala_launchpad_remove_liquidity` | | `galachain-launchpad:add-liquidity-by-price` | legacy | Create new LP position by specifying price range and token amounts | `token0`*, `token1`*, `feeTier`*, `minPrice`*, `maxPrice`*, `amount0`*, `amount1`* | `gala_launchpad_add_liquidity_by_price`, `gala_launchpad_get_swap_pool_price` | | `galachain-launchpad:collect-fees` | legacy | Collect accumulated swap fees from your LP positions | `positionId`* | `gala_launchpad_collect_position_fees`, `gala_launchpad_get_user_liquidity_positions` | | `galachain-launchpad:remove-liquidity` | legacy | Exit an LP position and retrieve your tokens | `positionId`* | `gala_launchpad_estimate_remove_liquidity`, `gala_launchpad_get_user_liquidity_positions`, `gala_launchpad_remove_liquidity` | | `galachain-launchpad:optimize-liquidity` | legacy | Advanced liquidity optimization strategies - multi-tier positions, fee tier selection, range management | `tokenPair`*, `strategy`, `targetYield` | - | | `galachain-launchpad:advanced-positions` | legacy | Advanced liquidity position management - multi-leg strategies, fee collection, position monitoring | `action`*, `positionId` | - | | `galachain-launchpad:liquidity-strategy` | legacy | Plan and optimize liquidity provision strategy based on market conditions and risk tolerance | `marketCondition`, `riskTolerance` | - | | `galachain-launchpad:fetch-available-dex-tokens` | legacy | Discover all tokens available for trading on the DEX with rich metadata | `search`, `all` | `gala_launchpad_fetch_all_available_dex_tokens`, `gala_launchpad_fetch_available_dex_tokens` | | `galachain-launchpad:dex-swap` | legacy | Execute a token swap on GalaSwap DEX for graduated tokens | `fromToken`*, `toToken`*, `amount`*, `slippage` | `gala_launchpad_execute_swap`, `gala_launchpad_get_swap_pool_info`, `gala_launchpad_get_swap_quote_exact_input`, `gala_launchpad_get_swap_quote_exact_output`, `gala_launchpad_get_swap_result`, `gala_launchpad_get_swap_user_assets` | | `galachain-launchpad:get-all-swap-user-assets` | legacy | Get ALL token assets for a wallet with automatic pagination | `walletAddress`* | `gala_launchpad_get_all_swap_user_assets` | | `galachain-launchpad:fetch-composite-pool-data` | legacy | Fetch complete pool state for offline DEX quote calculations | `token0`*, `token1`*, `fee`* | `gala_launchpad_fetch_composite_pool_data`, `gala_launchpad_get_swap_quote_exact_input` | | `galachain-launchpad:calculate-dex-pool-quote` | legacy | Calculate DEX swap quote using local or external calculation | `token0`*, `token1`*, `fee`*, `fromToken`*, `toToken`*, `amount`*, `mode` | `gala_launchpad_calculate_dex_pool_quote_local` | | `galachain-launchpad:fetch-dex-pools` | legacy | Discover DEX liquidity pools with pagination, sorting, and search filtering | `search`, `sortBy`, `sortOrder`, `page`, `limit` | `gala_launchpad_fetch_dex_pools` | | `galachain-launchpad:fetch-all-dex-pools` | legacy | Discover ALL DEX liquidity pools with automatic pagination | `search`, `sortBy`, `sortOrder` | `gala_launchpad_fetch_all_dex_pools` | | `galachain-launchpad:my-positions` | legacy | View all your open liquidity positions on GalaSwap DEX with details about each position | - | `gala_launchpad_get_user_liquidity_positions` | | `galachain-launchpad:add-liquidity` | legacy | Add liquidity to a GalaSwap DEX pool | `token0`*, `token1`*, `amount0`*, `amount1`*, `minPrice`, `maxPrice`, `feeTier` | `gala_launchpad_add_liquidity_by_price`, `gala_launchpad_get_swap_pool_info`, `gala_launchpad_get_swap_user_assets` | | `galachain-launchpad:get-all-liquidity-positions` | legacy | Get ALL liquidity positions for a wallet with automatic pagination and optional pricing | `ownerAddress`*, `withPrices` | `gala_launchpad_get_all_user_liquidity_positions` | | `galachain-launchpad:estimate-remove-liquidity` | legacy | Estimate tokens and fees received when removing liquidity from a position | `token0`*, `token1`*, `fee`*, `liquidity`*, `tickLower`*, `tickUpper`*, `ownerAddress`* | `gala_launchpad_estimate_remove_liquidity` | | `galachain-launchpad:fetch-position-direct` | legacy | Fetch a single liquidity position using the compound key (most efficient when you have all position parameters) | `token0`*, `token1`*, `fee`*, `tickLower`*, `tickUpper`*, `owner`* | `gala_launchpad_fetch_swap_position_direct` | | `galachain-launchpad:fetch-gala-spot-price` | legacy | Fetch current GALA USD spot price | - | `gala_launchpad_fetch_gala_spot_price` | | `galachain-launchpad:watch-dex-pools` | legacy | Watch for new DEX pools by polling the swap backend pool list (not the realtime stream) | `duration`, `minTVL`, `tokens` | `gala_launchpad_on_dex_pool_creation` | | `galachain-launchpad:fetch-all-dex-seasons` | legacy | Fetch all DEX leaderboard seasons - explore season dates and rules | - | `gala_launchpad_fetch_current_dex_season`, `gala_launchpad_fetch_dex_leaderboard_by_season_id` | | `galachain-launchpad:fetch-current-dex-season` | legacy | Fetch the currently active DEX leaderboard season | - | `gala_launchpad_fetch_all_dex_seasons`, `gala_launchpad_fetch_current_dex_leaderboard`, `gala_launchpad_fetch_dex_leaderboard_by_season_id` | | `galachain-launchpad:fetch-dex-leaderboard-by-season-id` | legacy | Fetch DEX leaderboard rankings for a specific season | `seasonId`* | `gala_launchpad_fetch_all_dex_seasons`, `gala_launchpad_fetch_current_dex_leaderboard`, `gala_launchpad_fetch_current_dex_season` | | `galachain-launchpad:fetch-current-dex-leaderboard` | legacy | Fetch DEX leaderboard rankings for the currently active season | - | `gala_launchpad_fetch_all_dex_seasons`, `gala_launchpad_fetch_current_dex_season`, `gala_launchpad_fetch_dex_leaderboard_by_season_id` | | `galachain-launchpad:fetch-dex-aggregated-volume-summary` | legacy | Fetch DEX aggregated volume summary with 1d/7d/30d trend metrics | - | `gala_launchpad_fetch_all_dex_pools`, `gala_launchpad_fetch_dex_pools`, `gala_launchpad_get_swap_quote_exact_input` | | `galachain-launchpad:subscribe-dex-liquidity-added` | legacy | Subscribe to real-time DEX liquidity addition events via WebSocket connection | `duration`, `minLiquidity` | `gala_launchpad_on_dex_pool_creation` | | `galachain-launchpad:subscribe-dex-liquidity-changed` | legacy | Subscribe to real-time DEX liquidity modification events via WebSocket connection | `duration` | `gala_launchpad_on_dex_pool_creation` | | `galachain-launchpad:subscribe-dex-liquidity-removed` | legacy | Subscribe to real-time DEX liquidity removal events via WebSocket connection | `duration`, `minAmount` | `gala_launchpad_on_dex_pool_creation` | | `galachain-launchpad:subscribe-dex-pool-added` | legacy | Watch for new DEX pools by polling the swap backend pool list (not the realtime stream) | `duration`, `feeTier` | `gala_launchpad_on_dex_pool_creation` | | `galachain-launchpad:subscribe-dex-swap-executed` | legacy | Subscribe to real-time DEX swap execution events via WebSocket connection | `duration`, `minAmount` | `gala_launchpad_on_dex_pool_creation` | --- # composite toolset: tools and prompts The `composite` toolset of `@gala-chain/gala-mcp-server` 1.0.0-rc.9 provides tools that need both the Launchpad and the GSwap client, enabled exactly when both toolsets are. It defines 3 tools and 9 prompts. A prompt is offered only when every tool it names is registered by the selection. The same data, with every parameter's type and description, is at `/mcp/composite/tools.json`. `*` marks a required parameter. Tools whose description says they need authentication need a wallet in full-access mode. ## Tools ### fetch | Tool | What it does | Auth | Parameters | | --- | --- | --- | --- | | `gala_launchpad_fetch_token_spot_price` | Fetch USD spot price for ANY token with smart routing | no | `tokenName`, `tokenId`, `currentSupply`, `calculateAmountMode` | | `gala_launchpad_fetch_price_history` | Fetch historical price snapshots for DEX tokens from the DEX Backend API | no | `tokenName`, `tokenId`, `from`, `to`, `sortOrder`, `cursor`, `pageSize` | | `gala_launchpad_fetch_all_price_history` | Fetch all historical price snapshots for DEX tokens from the DEX Backend API with automatic pagination | no | `tokenName`, `tokenId`, `from`, `to`, `sortOrder` | ## Prompts | Prompt | Tier | What it does | Arguments | Tools it names | | --- | --- | --- | --- | --- | | `galachain-launchpad:price-trends` | legacy | Analyze token price history and trends - technical analysis, volatility assessment, and price discovery | `tokenName`*, `days` | `gala_launchpad_fetch_price_history`, `gala_launchpad_fetch_token_spot_price` | | `galachain-launchpad:fetch-price-history` | tier1 | Get historical price data for technical analysis and trend identification | `tokenName`*, `days` | `gala_launchpad_fetch_price_history` | | `galachain-launchpad:fetch-current-price` | legacy | Get current USD spot price for any token | `tokenName`* | `gala_launchpad_fetch_token_spot_price` | | `galachain-launchpad:fetch-all-price-history` | tier1 | Get complete price history with auto-pagination for comprehensive historical analysis (Node.js only) | `tokenName`* | `gala_launchpad_fetch_all_price_history` | | `galachain-launchpad:portfolio` | legacy | Analyze complete portfolio with GALA balance, token holdings, and total USD value | - | `gala_launchpad_fetch_gala_balance`, `gala_launchpad_fetch_gala_spot_price`, `gala_launchpad_fetch_launchpad_token_spot_price`, `gala_launchpad_fetch_pool_details_for_calculation`, `gala_launchpad_fetch_tokens_held` | | `galachain-launchpad:balance` | legacy | Check GALA balance and optionally a specific token balance | `tokenName` | `gala_launchpad_fetch_gala_balance`, `gala_launchpad_fetch_gala_spot_price`, `gala_launchpad_fetch_launchpad_token_spot_price`, `gala_launchpad_fetch_token_balance` | | `galachain-launchpad:spot-prices` | legacy | Get spot prices for multiple Launchpad tokens efficiently | `tokens`* | `gala_launchpad_fetch_gala_spot_price`, `gala_launchpad_fetch_launchpad_token_spot_price`, `gala_launchpad_fetch_pool_details_for_calculation` | | `galachain-launchpad:fetch-token-spot-price` | legacy | Fetch USD spot price for any token (launchpad or DEX) | `tokenName`* | `gala_launchpad_fetch_token_spot_price` | | `galachain-launchpad:subscribe-to-event` | legacy | Subscribe to any event type with custom parameters via WebSocket | `eventType`*, `duration`, `filters` | `gala_launchpad_on_dex_pool_creation`, `gala_launchpad_on_launchpad_token_creation` |