@gala-chain/launchpad-sdk 3.31.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/API.md +524 -4
  2. package/CHANGELOG.md +92 -0
  3. package/EXAMPLES.md +845 -0
  4. package/README.md +421 -14
  5. package/dist/LaunchpadSDK.d.ts +435 -18
  6. package/dist/LaunchpadSDK.d.ts.map +1 -1
  7. package/dist/api/LaunchpadAPI.d.ts.map +1 -1
  8. package/dist/api/dto/TransferTokenDto.d.ts.map +1 -1
  9. package/dist/constants/version.generated.d.ts +1 -1
  10. package/dist/constants/version.generated.d.ts.map +1 -1
  11. package/dist/helpers/sdk.d.ts +1 -0
  12. package/dist/helpers/sdk.d.ts.map +1 -1
  13. package/dist/index.cjs.js +1 -1
  14. package/dist/index.d.ts +10 -3
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.esm.js +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/services/BaseService.d.ts +32 -3
  19. package/dist/services/BaseService.d.ts.map +1 -1
  20. package/dist/services/BundleService.d.ts.map +1 -1
  21. package/dist/services/CommentService.d.ts.map +1 -1
  22. package/dist/services/DexBackendClient.d.ts +46 -0
  23. package/dist/services/DexBackendClient.d.ts.map +1 -0
  24. package/dist/services/DexPoolService.d.ts +54 -12
  25. package/dist/services/DexPoolService.d.ts.map +1 -1
  26. package/dist/services/DexQuoteService.d.ts +288 -0
  27. package/dist/services/DexQuoteService.d.ts.map +1 -0
  28. package/dist/services/DexService.d.ts.map +1 -1
  29. package/dist/services/FaucetService.d.ts.map +1 -1
  30. package/dist/services/GSwapService.d.ts +519 -44
  31. package/dist/services/GSwapService.d.ts.map +1 -1
  32. package/dist/services/GalaChainGatewayClient.d.ts +89 -0
  33. package/dist/services/GalaChainGatewayClient.d.ts.map +1 -0
  34. package/dist/services/GalaChainService.d.ts +26 -0
  35. package/dist/services/GalaChainService.d.ts.map +1 -1
  36. package/dist/services/ImageService.d.ts.map +1 -1
  37. package/dist/services/PoolService.d.ts.map +1 -1
  38. package/dist/services/PoolStateManager.d.ts +176 -0
  39. package/dist/services/PoolStateManager.d.ts.map +1 -0
  40. package/dist/services/PriceHistoryService.d.ts +4 -5
  41. package/dist/services/PriceHistoryService.d.ts.map +1 -1
  42. package/dist/services/SignatureService.d.ts +15 -38
  43. package/dist/services/SignatureService.d.ts.map +1 -1
  44. package/dist/services/TokenClassKeyService.d.ts +3 -4
  45. package/dist/services/TokenClassKeyService.d.ts.map +1 -1
  46. package/dist/services/TokenMetadataCache.d.ts +2 -2
  47. package/dist/services/TokenMetadataCache.d.ts.map +1 -1
  48. package/dist/services/TokenMetadataService.d.ts +3 -3
  49. package/dist/services/TokenMetadataService.d.ts.map +1 -1
  50. package/dist/services/TokenResolverService.d.ts +2 -2
  51. package/dist/services/TokenResolverService.d.ts.map +1 -1
  52. package/dist/services/TradeService.d.ts.map +1 -1
  53. package/dist/services/UserService.d.ts.map +1 -1
  54. package/dist/services/WebSocketService.d.ts +100 -2
  55. package/dist/services/WebSocketService.d.ts.map +1 -1
  56. package/dist/services/__mocks__/logger.mock.d.ts +17 -0
  57. package/dist/services/__mocks__/logger.mock.d.ts.map +1 -0
  58. package/dist/types/common.d.ts +2 -0
  59. package/dist/types/common.d.ts.map +1 -1
  60. package/dist/types/composite-pool.dto.d.ts +103 -0
  61. package/dist/types/composite-pool.dto.d.ts.map +1 -0
  62. package/dist/types/dex-pool.dto.d.ts +56 -5
  63. package/dist/types/dex-pool.dto.d.ts.map +1 -1
  64. package/dist/types/dto.d.ts +6 -6
  65. package/dist/types/dto.d.ts.map +1 -1
  66. package/dist/types/eip712-types.d.ts +140 -0
  67. package/dist/types/eip712-types.d.ts.map +1 -0
  68. package/dist/types/galachain-api.types.d.ts +206 -0
  69. package/dist/types/galachain-api.types.d.ts.map +1 -0
  70. package/dist/types/gswap-responses.types.d.ts +366 -0
  71. package/dist/types/gswap-responses.types.d.ts.map +1 -0
  72. package/dist/types/gswap.dto.d.ts +58 -3
  73. package/dist/types/gswap.dto.d.ts.map +1 -1
  74. package/dist/types/launchpad.dto.d.ts +57 -0
  75. package/dist/types/launchpad.dto.d.ts.map +1 -1
  76. package/dist/types/pool-state-delta.dto.d.ts +246 -0
  77. package/dist/types/pool-state-delta.dto.d.ts.map +1 -0
  78. package/dist/types/pool-state-manager-config.dto.d.ts +103 -0
  79. package/dist/types/pool-state-manager-config.dto.d.ts.map +1 -0
  80. package/dist/utils/SignatureHelper.d.ts.map +1 -1
  81. package/dist/utils/auto-pagination.d.ts +206 -0
  82. package/dist/utils/auto-pagination.d.ts.map +1 -0
  83. package/dist/utils/bignumber-helpers.d.ts +336 -0
  84. package/dist/utils/bignumber-helpers.d.ts.map +1 -0
  85. package/dist/utils/bignumber-pool-cache.d.ts +169 -0
  86. package/dist/utils/bignumber-pool-cache.d.ts.map +1 -0
  87. package/dist/utils/composite-pool-converter.d.ts +121 -0
  88. package/dist/utils/composite-pool-converter.d.ts.map +1 -0
  89. package/dist/utils/errors.d.ts +86 -0
  90. package/dist/utils/errors.d.ts.map +1 -1
  91. package/dist/utils/http.d.ts.map +1 -1
  92. package/dist/utils/load-env.d.ts +31 -0
  93. package/dist/utils/load-env.d.ts.map +1 -0
  94. package/dist/utils/pool-pair-parser.d.ts +55 -0
  95. package/dist/utils/pool-pair-parser.d.ts.map +1 -0
  96. package/dist/utils/pool-state-validator.d.ts +207 -0
  97. package/dist/utils/pool-state-validator.d.ts.map +1 -0
  98. package/dist/utils/position-filters.d.ts +253 -0
  99. package/dist/utils/position-filters.d.ts.map +1 -0
  100. package/dist/utils/swap-delta-calculator.d.ts +231 -0
  101. package/dist/utils/swap-delta-calculator.d.ts.map +1 -0
  102. package/dist/utils/tick-crossing-handler.d.ts +250 -0
  103. package/dist/utils/tick-crossing-handler.d.ts.map +1 -0
  104. package/dist/utils/token-format-converter.d.ts +85 -6
  105. package/dist/utils/token-format-converter.d.ts.map +1 -1
  106. package/dist/utils/token-parser.d.ts +235 -0
  107. package/dist/utils/token-parser.d.ts.map +1 -0
  108. package/dist/utils/tokenNormalizer.d.ts +66 -0
  109. package/dist/utils/tokenNormalizer.d.ts.map +1 -1
  110. package/dist/utils/transfer-validation.d.ts.map +1 -1
  111. package/dist/utils/validation-helpers.d.ts +75 -0
  112. package/dist/utils/validation-helpers.d.ts.map +1 -1
  113. package/package.json +36 -15
  114. package/dist/utils/tokenFormatConverter.d.ts +0 -53
  115. package/dist/utils/tokenFormatConverter.d.ts.map +0 -1
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Safe Token Parser - Comprehensive token format validation and parsing
3
+ *
4
+ * Handles STRICT parsing of token formats received from APIs:
5
+ * - Pipe-delimited: "GALA|Unit|none|none"
6
+ * - Dollar-delimited: "GALA$Unit$none$none"
7
+ * - Dollar with $ in collection: "$MUSIC$Unit$none$none" (parses from END)
8
+ *
9
+ * CRITICAL SECURITY NOTE:
10
+ * Plain strings like "GALA" are REJECTED by default - they are not valid token formats!
11
+ * Token formats MUST be explicitly delimited with | or $.
12
+ * This prevents dangerous assumptions about token structure.
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+ import type { TokenClassKey } from '../types/common';
17
+ /**
18
+ * PERFORMANCE CHARACTERISTICS:
19
+ *
20
+ * Fast-path (O(n) where n = token length):
21
+ * - Pipe-delimited tokens: Direct split() call, minimal string operations
22
+ * - Dollar-delimited tokens: Reverse algorithm, ~2x string operations
23
+ *
24
+ * Slow-path (format detection):
25
+ * - Plain strings without delimiters: Requires fallback logic
26
+ * - Type validation: Object instanceof checks for already-parsed tokens
27
+ *
28
+ * Recommendation: Pre-detect format when parsing large token batches:
29
+ * ```typescript
30
+ * import { isPipeDelimited, isDollarDelimited } from './token-parser';
31
+ *
32
+ * if (isPipeDelimited(token)) {
33
+ * return parsePipeDelimitedToken(token); // Fastest path
34
+ * } else if (isDollarDelimited(token)) {
35
+ * return parseDollarDelimitedTokenSafe(token); // Fast path
36
+ * }
37
+ * ```
38
+ */
39
+ /**
40
+ * Parse token from ANY format (pipe/dollar delimited) into TokenClassKey
41
+ *
42
+ * Accepts:
43
+ * - Pipe format: "GALA|Unit|none|none"
44
+ * - Dollar format: "GALA$Unit$none$none"
45
+ * - Dollar with $ in collection: "$MUSIC$Unit$none$none"
46
+ * - TokenClassKey objects: { collection, category, type, additionalKey }
47
+ *
48
+ * REJECTS:
49
+ * - Plain strings like "GALA" (DANGEROUS - no delimiters!)
50
+ * - Null/undefined values
51
+ * - Invalid formats
52
+ *
53
+ * ⚠️ SECURITY ENFORCEMENT (v3.33.0+):
54
+ * Plain token strings are NO LONGER accepted. All tokens must use explicit delimiters.
55
+ * This is a breaking change to enforce secure token format validation.
56
+ *
57
+ * @param token Token string to parse
58
+ * @returns TokenClassKey with { collection, category, type, additionalKey }
59
+ * @throws ValidationError if format is invalid or if plain string is provided
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * // Pipe-delimited (RECOMMENDED)
64
+ * parseToken("GALA|Unit|none|none")
65
+ * // → { collection: "GALA", category: "Unit", type: "none", additionalKey: "none" }
66
+ *
67
+ * // Dollar-delimited
68
+ * parseToken("GALA$Unit$none$none")
69
+ * // → { collection: "GALA", category: "Unit", type: "none", additionalKey: "none" }
70
+ *
71
+ * // Dollar with $ in collection (EDGE CASE)
72
+ * parseToken("$MUSIC$Unit$none$none")
73
+ * // → { collection: "$MUSIC", category: "Unit", type: "none", additionalKey: "none" }
74
+ *
75
+ * // TokenClassKey object
76
+ * parseToken({ collection: "GALA", category: "Unit", type: "none", additionalKey: "none" })
77
+ * // → { collection: "GALA", category: "Unit", type: "none", additionalKey: "none" }
78
+ *
79
+ * // Plain string - PERMANENTLY REJECTED
80
+ * parseToken("GALA") // Throws ValidationError
81
+ * ```
82
+ *
83
+ * @since 3.32.0
84
+ * @updated 3.33.0 - Removed allowPlainStrings parameter, enforce strict delimiter-only parsing
85
+ */
86
+ export declare function parseToken(token: string | TokenClassKey | undefined | null): TokenClassKey;
87
+ /**
88
+ * Parse pipe-delimited token: "GALA|Unit|none|none"
89
+ *
90
+ * @internal Used by parseToken()
91
+ * @throws ValidationError if format is invalid
92
+ */
93
+ export declare function parsePipeDelimitedToken(token: string): TokenClassKey;
94
+ /**
95
+ * REVERSE-PARSING ALGORITHM FOR DOLLAR-DELIMITED TOKENS
96
+ *
97
+ * Problem: Tokens like "$MUSIC$Unit$none$none" contain $ in the collection name
98
+ * Standard left-to-right parsing fails because it can't distinguish where collection ends
99
+ *
100
+ * Solution: Parse from RIGHT-TO-LEFT
101
+ *
102
+ * ```
103
+ * Input token: "$MUSIC$Unit$none$none"
104
+ * [ 1 ][2 ][3 ][4 ] ← parts array (5 elements)
105
+ *
106
+ * Step 1: Split by '$'
107
+ * parts = ['', 'MUSIC', 'Unit', 'none', 'none']
108
+ *
109
+ * Step 2: Take last 3 parts (from right)
110
+ * category = parts[2] = 'Unit'
111
+ * type = parts[3] = 'none'
112
+ * additionalKey = parts[4] = 'none'
113
+ *
114
+ * Step 3: Everything BEFORE those 3 parts = collection (rejoin with '$')
115
+ * collectionParts = parts[0:2] = ['', 'MUSIC']
116
+ * collection = '$MUSIC' (rejoin with '$')
117
+ *
118
+ * Result: { collection: "$MUSIC", category: "Unit", type: "none", additionalKey: "none" } ✓
119
+ * ```
120
+ *
121
+ * Why this works:
122
+ * - Handles ANY number of $ characters in collection
123
+ * - Guarantees exactly 4 components (collection, category, type, additionalKey)
124
+ * - Clear error messages when format is invalid
125
+ *
126
+ * Edge cases handled:
127
+ * - "$MUSIC$Unit$none$none" → collection: "$MUSIC" ✓
128
+ * - "COLLECTION$WITH$DOLLARS$Unit$symbol$additionalKey" → works ✓
129
+ * - "NotEnoughParts$Unit$none" → throws ValidationError ✓
130
+ *
131
+ * Performance: O(n) where n = token length (single split + slice + rejoin operations)
132
+ */
133
+ /**
134
+ * Parse dollar-delimited token: "GALA$Unit$none$none"
135
+ *
136
+ * ⚠️ CRITICAL: Handles edge case where $ is part of collection name
137
+ * Example: "$MUSIC$Unit$none$none" → { collection: "$MUSIC", ... }
138
+ *
139
+ * Solution: Parse from END backwards
140
+ * - Last 3 parts (from right): category, type, additionalKey
141
+ * - Everything else: collection
142
+ *
143
+ * @internal Used by parseToken()
144
+ * @throws ValidationError if format is invalid
145
+ */
146
+ export declare function parseDollarDelimitedTokenSafe(token: string): TokenClassKey;
147
+ /**
148
+ * Check if token string is in pipe-delimited format
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * isPipeDelimited("GALA|Unit|none|none") // → true
153
+ * isPipeDelimited("GALA") // → false
154
+ * ```
155
+ */
156
+ export declare function isPipeDelimited(token: string): boolean;
157
+ /**
158
+ * Check if token string is in dollar-delimited format
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * isDollarDelimited("GALA$Unit$none$none") // → true
163
+ * isDollarDelimited("$MUSIC$Unit$none$none") // → true
164
+ * isDollarDelimited("GALA") // → false
165
+ * ```
166
+ */
167
+ export declare function isDollarDelimited(token: string): boolean;
168
+ /**
169
+ * Check if token is in ANY valid delimited format (pipe or dollar)
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * isDelimited("GALA|Unit|none|none") // → true
174
+ * isDelimited("GALA$Unit$none$none") // → true
175
+ * isDelimited("GALA") // → false
176
+ * ```
177
+ */
178
+ export declare function isDelimited(token: string): boolean;
179
+ /**
180
+ * Check if a value is a valid token format (string OR TokenClassKey object)
181
+ *
182
+ * @param token Token to validate
183
+ * @returns true if token is valid format (pipe/dollar delimited OR TokenClassKey object)
184
+ *
185
+ * @example
186
+ * ```typescript
187
+ * isValidTokenFormat("GALA|Unit|none|none") // → true
188
+ * isValidTokenFormat("GALA$Unit$none$none") // → true
189
+ * isValidTokenFormat({ collection: "GALA", ... }) // → true
190
+ * isValidTokenFormat("GALA") // → false (plain string, not delimited)
191
+ * ```
192
+ */
193
+ export declare function isValidTokenFormat(token: unknown): boolean;
194
+ /**
195
+ * Check if token is a plain symbol string (NOT a delimited format)
196
+ *
197
+ * Plain token symbols are simple strings like "GALA", "USDC", etc.
198
+ * These are REJECTED by default by parseToken() for security reasons.
199
+ * Use parseToken(symbol, true) to parse plain symbols.
200
+ *
201
+ * @param token Token to check
202
+ * @returns true if token is plain symbol (no delimiters)
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * isPlainTokenSymbol("GALA") // → true
207
+ * isPlainTokenSymbol("GALA|Unit|none|none") // → false
208
+ * isPlainTokenSymbol("GALA$Unit$none$none") // → false
209
+ * ```
210
+ *
211
+ * @security WARNING: Plain tokens are inherently ambiguous!
212
+ * Always use delimited formats when possible.
213
+ */
214
+ export declare function isPlainTokenSymbol(token: unknown): boolean;
215
+ /**
216
+ * Type guard: Check if value is a TokenClassKey object
217
+ *
218
+ * @param token Value to check
219
+ * @returns true if token is a valid TokenClassKey object with all required properties
220
+ *
221
+ * @example
222
+ * ```typescript
223
+ * const value: string | TokenClassKey = getToken();
224
+ *
225
+ * if (isTokenClassKey(value)) {
226
+ * // TypeScript now knows value is TokenClassKey
227
+ * console.log(value.collection, value.category, value.type, value.additionalKey);
228
+ * } else {
229
+ * // value is string
230
+ * console.log(parseToken(value));
231
+ * }
232
+ * ```
233
+ */
234
+ export declare function isTokenClassKey(token: unknown): token is TokenClassKey;
235
+ //# sourceMappingURL=token-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-parser.d.ts","sourceRoot":"","sources":["../../src/utils/token-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGrD;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,GAAG,IAAI,GAC/C,aAAa,CAyCf;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CA6CpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CA8C1E;AA2DD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAe1D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE1D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAgBtE"}
@@ -108,4 +108,70 @@ export declare function tokenClassKeyToString(tokenClass: TokenClassKey): string
108
108
  * @throws ValidationError if validation fails
109
109
  */
110
110
  export declare function validateTokenId(tokenId: TokenId): void;
111
+ /**
112
+ * Parses a vault address into a TokenClassKey
113
+ *
114
+ * Vault address format: "service|Token$Unit$SYMBOL$additionalKey$launchpad"
115
+ * This consolidates 5+ identical vault address parsing patterns scattered across services.
116
+ *
117
+ * Handles additionalKey that may contain $ characters by excluding the 'launchpad' suffix
118
+ * and joining all remaining parts.
119
+ *
120
+ * @param vaultAddress Vault address string to parse
121
+ * @returns TokenClassKey object
122
+ * @throws ValidationError if the vault address format is invalid
123
+ *
124
+ * @example
125
+ * ```typescript
126
+ * const tokenClass = parseVaultAddressToTokenClassKey(
127
+ * "service|Token$Unit$DRAGNRKTI$eth:0x...$launchpad"
128
+ * );
129
+ * // → { collection: "Token", category: "Unit", type: "DRAGNRKTI", additionalKey: "eth:0x..." }
130
+ * ```
131
+ *
132
+ * @since 3.32.0
133
+ */
134
+ export declare function parseVaultAddressToTokenClassKey(vaultAddress: string): TokenClassKey;
135
+ /**
136
+ * Parses a vault address into a TokenInstanceKey
137
+ *
138
+ * Vault address format: "service|Token$Unit$SYMBOL$eth:address$launchpad"
139
+ * Instance is defaulted to "0" if not provided in the vault address.
140
+ *
141
+ * @param vaultAddress Vault address string to parse
142
+ * @returns TokenInstanceKey object with instance defaulted to "0"
143
+ * @throws ValidationError if the vault address format is invalid
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * const tokenInstance = parseVaultAddressToTokenInstance(
148
+ * "service|Token$Unit$DRAGNRKTI$eth:0x...$launchpad"
149
+ * );
150
+ * // → { collection: "Token", category: "Unit", type: "DRAGNRKTI", additionalKey: "eth:0x...", instance: "0" }
151
+ * ```
152
+ *
153
+ * @since 3.32.0
154
+ */
155
+ export declare function parseVaultAddressToTokenInstance(vaultAddress: string): TokenInstanceKey;
156
+ /**
157
+ * Extracts the token symbol/type from a vault address
158
+ *
159
+ * Vault address format: "service|Token$Unit$SYMBOL$eth:address$launchpad"
160
+ * The symbol is the 3rd component (index 2) after splitting the token part by $.
161
+ *
162
+ * @param vaultAddress Vault address string to parse
163
+ * @returns Token symbol/type (e.g., "DRAGNRKTI", "GALA", "GUSDC")
164
+ * @throws ValidationError if the vault address format is invalid
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * const symbol = extractTokenSymbolFromVault(
169
+ * "service|Token$Unit$DRAGNRKTI$eth:0x...$launchpad"
170
+ * );
171
+ * // → "DRAGNRKTI"
172
+ * ```
173
+ *
174
+ * @since 3.32.0
175
+ */
176
+ export declare function extractTokenSymbolFromVault(vaultAddress: string): string;
111
177
  //# sourceMappingURL=tokenNormalizer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokenNormalizer.d.ts","sourceRoot":"","sources":["../../src/utils/tokenNormalizer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAG3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CA2D9E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,gBAAgB,CAKhF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,aAAa,CAI1E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,MAAM,CAEnE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,gBAAgB,GAAG,MAAM,CAEhF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,aAAa,GAAG,MAAM,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CActD"}
1
+ {"version":3,"file":"tokenNormalizer.d.ts","sourceRoot":"","sources":["../../src/utils/tokenNormalizer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAG3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,CA2D9E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,gBAAgB,CAKhF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,aAAa,CAI1E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,MAAM,CAEnE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,gBAAgB,GAAG,MAAM,CAEhF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,aAAa,GAAG,MAAM,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CActD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gCAAgC,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,CAyCpF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gCAAgC,CAAC,YAAY,EAAE,MAAM,GAAG,gBAAgB,CAMvF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAGxE"}
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-validation.d.ts","sourceRoot":"","sources":["../../src/utils/transfer-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH;;;;;GAKG;AACH,qBAAa,wBAAwB;IACnC;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAc3C;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;CAqB9D"}
1
+ {"version":3,"file":"transfer-validation.d.ts","sourceRoot":"","sources":["../../src/utils/transfer-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH;;;;;GAKG;AACH,qBAAa,wBAAwB;IACnC;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAc3C;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;CAqB9D"}
@@ -366,4 +366,79 @@ export type TypeGuard<T> = (value: unknown) => value is T;
366
366
  * ```
367
367
  */
368
368
  export declare function createValidator<T>(typeGuard: TypeGuard<T>, dataTypeName: string, fieldName?: string, errorCode?: string): (value: unknown) => asserts value is T;
369
+ /**
370
+ * Result of mutual exclusivity validation
371
+ */
372
+ export interface MutualExclusivityResult {
373
+ /** Which field was provided (if valid) */
374
+ chosen: string;
375
+ /** Whether fieldA was provided */
376
+ hasA: boolean;
377
+ /** Whether fieldB was provided */
378
+ hasB: boolean;
379
+ }
380
+ /**
381
+ * Validates that exactly one of two parameters is provided (mutual exclusivity)
382
+ *
383
+ * Consolidates 12+ instances of identical validation logic found across services:
384
+ * - PriceHistoryService: tokenName XOR tokenId (lines 451-470)
385
+ * - DexService: Similar patterns with token identification
386
+ * - Other services: Scattered mutual exclusivity validation
387
+ *
388
+ * ## Use Cases
389
+ *
390
+ * ### Validate Token Identification (Highest Priority)
391
+ * ```typescript
392
+ * // In service methods receiving either tokenName or tokenId (but not both)
393
+ * const { chosen, hasA } = validateMutualExclusive(
394
+ * options,
395
+ * 'tokenName',
396
+ * 'tokenId',
397
+ * { description: 'token identifier' }
398
+ * );
399
+ *
400
+ * if (hasA) {
401
+ * // Use tokenName
402
+ * const resolved = await this.tokenResolver.resolve(options.tokenName!);
403
+ * } else {
404
+ * // Use tokenId
405
+ * const formatted = this.converter.toTokenClassKey(options.tokenId!);
406
+ * }
407
+ * ```
408
+ *
409
+ * ### Generic Parameter Validation
410
+ * ```typescript
411
+ * // Validate address or transaction ID (mutually exclusive)
412
+ * const { chosen } = validateMutualExclusive(
413
+ * params,
414
+ * 'walletAddress',
415
+ * 'transactionId',
416
+ * { description: 'transaction reference' }
417
+ * );
418
+ * ```
419
+ *
420
+ * @param obj The object containing the fields to validate
421
+ * @param fieldA First field name (mutual exclusive with fieldB)
422
+ * @param fieldB Second field name (mutual exclusive with fieldA)
423
+ * @param options Validation options
424
+ * @returns Result object with chosen field and validation flags
425
+ *
426
+ * @throws {ConfigurationError} If neither field is provided or both are provided
427
+ *
428
+ * @example Token identifier validation
429
+ * ```typescript
430
+ * // PriceHistoryService.fetchAllPriceHistory() - replaces 20-line validation method
431
+ * const { hasA } = validateMutualExclusive(options, 'tokenName', 'tokenId', {
432
+ * description: 'token identifier'
433
+ * });
434
+ * ```
435
+ *
436
+ * @since 3.32.0
437
+ */
438
+ export declare function validateMutualExclusive(obj: Record<string, any>, fieldA: string, fieldB: string, options?: {
439
+ /** Human-readable description for error messages (e.g., "token identifier") */
440
+ description?: string;
441
+ /** Whether empty strings should count as "not provided" (default: true) */
442
+ treatEmptyAsNull?: boolean;
443
+ }): MutualExclusivityResult;
369
444
  //# sourceMappingURL=validation-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validation-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/validation-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0FG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,qBAAqB,GACjC,IAAI,CAoBN;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;IAC3B,wEAAwE;;IAExE,yEAAyE;;CAEjE,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEhE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAQvD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8FG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,YAAY,EAAE,MAAM,EACpB,SAAS,GAAE,MAAe,EAC1B,SAAS,GAAE,MAAuB,GACjC,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,KAAK,IAAI,CAAC,CAUxC"}
1
+ {"version":3,"file":"validation-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/validation-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0FG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,qBAAqB,GACjC,IAAI,CAoBN;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;IAC3B,wEAAwE;;IAExE,yEAAyE;;CAEjE,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEhE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAQvD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8FG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,YAAY,EAAE,MAAM,EACpB,SAAS,GAAE,MAAe,EAC1B,SAAS,GAAE,MAAuB,GACjC,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,KAAK,IAAI,CAAC,CAUxC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,kCAAkC;IAClC,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACxB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACvB,GACL,uBAAuB,CA8BzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gala-chain/launchpad-sdk",
3
- "version": "3.31.0",
3
+ "version": "4.0.0",
4
4
  "description": "TypeScript SDK for Gala Launchpad Backend API - 72 methods supporting optional wallet (read-only and full-access modes). Production-ready DeFi token launchpad integration with AgentConfig setup, GalaChain trading, GSwap DEX integration, price history, token creation, DEX pool discovery, WebSocket event watchers, and comprehensive user operations. Multi-format output (ESM, CJS, UMD).",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",
@@ -38,19 +38,39 @@
38
38
  "test:watch": "jest --watch",
39
39
  "test:coverage": "jest --coverage",
40
40
  "test:ci": "jest --coverage --ci --watchAll=false",
41
- "demo": "tsx examples/complete-sdk-demo.ts",
42
- "demo:read-only": "tsx examples/read-only-operations.ts",
43
- "demo:authenticated": "tsx examples/authenticated-operations.ts",
44
- "demo:privatekey-override": "tsx examples/privatekey-override-pattern.ts",
45
- "demo:trades": "tsx examples/demo-trades.ts",
46
- "demo:liquidity": "tsx examples/demo-liquidity-positions.ts",
47
- "demo:liquidity:detailed": "tsx examples/demo-liquidity-detailed.ts",
48
- "demo:cache": "tsx examples/demo-cache.ts",
49
- "demo:fetch-all-pools": "tsx examples/demo-fetch-all-pools.ts",
50
- "demo:dex-trades": "tsx examples/demo-dex-trades.ts",
51
- "demo:dex-pool-discovery": "tsx examples/demo-dex-pool-discovery.ts",
52
- "demo:watch-pools": "tsx examples/demo-watch-pools.ts",
53
- "demo:watch-tokens": "tsx examples/demo-watch-tokens.ts",
41
+ "test:integration": "jest --config jest.integration.config.js --forceExit",
42
+ "demo": "tsx examples/core/complete-sdk-demo.ts",
43
+ "demo:read-only": "tsx examples/core/read-only-operations.ts",
44
+ "demo:authenticated": "tsx examples/core/authenticated-operations.ts",
45
+ "demo:privatekey-override": "tsx examples/core/privatekey-override-pattern.ts",
46
+ "demo:trades": "tsx examples/bonding-curve/basic-trading.ts",
47
+ "demo:liquidity": "tsx examples/liquidity/positions-cli.ts",
48
+ "demo:liquidity:all": "tsx examples/liquidity/orchestrator.ts",
49
+ "demo:liquidity:detailed": "tsx examples/liquidity/detailed.ts",
50
+ "demo:liquidity:ticks": "tsx examples/liquidity/ticks.ts",
51
+ "demo:liquidity:portfolio": "tsx examples/liquidity/multi-position.ts",
52
+ "demo:liquidity:apr": "tsx examples/liquidity/apr-calculator.ts",
53
+ "demo:liquidity:errors": "tsx examples/liquidity/errors.ts",
54
+ "demo:liquidity:fetch-all": "tsx examples/liquidity/demo-fetch-all-positions.ts",
55
+ "demo:liquidity:positions-with-prices": "tsx examples/liquidity/demo-positions-with-chunked-pricing.ts",
56
+ "demo:cache": "tsx examples/utilities/demo-cache.ts",
57
+ "demo:dex": "tsx examples/dex/swap-workflow.ts",
58
+ "demo:dex:pools": "tsx examples/dex/pool-discovery.ts",
59
+ "demo:dex:pricing": "tsx examples/dex/pools-with-pricing.ts",
60
+ "demo:dex:quotes": "tsx examples/dex/quote-comparison.ts",
61
+ "demo:dex:roundtrip": "tsx examples/dex/demo-roundtrip-liquidity.ts",
62
+ "demo:watch": "tsx examples/monitoring/demo-watch-pools.ts",
63
+ "demo:watch:tokens": "tsx examples/monitoring/demo-watch-tokens.ts",
64
+ "demo:fees": "tsx examples/fees/demo-fee-generation-and-collection.ts",
65
+ "demo:fees:high-volume": "tsx examples/fees/demo-fees-high-volume.ts",
66
+ "demo:fees:test": "tsx examples/fees/complete-fee-test.ts",
67
+ "demo:fees:trade-collect": "tsx examples/fees/trade-and-collect-fees.ts",
68
+ "demo:liquidity:bundler-test": "tsx examples/liquidity/test-bundler-operations.ts",
69
+ "demo:liquidity:roundtrip-remove": "tsx examples/liquidity/demo-roundtrip-remove.ts",
70
+ "demo:liquidity:direct": "tsx examples/liquidity/demo-position-direct.ts",
71
+ "demo:token-supply": "tsx examples/utilities/demo-token-supply.ts",
72
+ "debug:websocket:stage": "ENVIRONMENT=stage tsx examples/debug/websocket-monitor.ts",
73
+ "debug:websocket:prod": "ENVIRONMENT=prod tsx examples/debug/websocket-monitor.ts",
54
74
  "lint": "eslint src tests scripts --ext .ts,.tsx --fix",
55
75
  "lint:check": "eslint src tests scripts --ext .ts,.tsx",
56
76
  "typecheck": "tsc --noEmit",
@@ -139,6 +159,7 @@
139
159
  "peerDependencies": {
140
160
  "@gala-chain/api": "^2.4.3",
141
161
  "@gala-chain/connect": "^2.4.3",
162
+ "@gala-chain/dex": "^1.0.26",
142
163
  "axios": "^1.12.2",
143
164
  "bignumber.js": "^9.1.2",
144
165
  "ethers": "^6.15.0",
@@ -154,7 +175,7 @@
154
175
  "dependencies": {
155
176
  "@gala-chain/api": "^2.4.3",
156
177
  "@gala-chain/connect": "^2.4.3",
157
- "@gala-chain/gswap-sdk": "^0.0.9",
178
+ "@gala-chain/dex": "^1.0.26",
158
179
  "@types/uuid": "^10.0.0",
159
180
  "axios": "^1.12.2",
160
181
  "bignumber.js": "^9.1.2",
@@ -1,53 +0,0 @@
1
- /**
2
- * Token Format Conversion Utilities
3
- *
4
- * Converts between pipe-delimited and dollar-delimited token ID formats.
5
- * Used for translating between SDK format (pipe) and DEX Backend API format (dollar).
6
- *
7
- * @internal
8
- */
9
- /**
10
- * Convert pipe-delimited token ID to dollar-delimited format for API
11
- *
12
- * @param pipeToken Pipe-delimited format: "Token|Unit|GUSDC|eth:0x..."
13
- * @returns Dollar-delimited format: "Token$Unit$GUSDC$eth:0x..."
14
- * @throws Error if token is null or empty
15
- *
16
- * @example
17
- * ```typescript
18
- * pipeFormatToDollarFormat("Token|Unit|GUSDC|eth:0x123")
19
- * // Returns: "Token$Unit$GUSDC$eth:0x123"
20
- * ```
21
- */
22
- export declare function pipeFormatToDollarFormat(pipeToken: string): string;
23
- /**
24
- * Convert dollar-delimited API response to pipe-delimited format
25
- *
26
- * @param dollarToken Dollar-delimited format: "Token$Unit$GUSDC$eth:0x..."
27
- * @returns Pipe-delimited format: "Token|Unit|GUSDC|eth:0x..."
28
- * @throws Error if token is null or empty
29
- *
30
- * @example
31
- * ```typescript
32
- * dollarFormatToPipeFormat("Token$Unit$GUSDC$eth:0x123")
33
- * // Returns: "Token|Unit|GUSDC|eth:0x123"
34
- * ```
35
- */
36
- export declare function dollarFormatToPipeFormat(dollarToken: string): string;
37
- /**
38
- * Convert sort order from SDK format (uppercase) to API format (lowercase)
39
- *
40
- * @param sortOrder SDK sort order: 'ASC' | 'DESC'
41
- * @returns API sort order: 'asc' | 'desc' | undefined
42
- *
43
- * @example
44
- * ```typescript
45
- * convertSortOrderToApi('ASC')
46
- * // Returns: 'asc'
47
- *
48
- * convertSortOrderToApi(undefined)
49
- * // Returns: undefined
50
- * ```
51
- */
52
- export declare function convertSortOrderToApi(sortOrder?: 'ASC' | 'DESC'): 'asc' | 'desc' | undefined;
53
- //# sourceMappingURL=tokenFormatConverter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tokenFormatConverter.d.ts","sourceRoot":"","sources":["../../src/utils/tokenFormatConverter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMlE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAMpE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAM5F"}