Summary
Since ~2026-08-31, GalaSwap POST /bundle rejects Swap submissions for any pool whose token composite keys are long enough that a derived stringsInstructions entry exceeds 128 characters:
(400) each value in stringsInstructions must be shorter than or equal to 128 characters
This is not a caller error. The offending strings are constructed deterministically from the pool's own token class keys — by gswap-sdk itself — so the limit makes a subset of GalaSwap's own live pools structurally unswappable. 39 of 186 pools (21%) currently returned by explore/pools cannot be swapped, including pools holding real TVL.
The strings are derived, not caller-supplied
gswap-sdk/src/classes/swaps.ts:115-128 builds all five entries from the pool identity:
const poolString = `$pool$${token0StringKey}$${token1StringKey}$${fee}`;
const tokenBalance0 = `$tokenBalance$${token0StringKey}$${walletAddress}`;
const tokenBalance1 = `$tokenBalance$${token1StringKey}$${walletAddress}`;
const tokenBalance0Pool = `$tokenBalance$${token0StringKey}$${poolString}`;
const tokenBalance1Pool = `$tokenBalance$${token1StringKey}$${poolString}`;
tokenBalance{0,1}Pool embed a token key and poolString, which already contains both token keys — so the longest entry grows as 2 × len(token0) + len(token1) + 23. A caller has no way to shorten it.
Concrete, using only public data (GALA/MOON, 1% fee):
$tokenBalance$Token$Unit$MOON$eth:321485B12C6b7aEd3888D240Df3e3E8Ee79e7393$$pool$GALA$Unit$none$none$Token$Unit$MOON$eth:321485B12C6b7aEd3888D240Df3e3E8Ee79e7393$10000
167 characters. Rejected.
The trigger is launchpad/bridged tokens whose composite keys carry a creator suffix. GALA$Unit$none$none is 19 chars; Token$Unit$MOON$eth:321485B12C6b7aEd3888D240Df3e3E8Ee79e7393 is 60. Two ordinary keys fit comfortably; one long key does not.
Scope
Computed over all 186 pools from GET /explore/pools, using each pool's own token0CompositeKey / token1CompositeKey / fee and a standard 45-char eth|… wallet address:
- 39 of 186 pools (21.0%) produce at least one instruction over 128 chars
- Worst case:
FIM/SMOOV at 209 chars
- Affected pairs include
GALA/MOON (167), GALA/BENE (141/140), GALA/DKP (164), GALA/FGC (139), GALA/TSP (139), GALA/STU (165), GALA/FIM (165), GALA/SMOOV (169), GALA/GRILLZ (170), GALA/ALIEN (168), GALA/PUMPX (168), GUSDC/MOON, GUSDT/MOON, GUSDC/BENE, GUSDT/BENE, BENE/MOON (195)
These pools accept liquidity and are listed as tradeable, but every swap against them 400s.
Timeline
These pools swapped successfully as recently as 2026-08-11 (confirmed against our own execution history, 19/19 successful swaps through GALA/MOON and GALA/BENE pools). First stringsInstructions rejection observed 2026-09-01 02:52:48 UTC. 401 rejections since, 100% of attempts. No change on our side in that window.
Suspected cause — hypothesis, not a diagnosis
I can't see where the validator is declared (stringsInstructions doesn't appear in this repo — it's the bundler request envelope), so this may belong on the bundler or GalaChain/dex instead; happy to move it.
But the timing lines up with the #811 strict-whitelist rollout:
| when (UTC) |
what |
| 2026-08-26 10:33 |
v3.2.0 — #811 "Reject unknown DTO properties during validation" |
| 2026-08-26 11:55 |
GalaChain/dex #89 "Mark optional liquidity DTO fields callers already send" |
| 2026-08-27 17:05 |
GalaChain/dex v1.1.4 pins @gala-chain/api 3.2.0 |
| 2026-08-27 09:59 |
v3.2.1 — #819 mark optional oracle DTO filters for whitelist |
| 2026-08-31 14:30 |
v3.2.2 — #821 add back legacy balance field |
| 2026-08-31 18:39 |
v3.2.3 — #823 remove validation on balance responses |
| 2026-09-01 02:52 |
first stringsInstructions 128-char rejection |
| 2026-09-02 13:39 |
#825 merged — "the third face of the #811 strict-whitelist rollout" |
#825 describes the mechanism precisely: "Whitelist validation only recognizes properties that carry at least one validator decorator, so an undecorated property is 'unknown' even on its own class."
If stringsInstructions was previously undecorated, #811 would have made it fail whitelist validation, and the fix would be to add a decorator. My guess is that the decorator added was @MaxLength(128, { each: true }) — the error text is that decorator's verbatim class-validator output, and the each value in prefix is exactly how class-validator renders { each: true }. If so, 128 was a default reached for rather than a deliberate protocol limit, and this would be the fourth face of the same rollout.
Expected behaviour
Either:
- The cap is raised or removed for
stringsInstructions — the entries are protocol-derived state keys whose length is a function of token composite keys the platform itself issues, so no fixed cap that is shorter than the longest constructible key is safe; or
- If a cap is genuinely intended, GalaSwap should not list pools whose swaps can never validate — and
gswap-sdk should surface the constraint at quote/route time rather than as a 400 at submit.
Environment
- Bundler:
https://bundle-backend-prod1.defi.gala.com/bundle
- Backend:
https://dex-backend-prod1.defi.gala.com
- Client: a Go implementation constructing the identical five
stringsInstructions entries as gswap-sdk/src/classes/swaps.ts
@gala-chain/dex on main is v1.1.4, pinning @gala-chain/api 3.2.0
Summary
Since ~2026-08-31, GalaSwap
POST /bundlerejectsSwapsubmissions for any pool whose token composite keys are long enough that a derivedstringsInstructionsentry exceeds 128 characters:This is not a caller error. The offending strings are constructed deterministically from the pool's own token class keys — by
gswap-sdkitself — so the limit makes a subset of GalaSwap's own live pools structurally unswappable. 39 of 186 pools (21%) currently returned byexplore/poolscannot be swapped, including pools holding real TVL.The strings are derived, not caller-supplied
gswap-sdk/src/classes/swaps.ts:115-128builds all five entries from the pool identity:tokenBalance{0,1}Poolembed a token key andpoolString, which already contains both token keys — so the longest entry grows as2 × len(token0) + len(token1) + 23. A caller has no way to shorten it.Concrete, using only public data (
GALA/MOON, 1% fee):167 characters. Rejected.
The trigger is launchpad/bridged tokens whose composite keys carry a creator suffix.
GALA$Unit$none$noneis 19 chars;Token$Unit$MOON$eth:321485B12C6b7aEd3888D240Df3e3E8Ee79e7393is 60. Two ordinary keys fit comfortably; one long key does not.Scope
Computed over all 186 pools from
GET /explore/pools, using each pool's owntoken0CompositeKey/token1CompositeKey/feeand a standard 45-chareth|…wallet address:FIM/SMOOVat 209 charsGALA/MOON(167),GALA/BENE(141/140),GALA/DKP(164),GALA/FGC(139),GALA/TSP(139),GALA/STU(165),GALA/FIM(165),GALA/SMOOV(169),GALA/GRILLZ(170),GALA/ALIEN(168),GALA/PUMPX(168),GUSDC/MOON,GUSDT/MOON,GUSDC/BENE,GUSDT/BENE,BENE/MOON(195)These pools accept liquidity and are listed as tradeable, but every swap against them 400s.
Timeline
These pools swapped successfully as recently as 2026-08-11 (confirmed against our own execution history, 19/19 successful swaps through
GALA/MOONandGALA/BENEpools). FirststringsInstructionsrejection observed 2026-09-01 02:52:48 UTC. 401 rejections since, 100% of attempts. No change on our side in that window.Suspected cause — hypothesis, not a diagnosis
I can't see where the validator is declared (
stringsInstructionsdoesn't appear in this repo — it's the bundler request envelope), so this may belong on the bundler orGalaChain/dexinstead; happy to move it.But the timing lines up with the
#811strict-whitelist rollout:v3.2.0— #811 "Reject unknown DTO properties during validation"GalaChain/dex#89 "Mark optional liquidity DTO fields callers already send"GalaChain/dexv1.1.4 pins@gala-chain/api3.2.0v3.2.1— #819 mark optional oracle DTO filters for whitelistv3.2.2— #821 add back legacy balance fieldv3.2.3— #823 remove validation on balance responsesstringsInstructions128-char rejection#825 describes the mechanism precisely: "Whitelist validation only recognizes properties that carry at least one validator decorator, so an undecorated property is 'unknown' even on its own class."
If
stringsInstructionswas previously undecorated, #811 would have made it fail whitelist validation, and the fix would be to add a decorator. My guess is that the decorator added was@MaxLength(128, { each: true })— the error text is that decorator's verbatimclass-validatoroutput, and theeach value inprefix is exactly howclass-validatorrenders{ each: true }. If so, 128 was a default reached for rather than a deliberate protocol limit, and this would be the fourth face of the same rollout.Expected behaviour
Either:
stringsInstructions— the entries are protocol-derived state keys whose length is a function of token composite keys the platform itself issues, so no fixed cap that is shorter than the longest constructible key is safe; orgswap-sdkshould surface the constraint at quote/route time rather than as a 400 at submit.Environment
https://bundle-backend-prod1.defi.gala.com/bundlehttps://dex-backend-prod1.defi.gala.comstringsInstructionsentries asgswap-sdk/src/classes/swaps.ts@gala-chain/dexonmainis v1.1.4, pinning@gala-chain/api3.2.0