@l.x/gating 1.0.3 → 1.0.4

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.
package/.depcheckrc ADDED
@@ -0,0 +1,13 @@
1
+ ignores: [
2
+ # Standard ignores
3
+ "typescript",
4
+ "@typescript/native-preview",
5
+ "depcheck",
6
+
7
+ # Internal packages / workspaces
8
+ "@universe/gating",
9
+ "@universe/config",
10
+
11
+ # Peer dependencies
12
+ "react",
13
+ ]
package/.eslintrc.js ADDED
@@ -0,0 +1,21 @@
1
+ module.exports = {
2
+ extends: ['@luxamm/eslint-config/lib'],
3
+ parserOptions: {
4
+ tsconfigRootDir: __dirname,
5
+ },
6
+ overrides: [
7
+ {
8
+ files: ['*.ts', '*.tsx'],
9
+ rules: {
10
+ 'no-relative-import-paths/no-relative-import-paths': [
11
+ 'error',
12
+ {
13
+ allowSameFolder: false,
14
+ prefix: '@luxexchange/gating',
15
+ },
16
+ ],
17
+ '@typescript-eslint/prefer-enum-initializers': 'off',
18
+ },
19
+ },
20
+ ],
21
+ }
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @universe/gating
2
+
3
+ // TODO
package/package.json CHANGED
@@ -1 +1,39 @@
1
- {"name":"@l.x/gating","version":"1.0.3","description":"LX Exchange - gating","main":"index.js","dependencies":{"@luxexchange/gating":"1.0.3"}}
1
+ {
2
+ "name": "@l.x/gating",
3
+ "version": "1.0.4",
4
+ "dependencies": {
5
+ "@statsig/client-core": "3.12.2",
6
+ "@statsig/js-client": "3.12.2",
7
+ "@statsig/js-local-overrides": "3.12.2",
8
+ "@statsig/react-bindings": "3.12.2",
9
+ "@statsig/react-native-bindings": "3.12.2",
10
+ "@l.x/api": "workspace:*",
11
+ "@l.x/config": "workspace:*",
12
+ "@luxfi/utilities": "workspace:*"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "22.13.1",
16
+ "@typescript/native-preview": "7.0.0-dev.20260311.1",
17
+ "@luxfi/eslint-config": "workspace:^",
18
+ "depcheck": "1.4.7",
19
+ "eslint": "8.57.1",
20
+ "typescript": "5.8.3"
21
+ },
22
+ "scripts": {
23
+ "typecheck": "nx typecheck gating",
24
+ "typecheck:tsgo": "nx typecheck:tsgo gating",
25
+ "lint": "nx lint gating",
26
+ "lint:fix": "nx lint:fix gating",
27
+ "lint:biome": "nx lint:biome gating",
28
+ "lint:biome:fix": "nx lint:biome:fix gating",
29
+ "lint:eslint": "nx lint:eslint gating",
30
+ "lint:eslint:fix": "nx lint:eslint:fix gating",
31
+ "check:deps:usage": "nx check:deps:usage gating"
32
+ },
33
+ "nx": {
34
+ "includedScripts": []
35
+ },
36
+ "main": "src/index.ts",
37
+ "private": false,
38
+ "sideEffects": false
39
+ }
package/project.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@l.x/gating",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "pkgs/gating/src",
5
+ "projectType": "library",
6
+ "tags": ["scope:gating", "type:lib"],
7
+ "targets": {
8
+ "typecheck": {},
9
+ "typecheck:tsgo": {},
10
+ "lint:biome": {},
11
+ "lint:biome:fix": {},
12
+ "lint:eslint": {},
13
+ "lint:eslint:fix": {},
14
+ "lint": {},
15
+ "lint:fix": {},
16
+ "check:deps:usage": {}
17
+ }
18
+ }
@@ -0,0 +1,63 @@
1
+ import { LocalOverrideAdapter } from '@statsig/js-local-overrides'
2
+ import { getStatsigClient } from '@l.x/gating/src/sdk/statsig'
3
+
4
+ // Workaround for @statsig 3.x.x refreshing client after applying overrides to get the result without reloading
5
+ // Should be removed after statsig add real time override apply functionality
6
+ // Adds refresh only to used LocalOverrideAdapter methods. Other methods need to be added if refresh is required.
7
+ export class LocalOverrideAdapterWrapper extends LocalOverrideAdapter {
8
+ constructor(sdkKey: string) {
9
+ super(sdkKey)
10
+ }
11
+
12
+ refreshStatsig(): void {
13
+ const statsigClient = getStatsigClient()
14
+ const statsigUser = statsigClient.getContext().user
15
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
16
+ statsigClient.updateUserAsync(statsigUser)
17
+ }
18
+
19
+ overrideGate(name: string, value: boolean): void {
20
+ super.overrideGate(name, value)
21
+ this.refreshStatsig()
22
+ }
23
+
24
+ removeGateOverride(name: string): void {
25
+ super.removeGateOverride(name)
26
+ this.refreshStatsig()
27
+ }
28
+
29
+ overrideDynamicConfig(name: string, value: Record<string, unknown>): void {
30
+ super.overrideDynamicConfig(name, value)
31
+ this.refreshStatsig()
32
+ }
33
+
34
+ removeDynamicConfigOverride(name: string): void {
35
+ super.removeDynamicConfigOverride(name)
36
+ this.refreshStatsig()
37
+ }
38
+
39
+ removeAllOverrides(): void {
40
+ super.removeAllOverrides()
41
+ this.refreshStatsig()
42
+ }
43
+
44
+ removeExperimentOverride(name: string): void {
45
+ super.removeExperimentOverride(name)
46
+ this.refreshStatsig()
47
+ }
48
+
49
+ overrideExperiment(name: string, value: Record<string, unknown>): void {
50
+ super.overrideExperiment(name, value)
51
+ this.refreshStatsig()
52
+ }
53
+
54
+ overrideLayer(name: string, value: Record<string, unknown>): void {
55
+ super.overrideLayer(name, value)
56
+ this.refreshStatsig()
57
+ }
58
+
59
+ removeLayerOverride(name: string): void {
60
+ super.removeLayerOverride(name)
61
+ this.refreshStatsig()
62
+ }
63
+ }
package/src/configs.ts ADDED
@@ -0,0 +1,296 @@
1
+ import { GasStrategy } from '@luxfi/api'
2
+
3
+ // TODO: move to own package
4
+ export enum Locale {
5
+ Afrikaans = 'af-ZA',
6
+ ArabicSaudi = 'ar-SA',
7
+ Catalan = 'ca-ES',
8
+ ChineseSimplified = 'zh-Hans',
9
+ ChineseTraditional = 'zh-Hant',
10
+ CzechCzechia = 'cs-CZ',
11
+ DanishDenmark = 'da-DK',
12
+ DutchNetherlands = 'nl-NL',
13
+ EnglishUnitedStates = 'en-US',
14
+ FinnishFinland = 'fi-FI',
15
+ FrenchFrance = 'fr-FR',
16
+ GreekGreece = 'el-GR',
17
+ HebrewIsrael = 'he-IL',
18
+ HindiIndia = 'hi-IN',
19
+ HungarianHungarian = 'hu-HU',
20
+ IndonesianIndonesia = 'id-ID',
21
+ ItalianItaly = 'it-IT',
22
+ JapaneseJapan = 'ja-JP',
23
+ KoreanKorea = 'ko-KR',
24
+ MalayMalaysia = 'ms-MY',
25
+ NorwegianNorway = 'no-NO',
26
+ PolishPoland = 'pl-PL',
27
+ PortugueseBrazil = 'pt-BR',
28
+ PortuguesePortugal = 'pt-PT',
29
+ RomanianRomania = 'ro-RO',
30
+ RussianRussia = 'ru-RU',
31
+ Serbian = 'sr-SP',
32
+ SpanishLatam = 'es-419',
33
+ SpanishBelize = 'es-BZ',
34
+ SpanishCuba = 'es-CU',
35
+ SpanishDominicanRepublic = 'es-DO',
36
+ SpanishGuatemala = 'es-GT',
37
+ SpanishHonduras = 'es-HN',
38
+ SpanishMexico = 'es-MX',
39
+ SpanishNicaragua = 'es-NI',
40
+ SpanishPanama = 'es-PA',
41
+ SpanishPeru = 'es-PE',
42
+ SpanishPuertoRico = 'es-PR',
43
+ SpanishElSalvador = 'es-SV',
44
+ SpanishUnitedStates = 'es-US',
45
+ SpanishArgentina = 'es-AR',
46
+ SpanishBolivia = 'es-BO',
47
+ SpanishChile = 'es-CL',
48
+ SpanishColombia = 'es-CO',
49
+ SpanishCostaRica = 'es-CR',
50
+ SpanishEcuador = 'es-EC',
51
+ SpanishSpain = 'es-ES',
52
+ SpanishParaguay = 'es-PY',
53
+ SpanishUruguay = 'es-UY',
54
+ SpanishVenezuela = 'es-VE',
55
+ SwahiliTanzania = 'sw-TZ',
56
+ SwedishSweden = 'sv-SE',
57
+ TurkishTurkey = 'tr-TR',
58
+ UkrainianUkraine = 'uk-UA',
59
+ UrduPakistan = 'ur-PK',
60
+ VietnameseVietnam = 'vi-VN',
61
+ }
62
+
63
+ /**
64
+ * Dynamic Configs
65
+ * These should match the dynamic config's `Config Name` on Statsig
66
+ */
67
+ export enum DynamicConfigs {
68
+ // Shared
69
+ Swap = 'swap_config',
70
+ NetworkRequests = 'network_requests',
71
+ Chains = 'chains',
72
+ SyncTransactionSubmissionChainIds = 'sync_transaction_submission_chain_ids',
73
+ BlockedAsyncSubmissionChainIds = 'blocked_async_submission_chain_ids',
74
+
75
+ // Wallet
76
+ HomeScreenExploreTokens = 'home_screen_explore_tokens',
77
+ ForceUpgrade = 'force_upgrade',
78
+ OnDeviceRecovery = 'on_device_recovery',
79
+ UwuLink = 'uwulink_config',
80
+ GasStrategies = 'gas_strategy',
81
+ DatadogSessionSampleRate = 'datadog_session_sample_rate',
82
+ DatadogIgnoredErrors = 'datadog_ignored_errors',
83
+ EmbeddedWalletConfig = 'embedded_wallet_config',
84
+ ExtensionBiometricUnlock = 'extension_biometric_unlock_config',
85
+
86
+ // Web
87
+ AstroChain = 'astro_chain',
88
+ EmbeddedWalletBetaPassphrases = 'embedded_wallet_beta_passphrases',
89
+ ExternallyConnectableExtension = 'externally_connectable_extension',
90
+ LPConfig = 'lp_config',
91
+ AllowedV4WethHookAddresses = 'allowed_v4_weth_hook_addresses',
92
+ OutageBannerChainId = 'outage_banner_chain_id',
93
+ VerifiedAuctions = 'verified_auctions',
94
+ CreateAuction = 'create_auction_config',
95
+ }
96
+
97
+ // Config values go here for easy access
98
+
99
+ // Shared
100
+ export enum SwapConfigKey {
101
+ AverageL1BlockTimeMs = 'averageL1BlockTimeMs',
102
+ AverageL2BlockTimeMs = 'averageL2BlockTimeMs',
103
+ TradingApiSwapRequestMs = 'tradingApiSwapRequestMs',
104
+
105
+ MinAutoSlippageToleranceL2 = 'minAutoSlippageToleranceL2',
106
+
107
+ EthSwapMinGasAmount = 'ethSwapMinGasAmount',
108
+ EthSendMinGasAmount = 'ethSendMinGasAmount',
109
+ PolygonSwapMinGasAmount = 'polygonSwapMinGasAmount',
110
+ PolygonSendMinGasAmount = 'polygonSendMinGasAmount',
111
+ AvalancheSwapMinGasAmount = 'avalancheSwapMinGasAmount',
112
+ AvalancheSendMinGasAmount = 'avalancheSendMinGasAmount',
113
+ CeloSwapMinGasAmount = 'celoSwapMinGasAmount',
114
+ CeloSendMinGasAmount = 'celoSendMinGasAmount',
115
+ MonSwapMinGasAmount = 'monSwapMinGasAmount',
116
+ MonSendMinGasAmount = 'monSendMinGasAmount',
117
+ SolanaSwapMinGasAmount = 'solanaSwapMinGasAmount',
118
+ SolanaSendMinGasAmount = 'solanaSendMinGasAmount',
119
+ GenericL2SwapMinGasAmount = 'genericL2SwapMinGasAmount',
120
+ GenericL2SendMinGasAmount = 'genericL2SendMinGasAmount',
121
+
122
+ LowBalanceWarningGasPercentage = 'lowBalanceWarningGasPercentage',
123
+ }
124
+
125
+ export enum NetworkRequestsConfigKey {
126
+ BalanceMaxRefetchAttempts = 'balanceMaxRefetchAttempts',
127
+ }
128
+
129
+ export enum ChainsConfigKey {
130
+ OrderedChainIds = 'orderedChainIds',
131
+ NewChainIds = 'newChainIds',
132
+ }
133
+
134
+ // Wallet
135
+ export enum ForceUpgradeConfigKey {
136
+ Status = 'status',
137
+ Translations = 'translations',
138
+ }
139
+
140
+ export type ForceUpgradeStatus = 'recommended' | 'required' | 'not-required'
141
+
142
+ type SupportedLocale = `${Extract<Locale[keyof Locale], string>}`
143
+
144
+ type ContentMessage = {
145
+ title: string
146
+ description: string
147
+ }
148
+
149
+ export type ForceUpgradeTranslations = Record<SupportedLocale, ContentMessage>
150
+
151
+ export enum EmbeddedWalletConfigKey {
152
+ BaseUrl = 'baseUrl',
153
+ }
154
+
155
+ export enum ExtensionBiometricUnlockConfigKey {
156
+ EnableOnboardingEnrollment = 'enableOnboardingEnrollment',
157
+ EnableSettingsEnrollment = 'enableSettingsEnrollment',
158
+ EnableUnlocking = 'enableUnlocking',
159
+ }
160
+
161
+ export enum SyncTransactionSubmissionChainIdsConfigKey {
162
+ ChainIds = 'chainIds',
163
+ }
164
+
165
+ export enum BlockedAsyncSubmissionChainIdsConfigKey {
166
+ ChainIds = 'chainIds',
167
+ }
168
+
169
+ export enum HomeScreenExploreTokensConfigKey {
170
+ EthChainId = 'ethChainId',
171
+ Tokens = 'tokens',
172
+ }
173
+
174
+ export enum OnDeviceRecoveryConfigKey {
175
+ AppLoadingTimeoutMs = 'appLoadingTimeoutMs',
176
+ MaxMnemonicsToLoad = 'maxMnemonicsToLoad',
177
+ }
178
+
179
+ export enum UwuLinkConfigKey {
180
+ Allowlist = 'allowlist',
181
+ }
182
+
183
+ export enum DatadogIgnoredErrorsConfigKey {
184
+ Errors = 'errors',
185
+ }
186
+
187
+ export enum DatadogSessionSampleRateKey {
188
+ Rate = 'rate',
189
+ }
190
+
191
+ export enum ExternallyConnectableExtensionConfigKey {
192
+ ExtensionId = 'extensionId',
193
+ }
194
+
195
+ export type DatadogIgnoredErrorsValType = Array<{ messageContains: string; sampleRate: number }>
196
+
197
+ export type DatadogSessionSampleRateValType = number
198
+
199
+ export type GasStrategyType = 'general' | 'swap'
200
+
201
+ export type GasStrategyConditions = {
202
+ name: string
203
+ chainId: number
204
+ types: GasStrategyType
205
+ isActive: boolean
206
+ }
207
+
208
+ export type GasStrategyWithConditions = {
209
+ strategy: GasStrategy
210
+ conditions: GasStrategyConditions
211
+ }
212
+
213
+ export type GasStrategies = {
214
+ strategies: GasStrategyWithConditions[]
215
+ }
216
+
217
+ // Web
218
+ export enum QuickRouteChainsConfigKey {
219
+ Chains = 'quick_route_chains',
220
+ }
221
+
222
+ export enum AstroChainConfigKey {
223
+ Url = 'url',
224
+ }
225
+
226
+ export enum LPConfigKey {
227
+ DefaultSlippage = 'defaultSlippage',
228
+ V4SlippageOverride = 'v4SlippageOverride',
229
+ }
230
+
231
+ export enum AllowedV4WethHookAddressesConfigKey {
232
+ HookAddresses = 'hookAddresses',
233
+ }
234
+
235
+ export enum VerifiedAuctionsConfigKey {
236
+ VerifiedAuctionIds = 'verifiedAuctionIds',
237
+ }
238
+
239
+ export enum OutageBannerChainIdConfigKey {
240
+ ChainId = 'chainId',
241
+ }
242
+
243
+ export enum CreateAuctionConfigKey {
244
+ AllowedNetworks = 'allowedNetworks',
245
+ AllowedTokenCreationNetworks = 'allowedTokenCreationNetworks',
246
+ }
247
+
248
+ export enum EmbeddedWalletBetaPassphrasesKey {
249
+ Passphrases = 'passphrases',
250
+ }
251
+
252
+ export type DynamicConfigKeys = {
253
+ // Shared
254
+ [DynamicConfigs.Swap]: SwapConfigKey
255
+ [DynamicConfigs.NetworkRequests]: NetworkRequestsConfigKey
256
+ [DynamicConfigs.Chains]: ChainsConfigKey
257
+
258
+ // Wallet
259
+ [DynamicConfigs.HomeScreenExploreTokens]: HomeScreenExploreTokensConfigKey
260
+ [DynamicConfigs.ForceUpgrade]: ForceUpgradeConfigKey
261
+ [DynamicConfigs.OnDeviceRecovery]: OnDeviceRecoveryConfigKey
262
+ [DynamicConfigs.UwuLink]: UwuLinkConfigKey
263
+ [DynamicConfigs.DatadogIgnoredErrors]: DatadogIgnoredErrorsConfigKey
264
+ [DynamicConfigs.DatadogSessionSampleRate]: DatadogSessionSampleRateKey
265
+ [DynamicConfigs.EmbeddedWalletConfig]: EmbeddedWalletConfigKey
266
+ [DynamicConfigs.ExtensionBiometricUnlock]: ExtensionBiometricUnlockConfigKey
267
+ [DynamicConfigs.SyncTransactionSubmissionChainIds]: SyncTransactionSubmissionChainIdsConfigKey
268
+
269
+ // Web
270
+ [DynamicConfigs.AstroChain]: AstroChainConfigKey
271
+ [DynamicConfigs.ExternallyConnectableExtension]: ExternallyConnectableExtensionConfigKey
272
+ [DynamicConfigs.LPConfig]: LPConfigKey
273
+ [DynamicConfigs.AllowedV4WethHookAddresses]: AllowedV4WethHookAddressesConfigKey
274
+ [DynamicConfigs.VerifiedAuctions]: VerifiedAuctionsConfigKey
275
+ [DynamicConfigs.BlockedAsyncSubmissionChainIds]: BlockedAsyncSubmissionChainIdsConfigKey
276
+ [DynamicConfigs.OutageBannerChainId]: OutageBannerChainIdConfigKey
277
+ [DynamicConfigs.CreateAuction]: CreateAuctionConfigKey
278
+ [DynamicConfigs.EmbeddedWalletBetaPassphrases]: EmbeddedWalletBetaPassphrasesKey
279
+ }
280
+
281
+ // This type must match the format in statsig dynamic config for uwulink
282
+ // https://console.statsig.com/5HjUux4OvSGzgqWIfKFt8i/dynamic_configs/uwulink_config
283
+ export type UwULinkAllowlistItem = {
284
+ chainId: number
285
+ address: string
286
+ name: string
287
+ logo?: {
288
+ dark?: string
289
+ light?: string
290
+ }
291
+ }
292
+
293
+ export type UwULinkAllowlist = {
294
+ contracts: UwULinkAllowlistItem[]
295
+ tokenRecipients: UwULinkAllowlistItem[]
296
+ }
@@ -0,0 +1,4 @@
1
+ export enum StatsigCustomAppValue {
2
+ Mobile = 'mobile',
3
+ Extension = 'extension',
4
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Experiment parameter names. Ordered alphabetically.
3
+ *
4
+ * These must match parameter names on Statsig within an experiment
5
+ */
6
+ export enum Experiments {
7
+ EthAsErc20DEX = 'eth_as_erc20_luxx_experiment',
8
+ ExploreBackendSorting = 'explore_backend_sorting',
9
+ NativeTokenPercentageBuffer = 'lp_native_buffer',
10
+ PrivateRpc = 'private_rpc',
11
+ SwapConfirmation = 'swap-confirmation',
12
+ UnichainFlashblocksModal = 'unichain_flashblocks_modal',
13
+ }
14
+
15
+ export enum Layers {
16
+ ExplorePage = 'explore-page',
17
+ SwapPage = 'swap-page',
18
+ }
19
+
20
+ // experiment groups
21
+
22
+ export enum NativeTokenPercentageBufferExperimentGroup {
23
+ Control = 'Control',
24
+ Buffer1 = 'Buffer1',
25
+ }
26
+
27
+ // experiment properties
28
+
29
+ export enum ArbitrumXV2SamplingProperties {
30
+ RoutingType = 'routingType',
31
+ }
32
+
33
+ export enum PrivateRpcProperties {
34
+ FlashbotsEnabled = 'flashbots_enabled',
35
+ RefundPercent = 'refund_percent',
36
+ }
37
+
38
+ export enum NativeTokenPercentageBufferProperties {
39
+ BufferSize = 'bufferSize',
40
+ }
41
+
42
+ export enum SwapConfirmationProperties {
43
+ WaitTimes = 'wait_times',
44
+ }
45
+
46
+ export enum ExploreBackendSortingProperties {
47
+ BackendSortingEnabled = 'backendSortingEnabled',
48
+ }
49
+
50
+ // Swap Layer experiment properties
51
+
52
+ export enum SwapLayerProperties {
53
+ FlashblocksModalEnabled = 'flashblocksModalEnabled',
54
+ EthAsErc20DEXEnabled = 'ethAsErc20DEXEnabled',
55
+ MinEthErc20USDValueThresholdByChain = 'minEthErc20USDValueThresholdByChain',
56
+ }
57
+
58
+ export enum UnichainFlashblocksProperties {
59
+ FlashblocksModalEnabled = SwapLayerProperties.FlashblocksModalEnabled,
60
+ }
61
+
62
+ export enum EthAsErc20DEXProperties {
63
+ EthAsErc20DEXEnabled = SwapLayerProperties.EthAsErc20DEXEnabled,
64
+ MinEthErc20USDValueThresholdByChain = SwapLayerProperties.MinEthErc20USDValueThresholdByChain,
65
+ }
66
+
67
+ // Ordered alphabetically.
68
+ export type ExperimentProperties = {
69
+ [Experiments.EthAsErc20DEX]: EthAsErc20DEXProperties
70
+ [Experiments.ExploreBackendSorting]: ExploreBackendSortingProperties
71
+ [Experiments.NativeTokenPercentageBuffer]: NativeTokenPercentageBufferProperties
72
+ [Experiments.PrivateRpc]: PrivateRpcProperties
73
+ [Experiments.SwapConfirmation]: SwapConfirmationProperties
74
+ [Experiments.UnichainFlashblocksModal]: UnichainFlashblocksProperties
75
+ }
76
+
77
+ // will be a spread of all experiment properties in that layer
78
+ export const LayerProperties: Record<Layers, string[]> = {
79
+ [Layers.ExplorePage]: Object.values({
80
+ ...ExploreBackendSortingProperties,
81
+ }),
82
+ [Layers.SwapPage]: Object.values(SwapLayerProperties),
83
+ }