Skip to main content

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​

JobPackage
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​

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.

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.

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​

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​

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|<EIP-55 checksummed 40 hex digits> 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<hex> 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.

CodeMeaningFix
SUBMISSION_OUTCOME_UNKNOWNThe write POST got no answer (timeout or lost connection).Confirm by error.uniqueKey before any retry.
CONFIRMATION_TIMEOUTconfirm() did not see the apply result in time.Call confirm() again with the same uniqueKey; do not resubmit.
CHAIN_REJECTEDThe chain applied the request and rejected it.Read error.body; fix the input and submit a new swap.
INSUFFICIENT_LIQUIDITYThe pool cannot fill the amount.Quote a smaller amount or another fee tier.
NO_POOL_AVAILABLENo pool exists for the pair.Check the pair and fee tier with gSwap.pools.
NO_SIGNERA write was attempted on a client built without a signer.Pass signer and walletAddress to the constructor.
AMOUNT_IS_JS_NUMBERA JavaScript number was given as an amount.Pass the amount as a decimal string.
TICKS_NOT_ALIGNEDA tick is not divisible by the fee tier's spacing.Align the ticks, or use addLiquidityByPrice.
RATE_LIMITEDThe backend asked the client to slow down.Wait error.retryAfterMs and retry the read.
UPDATE_REQUIREDThe backend refuses this client version (HTTP 426).Upgrade the SDK.
INVALID_ETH_USER_REF_PREFIXAn address was written eth|0x<hex>.Write eth|<EIP-55 digits> or the bare 0x<hex>.