@steerprotocol/sdk 1.30.8-test-algebra-plugins.2 → 1.31.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 (54) hide show
  1. package/dist/cjs/base/PoolClient.js +137 -0
  2. package/dist/cjs/base/PoolClient.js.map +1 -1
  3. package/dist/cjs/base/VaultClient.js +111 -2
  4. package/dist/cjs/base/VaultClient.js.map +1 -1
  5. package/dist/cjs/const/feeManagerContracts.js +25 -0
  6. package/dist/cjs/const/feeManagerContracts.js.map +1 -0
  7. package/dist/cjs/const/network.js +7 -0
  8. package/dist/cjs/const/network.js.map +1 -1
  9. package/dist/cjs/const/protocol.js +68 -92
  10. package/dist/cjs/const/protocol.js.map +1 -1
  11. package/dist/cjs/scripts/processDeployments.js +1 -0
  12. package/dist/cjs/scripts/processDeployments.js.map +1 -1
  13. package/dist/esm/base/PoolClient.js +137 -0
  14. package/dist/esm/base/PoolClient.js.map +1 -1
  15. package/dist/esm/base/VaultClient.js +111 -2
  16. package/dist/esm/base/VaultClient.js.map +1 -1
  17. package/dist/esm/const/feeManagerContracts.js +25 -0
  18. package/dist/esm/const/feeManagerContracts.js.map +1 -0
  19. package/dist/esm/const/network.js +7 -0
  20. package/dist/esm/const/network.js.map +1 -1
  21. package/dist/esm/const/protocol.js +68 -92
  22. package/dist/esm/const/protocol.js.map +1 -1
  23. package/dist/esm/scripts/processDeployments.js +1 -0
  24. package/dist/esm/scripts/processDeployments.js.map +1 -1
  25. package/dist/types/base/PoolClient.d.ts +22 -0
  26. package/dist/types/base/PoolClient.d.ts.map +1 -1
  27. package/dist/types/base/VaultClient.d.ts +20 -0
  28. package/dist/types/base/VaultClient.d.ts.map +1 -1
  29. package/dist/types/const/feeManagerContracts.d.ts +6 -0
  30. package/dist/types/const/feeManagerContracts.d.ts.map +1 -0
  31. package/dist/types/const/network.d.ts +1 -0
  32. package/dist/types/const/network.d.ts.map +1 -1
  33. package/dist/types/const/protocol.d.ts +4 -19
  34. package/dist/types/const/protocol.d.ts.map +1 -1
  35. package/package.json +3 -2
  36. package/src/__tests__/base/PoolClient.test.ts +355 -104
  37. package/src/__tests__/base/StakingClient.test.ts +72 -72
  38. package/src/__tests__/base/VaultClient.protocol-filter.test.ts +64 -137
  39. package/src/__tests__/base/VaultClient.test.ts +460 -60
  40. package/src/__tests__/base/vault/single-asset/calculateLimitPrice.test.ts +32 -14
  41. package/src/__tests__/base/vault/single-asset/calculateSwapAmount.test.ts +7 -4
  42. package/src/__tests__/base/vault/single-asset/estimateLpTokens.test.ts +105 -570
  43. package/src/__tests__/base/vault/single-asset/simulateSwap.test.ts +45 -66
  44. package/src/__tests__/base/vault/single-asset/singleAssetDepositClient.test.ts +178 -381
  45. package/src/__tests__/const/network.feeManager.test.ts +47 -0
  46. package/src/__tests__/fixtures/live/single-asset.fixture.json +116 -0
  47. package/src/__tests__/fixtures/live/staking-pools.fixture.json +353 -0
  48. package/src/__tests__/fixtures/live/vaults.fixture.json +5392 -0
  49. package/src/base/PoolClient.ts +200 -1
  50. package/src/base/VaultClient.ts +169 -2
  51. package/src/const/feeManagerContracts.ts +28 -0
  52. package/src/const/network.ts +10 -1
  53. package/src/const/protocol.ts +18 -39
  54. package/src/scripts/processDeployments.ts +1 -0
@@ -67,10 +67,18 @@ export interface PoolFilter {
67
67
  chainId?: number;
68
68
  /** Protocol to filter pools by */
69
69
  protocol?: Protocol;
70
+ /** Exact pool address/id to look up */
71
+ poolAddress?: string;
70
72
  /** Minimum volume in USD to filter pools */
71
73
  minVolumeUSD?: number;
72
74
  /** Token address to find pools containing this token */
73
75
  tokenAddress?: string;
76
+ /** Multiple token addresses to find pools for */
77
+ tokenAddresses?: string[];
78
+ /** Token symbol to find pools containing this token */
79
+ tokenSymbol?: string;
80
+ /** Multiple token symbols to find pools for */
81
+ tokenSymbols?: string[];
74
82
  /** Maximum number of pools to return */
75
83
  limit?: number;
76
84
  }
@@ -207,6 +215,93 @@ export class PoolClient extends SubgraphClient {
207
215
  };
208
216
  }
209
217
 
218
+ private normalizeAddress(value?: string): string {
219
+ return value?.toLowerCase() || '';
220
+ }
221
+
222
+ private normalizeSymbol(value?: string): string {
223
+ return value?.trim().toLowerCase() || '';
224
+ }
225
+
226
+ private dedupePools(pools: GraphQLPoolData[]): GraphQLPoolData[] {
227
+ const seen = new Set<string>();
228
+ const deduped: GraphQLPoolData[] = [];
229
+
230
+ pools.forEach((pool) => {
231
+ const key = this.normalizeAddress(pool.id);
232
+ if (!key || seen.has(key)) {
233
+ return;
234
+ }
235
+
236
+ seen.add(key);
237
+ deduped.push(pool);
238
+ });
239
+
240
+ return deduped;
241
+ }
242
+
243
+ private filterPoolsBySymbols(
244
+ pools: GraphQLPoolData[],
245
+ symbols: string[],
246
+ ): GraphQLPoolData[] {
247
+ if (symbols.length === 0) {
248
+ return pools;
249
+ }
250
+
251
+ const normalizedSymbols = new Set(
252
+ symbols.map((symbol) => this.normalizeSymbol(symbol)).filter(Boolean),
253
+ );
254
+
255
+ return pools.filter((pool) => {
256
+ const token0Symbol = this.normalizeSymbol(pool.token0?.symbol);
257
+ const token1Symbol = this.normalizeSymbol(pool.token1?.symbol);
258
+
259
+ return normalizedSymbols.has(token0Symbol) || normalizedSymbols.has(token1Symbol);
260
+ });
261
+ }
262
+
263
+ private applyPoolSearchResultFilters(
264
+ pools: GraphQLPoolData[],
265
+ filter: PoolFilter,
266
+ ): GraphQLPoolData[] {
267
+ let filteredPools = this.dedupePools(pools);
268
+
269
+ if (typeof filter.minVolumeUSD === 'number') {
270
+ filteredPools = filteredPools.filter((pool) => {
271
+ const volumeUSD = parseFloat(pool.volumeUSD || pool.volumeUsd || '0');
272
+ return !Number.isNaN(volumeUSD) && volumeUSD >= filter.minVolumeUSD!;
273
+ });
274
+ }
275
+
276
+ if (typeof filter.limit === 'number' && filter.limit >= 0) {
277
+ filteredPools = filteredPools.slice(0, filter.limit);
278
+ }
279
+
280
+ return filteredPools;
281
+ }
282
+
283
+ private async searchPoolsBySymbols(
284
+ filter: Required<Pick<PoolFilter, 'chainId' | 'protocol'>> & PoolFilter,
285
+ symbols: string[],
286
+ ): Promise<SteerResponse<GraphQLPoolData[]>> {
287
+ // Symbol relation filtering is not portable across all supported AMM subgraphs.
288
+ // Use bounded top-pools fetch plus local symbol filtering as the baseline path.
289
+ const boundedLimit = Math.min(Math.max(filter.limit ?? 200, 1), 500);
290
+ const topPools = await this.getTopPools(boundedLimit, filter.protocol, filter.chainId);
291
+
292
+ if (!topPools.success || !topPools.data) {
293
+ return topPools;
294
+ }
295
+
296
+ const symbolMatches = this.filterPoolsBySymbols(topPools.data, symbols);
297
+
298
+ return {
299
+ data: this.applyPoolSearchResultFilters(symbolMatches, filter),
300
+ status: 200,
301
+ success: true,
302
+ };
303
+ }
304
+
210
305
  /**
211
306
  * Fetches data from GraphQL endpoint with retry logic for rate limits
212
307
  *
@@ -675,4 +770,108 @@ export class PoolClient extends SubgraphClient {
675
770
  return true;
676
771
  });
677
772
  }
678
- }
773
+
774
+ /**
775
+ * Searches pools using exact-address lookups where supported and local symbol
776
+ * filtering as a portable fallback.
777
+ *
778
+ * Symbol-based matching is best-effort because not every downstream AMM
779
+ * subgraph exposes portable nested token-symbol filters.
780
+ */
781
+ public async searchPools(
782
+ filter: PoolFilter,
783
+ ): Promise<SteerResponse<GraphQLPoolData[]>> {
784
+ const { chainId, protocol } = filter;
785
+
786
+ if (!chainId || !protocol) {
787
+ return {
788
+ data: null,
789
+ status: 400,
790
+ success: false,
791
+ error: 'searchPools requires both chainId and protocol',
792
+ };
793
+ }
794
+
795
+ const normalizedPoolAddress = this.normalizeAddress(filter.poolAddress);
796
+ const normalizedTokenAddress = this.normalizeAddress(filter.tokenAddress);
797
+ const normalizedTokenAddresses = (filter.tokenAddresses || [])
798
+ .map((address) => this.normalizeAddress(address))
799
+ .filter(Boolean);
800
+ const tokenSymbols = [
801
+ ...(filter.tokenSymbol ? [filter.tokenSymbol] : []),
802
+ ...(filter.tokenSymbols || []),
803
+ ].filter(Boolean);
804
+
805
+ if (
806
+ !normalizedPoolAddress &&
807
+ !normalizedTokenAddress &&
808
+ normalizedTokenAddresses.length === 0 &&
809
+ tokenSymbols.length === 0
810
+ ) {
811
+ return {
812
+ data: null,
813
+ status: 400,
814
+ success: false,
815
+ error: 'searchPools requires at least one of poolAddress, tokenAddress, tokenAddresses, tokenSymbol, or tokenSymbols',
816
+ };
817
+ }
818
+
819
+ const collectedPools: GraphQLPoolData[] = [];
820
+
821
+ if (normalizedPoolAddress) {
822
+ const exactPool = await this.getPoolById(normalizedPoolAddress, protocol, chainId);
823
+ if (!exactPool.success) {
824
+ return {
825
+ data: null,
826
+ status: exactPool.status,
827
+ success: false,
828
+ error: exactPool.error,
829
+ };
830
+ }
831
+
832
+ if (exactPool.data) {
833
+ collectedPools.push(exactPool.data);
834
+ }
835
+ }
836
+
837
+ if (normalizedTokenAddress) {
838
+ const tokenPools = await this.fetchPoolsForToken(normalizedTokenAddress, protocol, chainId);
839
+ if (!tokenPools.success) {
840
+ return tokenPools;
841
+ }
842
+
843
+ collectedPools.push(...(tokenPools.data || []));
844
+ }
845
+
846
+ if (normalizedTokenAddresses.length > 0) {
847
+ const batchPools = await this.fetchPoolsForTokensBatch(
848
+ normalizedTokenAddresses,
849
+ protocol,
850
+ chainId,
851
+ );
852
+ if (!batchPools.success) {
853
+ return batchPools;
854
+ }
855
+
856
+ collectedPools.push(...(batchPools.data || []));
857
+ }
858
+
859
+ if (tokenSymbols.length > 0) {
860
+ const symbolPools = await this.searchPoolsBySymbols(
861
+ { ...filter, chainId, protocol },
862
+ tokenSymbols,
863
+ );
864
+ if (!symbolPools.success) {
865
+ return symbolPools;
866
+ }
867
+
868
+ collectedPools.push(...(symbolPools.data || []));
869
+ }
870
+
871
+ return {
872
+ data: this.applyPoolSearchResultFilters(collectedPools, filter),
873
+ status: 200,
874
+ success: true,
875
+ };
876
+ }
877
+ }
@@ -218,6 +218,12 @@ export interface VaultFilter {
218
218
  protocol?: string;
219
219
  isActive?: boolean;
220
220
  beaconName?: string;
221
+ poolAddress?: string;
222
+ vaultAddress?: string;
223
+ tokenAddress?: string;
224
+ tokenAddresses?: string[];
225
+ tokenSymbol?: string;
226
+ tokenSymbols?: string[];
221
227
  }
222
228
 
223
229
  // API-specific filter that excludes protocol field
@@ -225,6 +231,7 @@ export interface ApiVaultFilter {
225
231
  chainId?: number;
226
232
  isActive?: boolean;
227
233
  beaconName?: string;
234
+ pool?: string;
228
235
  }
229
236
 
230
237
  export interface TokenFilter {
@@ -464,8 +471,16 @@ export class VaultClient extends SubgraphClient {
464
471
  return undefined;
465
472
  }
466
473
 
467
- const { protocol, ...rest } = filter;
468
- const apiFilter: ApiVaultFilter = { ...rest };
474
+ const { protocol, poolAddress, chainId, isActive, beaconName } = filter;
475
+ const apiFilter: ApiVaultFilter = {
476
+ chainId,
477
+ isActive,
478
+ beaconName,
479
+ };
480
+
481
+ if (poolAddress) {
482
+ apiFilter.pool = poolAddress;
483
+ }
469
484
 
470
485
  if (!apiFilter.beaconName && protocol) {
471
486
  const primaryBeaconName = this.getPrimaryProtocolBeaconName(protocol);
@@ -522,6 +537,88 @@ export class VaultClient extends SubgraphClient {
522
537
  };
523
538
  }
524
539
 
540
+ private normalizeAddress(value?: string): string {
541
+ return value?.toLowerCase() || '';
542
+ }
543
+
544
+ private normalizeSymbol(value?: string): string {
545
+ return value?.trim().toLowerCase() || '';
546
+ }
547
+
548
+ private matchesAnyAddress(candidates: Array<string | undefined>, filterValues: string[]): boolean {
549
+ if (filterValues.length === 0) {
550
+ return true;
551
+ }
552
+
553
+ const normalizedCandidates = new Set(
554
+ candidates.map((candidate) => this.normalizeAddress(candidate)).filter(Boolean),
555
+ );
556
+
557
+ return filterValues.some((value) => normalizedCandidates.has(value));
558
+ }
559
+
560
+ private matchesAnySymbol(candidates: Array<string | undefined>, filterValues: string[]): boolean {
561
+ if (filterValues.length === 0) {
562
+ return true;
563
+ }
564
+
565
+ const normalizedCandidates = new Set(
566
+ candidates.map((candidate) => this.normalizeSymbol(candidate)).filter(Boolean),
567
+ );
568
+
569
+ return filterValues.some((value) => normalizedCandidates.has(value));
570
+ }
571
+
572
+ private filterVaultNodes(vaults: VaultNode[], filter: VaultFilter): VaultNode[] {
573
+ const vaultAddress = this.normalizeAddress(filter.vaultAddress);
574
+ const poolAddress = this.normalizeAddress(filter.poolAddress);
575
+ const tokenAddressFilters = [
576
+ ...(filter.tokenAddress ? [filter.tokenAddress] : []),
577
+ ...(filter.tokenAddresses || []),
578
+ ]
579
+ .map((address) => this.normalizeAddress(address))
580
+ .filter(Boolean);
581
+ const tokenSymbolFilters = [
582
+ ...(filter.tokenSymbol ? [filter.tokenSymbol] : []),
583
+ ...(filter.tokenSymbols || []),
584
+ ]
585
+ .map((symbol) => this.normalizeSymbol(symbol))
586
+ .filter(Boolean);
587
+
588
+ return vaults.filter((vault) => {
589
+ if (vaultAddress && this.normalizeAddress(vault.vaultAddress) !== vaultAddress) {
590
+ return false;
591
+ }
592
+
593
+ if (
594
+ poolAddress &&
595
+ !this.matchesAnyAddress([vault.pool.poolAddress, vault.pool.id], [poolAddress])
596
+ ) {
597
+ return false;
598
+ }
599
+
600
+ if (
601
+ !this.matchesAnyAddress(
602
+ [vault.token0.address, vault.token0.id, vault.token1.address, vault.token1.id],
603
+ tokenAddressFilters,
604
+ )
605
+ ) {
606
+ return false;
607
+ }
608
+
609
+ if (
610
+ !this.matchesAnySymbol(
611
+ [vault.token0.symbol, vault.token1.symbol],
612
+ tokenSymbolFilters,
613
+ )
614
+ ) {
615
+ return false;
616
+ }
617
+
618
+ return true;
619
+ });
620
+ }
621
+
525
622
  /**
526
623
  * Gets vaults with pagination support
527
624
  * Fetches ALL data from both API (database) and subgraph in parallel, merges without duplicates, then paginates
@@ -1414,6 +1511,76 @@ export class VaultClient extends SubgraphClient {
1414
1511
  }
1415
1512
  }
1416
1513
 
1514
+ /**
1515
+ * Searches vaults by combining verified API-supported filters with local
1516
+ * filtering over the merged vault result set for unsupported server-side fields.
1517
+ */
1518
+ public async searchVaults(
1519
+ filter?: VaultFilter,
1520
+ ): Promise<SteerResponse<VaultNode[]>> {
1521
+ const response = await this.getAllVaults(filter);
1522
+
1523
+ if (!response.success || !response.data) {
1524
+ return response;
1525
+ }
1526
+
1527
+ return {
1528
+ data: this.filterVaultNodes(response.data, filter || {}),
1529
+ status: 200,
1530
+ success: true,
1531
+ };
1532
+ }
1533
+
1534
+ public async getVaultByAddress(
1535
+ vaultAddress: string,
1536
+ filter?: VaultFilter,
1537
+ ): Promise<SteerResponse<VaultNode | null>> {
1538
+ const response = await this.searchVaults({
1539
+ ...filter,
1540
+ vaultAddress,
1541
+ });
1542
+
1543
+ if (!response.success || !response.data) {
1544
+ return {
1545
+ data: null,
1546
+ status: response.status,
1547
+ success: response.success,
1548
+ error: response.error,
1549
+ };
1550
+ }
1551
+
1552
+ return {
1553
+ data: response.data[0] || null,
1554
+ status: 200,
1555
+ success: true,
1556
+ };
1557
+ }
1558
+
1559
+ public async getVaultsForPool(
1560
+ poolAddress: string,
1561
+ filter?: VaultFilter,
1562
+ ): Promise<SteerResponse<VaultNode[]>> {
1563
+ return this.searchVaults({
1564
+ ...filter,
1565
+ poolAddress,
1566
+ });
1567
+ }
1568
+
1569
+ public async getVaultsForToken(
1570
+ tokenAddressOrSymbol: string,
1571
+ filter?: VaultFilter,
1572
+ ): Promise<SteerResponse<VaultNode[]>> {
1573
+ const normalizedValue = tokenAddressOrSymbol.trim();
1574
+ const isAddress = /^0x[a-fA-F0-9]{40}$/.test(normalizedValue);
1575
+
1576
+ return this.searchVaults({
1577
+ ...filter,
1578
+ ...(isAddress
1579
+ ? { tokenAddress: normalizedValue }
1580
+ : { tokenSymbol: normalizedValue }),
1581
+ });
1582
+ }
1583
+
1417
1584
  /**
1418
1585
  * Gets APR data for vaults from the Steer Finance API
1419
1586
  * @param filter - Filter containing chainId and protocol
@@ -0,0 +1,28 @@
1
+ // This file is generated from @steerprotocol/contracts deployment JSON.
2
+ // It is intentionally scoped to FeeManager addresses only.
3
+ export interface FeeManagerDeployment {
4
+ address: string;
5
+ startBlock?: number;
6
+ }
7
+
8
+ export const feeManagerContractsByChainId: Record<number, FeeManagerDeployment> = {
9
+ 14: { address: '0xb944789b5C962f1096Ce8674456E68fb0F2e3BB7' },
10
+ 30: { address: '0xAa4448AeF5f5967693751BFB67197946BB6D1dC0' },
11
+ 40: { address: '0xE431A1dE6F37cD08AAA8821F83bD2157857E8172' },
12
+ 146: { address: '0x51aC65B177F084455750131A81706C32b466101D' },
13
+ 199: { address: '0xdca3251Ebe8f85458E8d95813bCb816460e4bef1' },
14
+ 314: { address: '0x0C5c5BEB833fD382b04e039f151942DC3D9A60ce' },
15
+ 1284: { address: '0xfF42cD42d8a5812CB38fb3C0720Dfc490912f48B' },
16
+ 1301: { address: '0xEd3420D9A8D42FAA8D054D284ed2bdd17a6Bca2b' },
17
+ 1329: { address: '0x9790aFEc5d23a840bC0597D9F54584057254d190' },
18
+ 8453: { address: '0xac4D51669B80D09d8Cc5EeFF50026c4d1D3290e6' },
19
+ 33139: { address: '0xd47CE509bE01e62cd4629E2f1eb22BA04e7dA192' },
20
+ 34443: { address: '0x7Daa68204232a78dBF1Dd853a4018330EE934A39' },
21
+ 43114: { address: '0x391cf3047db983caB8dD95B16c4e6C3918d72d23' },
22
+ 48900: { address: '0x0C5c5BEB833fD382b04e039f151942DC3D9A60ce' },
23
+ 59144: { address: '0xBcD427Ff26b70E73149858C4898DFa60107bedBe' },
24
+ 80084: { address: '0x0D3Ea88C8C3cb26EF21ab9E9ac6D178602Ef2779' },
25
+ 81457: { address: '0x7Daa68204232a78dBF1Dd853a4018330EE934A39' },
26
+ 167000: { address: '0x254d37F5eD7E96fc2d242CB06B17FAe1EE9E1ADA' },
27
+ 534352: { address: '0xa4a2f232C92f2DE7181E9fe4d46297FbBb4afaaA' },
28
+ };
@@ -11,6 +11,7 @@ import { peaqAddresses } from "./deployments/peaq.js";
11
11
  import { roninAddresses } from "./deployments/ronin.js";
12
12
  import { nibiruAddresses } from "./deployments/nibiru.js";
13
13
  import { hyperevmAddresses } from "./deployments/hyperevm.js";
14
+ import { feeManagerContractsByChainId } from './feeManagerContracts.js';
14
15
 
15
16
  /**
16
17
  * Interface representing a smart contract with its address and optional start block
@@ -56,6 +57,7 @@ export interface ContractAddresses {
56
57
  Helper?:Contract
57
58
 
58
59
  SingleAssetDeposit?:Contract
60
+ FeeManager?: Contract
59
61
  }
60
62
 
61
63
  /**
@@ -538,6 +540,13 @@ export const networks: Networks = {
538
540
  }
539
541
  };
540
542
 
543
+ for (const network of Object.values(networks) as NetworkConfig[]) {
544
+ const feeManagerDeployment = feeManagerContractsByChainId[network.chainId];
545
+ if (feeManagerDeployment) {
546
+ network.FeeManager = feeManagerDeployment;
547
+ }
548
+ }
549
+
541
550
 
542
551
  /**
543
552
  * Retrieves a contract address for a specific chain ID and contract name.
@@ -632,4 +641,4 @@ export function isSingleAssetDepositSupported(chainId: number) {
632
641
  const supportedChains = [ChainId.Polygon, ChainId.Hyperevm, ChainId.Peaq, ChainId.Arbitrum, ChainId.Katana, ChainId.Base, ChainId.Saga, ChainId.Mainnet, ChainId.Nibiru];
633
642
 
634
643
  return supportedChains.indexOf(chainId) > -1;
635
- }
644
+ }
@@ -1,6 +1,6 @@
1
- import { AMMType } from '../base/vault/single-asset/types';
2
- import { SupportedProtocol, ProtocolInfo } from '../types';
3
- import { Protocol, Chain } from './chain';
1
+ import { AMMType } from '../base/vault/single-asset/types.js';
2
+ import { SupportedProtocol } from '../types.js';
3
+ import { Protocol } from './chain.js';
4
4
 
5
5
  /**
6
6
  * Enum representing supported staking protocols
@@ -30,10 +30,15 @@ export enum StakingProtocol {
30
30
  * }
31
31
  * ```
32
32
  */
33
- export function isValidStakingProtocol(protocol: string): protocol is StakingProtocol {
34
- // Convert the input protocol to title case (first letter uppercase, rest lowercase)
35
- const normalizedProtocol = protocol.charAt(0).toUpperCase() + protocol.slice(1).toLowerCase();
36
- return Object.values(StakingProtocol).includes(normalizedProtocol as StakingProtocol);
33
+ export function isValidStakingProtocol(protocol: string | null | undefined): protocol is StakingProtocol {
34
+ if (!protocol || typeof protocol !== 'string') {
35
+ return false;
36
+ }
37
+
38
+ const normalizedProtocol = Object.values(StakingProtocol).find(
39
+ (value) => value.toLowerCase() === protocol.toLowerCase(),
40
+ );
41
+ return Boolean(normalizedProtocol);
37
42
  }
38
43
 
39
44
  /**
@@ -49,11 +54,13 @@ export function isValidStakingProtocol(protocol: string): protocol is StakingPro
49
54
  * ```
50
55
  */
51
56
  export function normalizeProtocol(protocol: string): StakingProtocol {
52
- const normalizedProtocol = protocol.charAt(0).toUpperCase() + protocol.slice(1).toLowerCase();
53
- if (!isValidStakingProtocol(normalizedProtocol)) {
57
+ const normalizedProtocol = Object.values(StakingProtocol).find(
58
+ (value) => value.toLowerCase() === protocol.toLowerCase(),
59
+ );
60
+ if (!normalizedProtocol || !isValidStakingProtocol(normalizedProtocol)) {
54
61
  throw new Error(`Invalid protocol: ${protocol}`);
55
62
  }
56
- return normalizedProtocol as StakingProtocol;
63
+ return normalizedProtocol;
57
64
  }
58
65
 
59
66
  /**
@@ -229,32 +236,4 @@ export const getProtcolTypeByAmmType = (ammType: AMMType): Protocol => {
229
236
  }
230
237
 
231
238
  throw Error('Protocol type not found')
232
- }
233
-
234
- /**
235
- * Checks if a protocol supports algebraHook for a given chain.
236
- *
237
- * @param protocolInfo - The protocol information object
238
- * @param chain - The chain to check for algebraHook support
239
- * @returns True if the protocol supports algebraHook on the given chain, false otherwise
240
- * @example
241
- * ```typescript
242
- * const protocolInfo = `getProtocolInfoBy`Name('QuickSwapIntegral', 'api-key');
243
- * if (isAlgebraHookSupported(protocolInfo, Chain.Base)) {
244
- * // Protocol supports algebraHook on Base chain
245
- * }
246
- * ```
247
- */
248
- export const isAlgebraHookSupported = (protocolInfo: ProtocolInfo | undefined, chain: Chain): boolean => {
249
- if (!protocolInfo) {
250
- return false;
251
- }
252
-
253
- // Check if the protocol has algebraHook supported chains defined
254
- if (protocolInfo.algebraHookSupportedChains && Array.isArray(protocolInfo.algebraHookSupportedChains)) {
255
- return protocolInfo.algebraHookSupportedChains.includes(chain);
256
- }
257
-
258
- // Fallback: if no specific chains are defined but beaconAlgebraHook exists, assume it's supported
259
- return !!protocolInfo.beaconAlgebraHook;
260
- }
239
+ }
@@ -47,6 +47,7 @@ const WHITELISTED_CONTRACTS = [
47
47
  'SteerPeriphery',
48
48
  'StrategyRegistry',
49
49
  'VaultRegistry',
50
+ 'FeeManager',
50
51
  "Orchestrator",
51
52
  "BundleRegistry",
52
53
  // 'Helper',