@paraswap/dex-lib 4.1.3 → 4.1.4-bal-v3-hooks.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 (56) hide show
  1. package/build/abi/balancer-v3/directionalFeeHook.json +684 -0
  2. package/build/abi/balancer-v3/stableSurgeHook.json +976 -0
  3. package/build/dex/balancer-v3/balancer-test-helpers.d.ts +5 -0
  4. package/build/dex/balancer-v3/balancer-test-helpers.js +122 -0
  5. package/build/dex/balancer-v3/balancer-test-helpers.js.map +1 -0
  6. package/build/dex/balancer-v3/balancer-v3-pool.d.ts +4 -1
  7. package/build/dex/balancer-v3/balancer-v3-pool.js +20 -13
  8. package/build/dex/balancer-v3/balancer-v3-pool.js.map +1 -1
  9. package/build/dex/balancer-v3/balancer-v3.d.ts +4 -0
  10. package/build/dex/balancer-v3/balancer-v3.js +29 -3
  11. package/build/dex/balancer-v3/balancer-v3.js.map +1 -1
  12. package/build/dex/balancer-v3/config.js +39 -0
  13. package/build/dex/balancer-v3/config.js.map +1 -1
  14. package/build/dex/balancer-v3/getOnChainState.d.ts +1 -2
  15. package/build/dex/balancer-v3/getOnChainState.js +0 -2
  16. package/build/dex/balancer-v3/getOnChainState.js.map +1 -1
  17. package/build/dex/balancer-v3/getPoolsApi.d.ts +2 -1
  18. package/build/dex/balancer-v3/getPoolsApi.js +17 -10
  19. package/build/dex/balancer-v3/getPoolsApi.js.map +1 -1
  20. package/build/dex/balancer-v3/getTopPoolsApi.d.ts +5 -1
  21. package/build/dex/balancer-v3/getTopPoolsApi.js +6 -3
  22. package/build/dex/balancer-v3/getTopPoolsApi.js.map +1 -1
  23. package/build/dex/balancer-v3/hooks/balancer-hook-event-subscriber.d.ts +54 -0
  24. package/build/dex/balancer-v3/hooks/balancer-hook-event-subscriber.js +153 -0
  25. package/build/dex/balancer-v3/hooks/balancer-hook-event-subscriber.js.map +1 -0
  26. package/build/dex/balancer-v3/hooks/directionalFeeHook.d.ts +26 -0
  27. package/build/dex/balancer-v3/hooks/directionalFeeHook.js +41 -0
  28. package/build/dex/balancer-v3/hooks/directionalFeeHook.js.map +1 -0
  29. package/build/dex/balancer-v3/hooks/loadHooksConfig.d.ts +2 -0
  30. package/build/dex/balancer-v3/hooks/loadHooksConfig.js +11 -0
  31. package/build/dex/balancer-v3/hooks/loadHooksConfig.js.map +1 -0
  32. package/build/dex/balancer-v3/hooks/stableSurgeHook.d.ts +39 -0
  33. package/build/dex/balancer-v3/hooks/stableSurgeHook.js +99 -0
  34. package/build/dex/balancer-v3/hooks/stableSurgeHook.js.map +1 -0
  35. package/build/dex/balancer-v3/types.d.ts +4 -1
  36. package/package.json +2 -2
  37. package/scripts/run-dex-integration-v3.ts +4 -4
  38. package/src/abi/balancer-v3/directionalFeeHook.json +684 -0
  39. package/src/abi/balancer-v3/stableSurgeHook.json +976 -0
  40. package/src/dex/balancer-v3/balancer-hooks-events.test.ts +99 -0
  41. package/src/dex/balancer-v3/balancer-stableSurge.test.ts +110 -0
  42. package/src/dex/balancer-v3/balancer-test-helpers.ts +199 -0
  43. package/src/dex/balancer-v3/balancer-v3-e2e.test.ts +20 -0
  44. package/src/dex/balancer-v3/balancer-v3-integration.test.ts +2 -197
  45. package/src/dex/balancer-v3/balancer-v3-pool.ts +37 -13
  46. package/src/dex/balancer-v3/balancer-v3.ts +42 -1
  47. package/src/dex/balancer-v3/config.ts +39 -0
  48. package/src/dex/balancer-v3/getOnChainState.ts +1 -4
  49. package/src/dex/balancer-v3/getPoolsApi.ts +42 -23
  50. package/src/dex/balancer-v3/getTopPoolsApi.ts +13 -2
  51. package/src/dex/balancer-v3/hooks/balancer-hook-event-subscriber.ts +226 -0
  52. package/src/dex/balancer-v3/hooks/directionalFeeHook.ts +51 -0
  53. package/src/dex/balancer-v3/hooks/loadHooksConfig.ts +12 -0
  54. package/src/dex/balancer-v3/hooks/stableSurgeHook.ts +163 -0
  55. package/src/dex/balancer-v3/types.ts +4 -2
  56. package/tests/constants-e2e.ts +6 -1
@@ -29,6 +29,11 @@ import {
29
29
  isStableMutableState,
30
30
  } from './stablePool';
31
31
  import { BI_POWS } from '../../bigint-constants';
32
+ import {
33
+ HookStateMap,
34
+ HooksConfigMap,
35
+ } from './hooks/balancer-hook-event-subscriber';
36
+ import { StableSurge, StableSurgeHookState } from './hooks/stableSurgeHook';
32
37
 
33
38
  export const WAD = BI_POWS[18];
34
39
 
@@ -48,8 +53,8 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
48
53
  interfaces: {
49
54
  [name: string]: Interface;
50
55
  };
51
-
52
56
  vault: Vault;
57
+ hooksConfigMap: HooksConfigMap = {};
53
58
 
54
59
  constructor(
55
60
  readonly parentName: string,
@@ -96,6 +101,10 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
96
101
  this.vault = new Vault();
97
102
  }
98
103
 
104
+ setHooksConfigMap(hooksConfigMap: HooksConfigMap) {
105
+ this.hooksConfigMap = hooksConfigMap;
106
+ }
107
+
99
108
  /**
100
109
  * The function is called every time any of the subscribed
101
110
  * addresses release log. The function accepts the current
@@ -134,7 +143,11 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
134
143
  blockNumber: number,
135
144
  ): Promise<DeepReadonly<PoolStateMap>> {
136
145
  const block = await this.dexHelper.provider.getBlock(blockNumber);
137
- const apiPoolStateMap = await getPoolsApi(this.network, block.timestamp);
146
+ const apiPoolStateMap = await getPoolsApi(
147
+ this.network,
148
+ this.hooksConfigMap,
149
+ block.timestamp,
150
+ );
138
151
  const allOnChainPools = await getOnChainState(
139
152
  this.network,
140
153
  apiPoolStateMap,
@@ -160,7 +173,10 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
160
173
  existingPoolState: DeepReadonly<PoolStateMap>,
161
174
  ): Promise<DeepReadonly<PoolStateMap> | null> {
162
175
  // Get all latest pools from API
163
- const apiPoolStateMap = await getPoolsApi(this.network);
176
+ const apiPoolStateMap = await getPoolsApi(
177
+ this.network,
178
+ this.hooksConfigMap,
179
+ );
164
180
 
165
181
  // Filter out pools that already exist in existing state
166
182
  const newApiPools = Object.entries(apiPoolStateMap).reduce(
@@ -186,19 +202,10 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
186
202
  this.interfaces,
187
203
  );
188
204
 
189
- // Filter out pools with hooks and paused pools from new state
190
- // TODO this won't be necessary once API has this filter option
191
- const filteredNewPools = Object.entries(newOnChainPools)
192
- .filter(([_, pool]) => !(pool.hasHook || pool.isPoolPaused))
193
- .reduce((acc, [address, pool]) => {
194
- acc[address] = pool;
195
- return acc;
196
- }, {} as PoolStateMap);
197
-
198
205
  // Merge existing pools with new pools
199
206
  return {
200
207
  ...existingPoolState,
201
- ...filteredNewPools,
208
+ ...newOnChainPools,
202
209
  };
203
210
  }
204
211
 
@@ -398,6 +405,7 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
398
405
  amountRaw: bigint,
399
406
  swapKind: SwapKind,
400
407
  timestamp: number,
408
+ hookStateMap: HookStateMap,
401
409
  ): bigint {
402
410
  if (amountRaw === 0n) return 0n;
403
411
 
@@ -411,6 +419,12 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
411
419
  let outputAmountRaw = 0n;
412
420
  for (const i of indices) {
413
421
  const step = steps[i];
422
+
423
+ // If the pool has a hook we fetch latest hook state for use in maths
424
+ let hookState = undefined;
425
+ if ('hookAddress' in step.poolState && step.poolState.hookAddress)
426
+ hookState = hookStateMap[step.poolState.hookAddress];
427
+
414
428
  // If its a Stable Pool with an updating Amp factor calculate current Amp value
415
429
  if (
416
430
  step.poolState.poolType === 'STABLE' &&
@@ -425,7 +439,16 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
425
439
  BigInt(timestamp),
426
440
  );
427
441
  }
442
+ // StableSurge hook uses Amp as part of maths
443
+ if (step.poolState.hookType === StableSurge.type && hookState)
444
+ hookState = {
445
+ ...(hookState as StableSurgeHookState)[
446
+ step.poolState.poolAddress.toLowerCase()
447
+ ],
448
+ amp: step.poolState.amp,
449
+ };
428
450
  }
451
+
429
452
  outputAmountRaw = this.vault.swap(
430
453
  {
431
454
  ...step.swapInput,
@@ -433,6 +456,7 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
433
456
  swapKind,
434
457
  },
435
458
  step.poolState,
459
+ hookState,
436
460
  );
437
461
  // Next step uses output from previous step as input
438
462
  amount = outputAmountRaw;
@@ -27,11 +27,13 @@ import balancerRouterAbi from '../../abi/balancer-v3/router.json';
27
27
  import balancerBatchRouterAbi from '../../abi/balancer-v3/batch-router.json';
28
28
  import { getGasCost } from './getGasCost';
29
29
  import { Block } from '@ethersproject/abstract-provider';
30
+ import { BalancerEventHook } from './hooks/balancer-hook-event-subscriber';
30
31
 
31
32
  const MAX_UINT256 =
32
33
  '115792089237316195423570985008687907853269984665640564039457584007913129639935';
33
34
  const POOL_UPDATE_TTL = 1 * 60; // 1min
34
35
  const RATE_UPDATE_TTL = 1 * 60; // 1min
36
+ const HOOK_UPDATE_TTL = 5 * 60; // 5min
35
37
 
36
38
  type DeepMutable<T> = {
37
39
  -readonly [P in keyof T]: T[P] extends object ? DeepMutable<T[P]> : T[P];
@@ -39,6 +41,7 @@ type DeepMutable<T> = {
39
41
 
40
42
  export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
41
43
  protected eventPools: BalancerV3EventPool;
44
+ protected eventHooks: BalancerEventHook;
42
45
 
43
46
  readonly hasConstantPriceLargeAmounts = false;
44
47
  // Vault can handle native
@@ -54,6 +57,7 @@ export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
54
57
  balancerBatchRouter: Interface;
55
58
  updateNewPoolsTimer?: NodeJS.Timeout;
56
59
  updateRatesTimer?: NodeJS.Timeout;
60
+ updateHooksTimer?: NodeJS.Timeout;
57
61
 
58
62
  latestBlock?: Block;
59
63
 
@@ -64,6 +68,12 @@ export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
64
68
  ) {
65
69
  super(dexHelper, dexKey);
66
70
  this.logger = dexHelper.getLogger(dexKey);
71
+ this.eventHooks = new BalancerEventHook(
72
+ dexKey,
73
+ network,
74
+ dexHelper,
75
+ this.logger,
76
+ );
67
77
  this.eventPools = new BalancerV3EventPool(
68
78
  dexKey,
69
79
  network,
@@ -79,6 +89,8 @@ export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
79
89
  // for pricing requests. It is optional for a DEX to
80
90
  // implement this function
81
91
  async initializePricing(blockNumber: number) {
92
+ await this.eventHooks.initialize(blockNumber);
93
+ this.eventPools.setHooksConfigMap(this.eventHooks.hooksConfigMap);
82
94
  await this.eventPools.initialize(blockNumber);
83
95
 
84
96
  // This will periodically query API and add any new pools to pool state
@@ -102,6 +114,17 @@ export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
102
114
  }
103
115
  }, RATE_UPDATE_TTL * 1000);
104
116
  }
117
+
118
+ // This will periodically update any hook state that can't be tracked by events
119
+ if (!this.updateHooksTimer) {
120
+ this.updateHooksTimer = setInterval(async () => {
121
+ try {
122
+ await this.updateHooksState();
123
+ } catch (e) {
124
+ this.logger.error(`${this.dexKey}: Failed to update hook state:`, e);
125
+ }
126
+ }, HOOK_UPDATE_TTL * 1000);
127
+ }
105
128
  }
106
129
 
107
130
  getAdapters(side: SwapSide): null {
@@ -261,6 +284,7 @@ export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
261
284
  unitAmount,
262
285
  swapKind,
263
286
  block.timestamp,
287
+ this.eventHooks.getState(blockNumber) || {},
264
288
  );
265
289
 
266
290
  const poolExchangePrice: PoolPrices<BalancerV3Data> = {
@@ -283,6 +307,7 @@ export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
283
307
  amounts[j],
284
308
  swapKind,
285
309
  block.timestamp,
310
+ this.eventHooks.getState(blockNumber) || {},
286
311
  );
287
312
  }
288
313
  }
@@ -559,6 +584,10 @@ export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
559
584
  await this.eventPools.updateStatePools();
560
585
  }
561
586
 
587
+ async updateHooksState(): Promise<void> {
588
+ await this.eventHooks.updateHookState();
589
+ }
590
+
562
591
  // Returns list of top pools based on liquidity. Max
563
592
  // limit number pools should be returned.
564
593
  async getTopPoolsForToken(
@@ -571,7 +600,12 @@ export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
571
600
  })
572
601
  .map(([address]) => address);
573
602
 
574
- const topPools = await getTopPoolsApi(this.network, poolsWithToken, count);
603
+ const topPools = await getTopPoolsApi(
604
+ this.network,
605
+ poolsWithToken,
606
+ count,
607
+ this.eventHooks.hooksConfigMap,
608
+ );
575
609
 
576
610
  return topPools.map(pool => {
577
611
  const tokens = pool.poolTokens
@@ -610,5 +644,12 @@ export class BalancerV3 extends SimpleExchange implements IDex<BalancerV3Data> {
610
644
  `${this.dexKey}: cleared updateRatesTimer before shutting down`,
611
645
  );
612
646
  }
647
+ if (this.updateHooksTimer) {
648
+ clearInterval(this.updateHooksTimer);
649
+ this.updateHooksTimer = undefined;
650
+ this.logger.info(
651
+ `${this.dexKey}: cleared updateHooksTimer before shutting down`,
652
+ );
653
+ }
613
654
  }
614
655
  }
@@ -25,30 +25,69 @@ export const BalancerV3Config: DexConfigMap<DexParams> = {
25
25
  apiNetworkName: 'SEPOLIA',
26
26
  balancerRouterAddress: '0x0BF61f706105EA44694f2e92986bD01C39930280',
27
27
  balancerBatchRouterAddress: '0xC85b652685567C1B074e8c0D4389f83a2E458b1C',
28
+ hooks: [
29
+ {
30
+ type: 'DirectionalFee',
31
+ address: '0xd68372e85d8a14afa5fdb3d506bf765939aaf382',
32
+ },
33
+ {
34
+ type: 'StableSurge',
35
+ factory: '0x9eB9867C1d4B6fd3a7D0dAd3101b5A153b1107Ec', // Pools with StableSurge hook will always be deployed from this factory
36
+ address: '0xc0cbcdd6b823a4f22aa6bbdde44c17e754266aef', // Address of the hook that will be used by pools
37
+ },
38
+ ],
28
39
  },
29
40
  [Network.GNOSIS]: {
30
41
  vaultAddress: '0xbA1333333333a1BA1108E8412f11850A5C319bA9',
31
42
  apiNetworkName: 'GNOSIS',
32
43
  balancerRouterAddress: '0x84813aA3e079A665C0B80F944427eE83cBA63617',
33
44
  balancerBatchRouterAddress: '0xe2fa4e1d17725e72dcdAfe943Ecf45dF4B9E285b',
45
+ hooks: [
46
+ {
47
+ type: 'StableSurge',
48
+ factory: '0x268E2EE1413D768b6e2dc3F5a4ddc9Ae03d9AF42', // Pools with StableSurge hook will always be deployed from this factory
49
+ address: '0xe4f1878eC9710846E2B529C1b5037F8bA94583b1', // Address of the hook that will be used by pools
50
+ },
51
+ ],
34
52
  },
35
53
  [Network.MAINNET]: {
36
54
  vaultAddress: '0xbA1333333333a1BA1108E8412f11850A5C319bA9',
37
55
  apiNetworkName: 'MAINNET',
38
56
  balancerRouterAddress: '0x5C6fb490BDFD3246EB0bB062c168DeCAF4bD9FDd',
39
57
  balancerBatchRouterAddress: '0x136f1EFcC3f8f88516B9E94110D56FDBfB1778d1',
58
+ hooks: [
59
+ {
60
+ type: 'StableSurge',
61
+ factory: '0xD53F5d8d926fb2a0f7Be614B16e649B8aC102D83', // Pools with StableSurge hook will always be deployed from this factory
62
+ address: '0xb18fA0cb5DE8cecB8899AAE6e38b1B7ed77885dA', // Address of the hook that will be used by pools
63
+ },
64
+ ],
40
65
  },
41
66
  [Network.ARBITRUM]: {
42
67
  vaultAddress: '0xbA1333333333a1BA1108E8412f11850A5C319bA9',
43
68
  apiNetworkName: 'ARBITRUM',
44
69
  balancerRouterAddress: '0x0f08eEf2C785AA5e7539684aF04755dEC1347b7c',
45
70
  balancerBatchRouterAddress: '0xaD89051bEd8d96f045E8912aE1672c6C0bF8a85E',
71
+ hooks: [
72
+ {
73
+ type: 'StableSurge',
74
+ factory: '0x86e67E115f96DF37239E0479441303De0de7bc2b', // Pools with StableSurge hook will always be deployed from this factory
75
+ address: '0x0Fa0f9990D7969a7aE6f9961d663E4A201Ed6417', // Address of the hook that will be used by pools
76
+ },
77
+ ],
46
78
  },
47
79
  [Network.BASE]: {
48
80
  vaultAddress: '0xbA1333333333a1BA1108E8412f11850A5C319bA9',
49
81
  apiNetworkName: 'BASE',
50
82
  balancerRouterAddress: '0x76578ecf9a141296Ec657847fb45B0585bCDa3a6',
51
83
  balancerBatchRouterAddress: '0x85a80afee867aDf27B50BdB7b76DA70f1E853062',
84
+ hooks: [
85
+ {
86
+ type: 'StableSurge',
87
+ factory: '0x4fb47126Fa83A8734991E41B942Ac29A3266C968', // Pools with StableSurge hook will always be deployed from this factory
88
+ address: '0xb2007B8B7E0260042517f635CFd8E6dD2Dd7f007', // Address of the hook that will be used by pools
89
+ },
90
+ ],
52
91
  },
53
92
  },
54
93
  };
@@ -10,7 +10,7 @@ import { Interface, Result } from '@ethersproject/abi';
10
10
  import { IDexHelper } from '../../dex-helper';
11
11
  import { WAD } from './balancer-v3-pool';
12
12
 
13
- interface callData {
13
+ export interface callData {
14
14
  target: string;
15
15
  callData: string;
16
16
  }
@@ -161,9 +161,6 @@ const poolOnChain: Record<
161
161
  (r: string) => BigInt(r),
162
162
  ),
163
163
  isPoolPaused: resultIsPoolPaused[0],
164
- hasHook:
165
- resultHooksConfig[0].hooksContract !==
166
- '0x0000000000000000000000000000000000000000',
167
164
  };
168
165
  },
169
166
  },
@@ -7,6 +7,7 @@ import {
7
7
  } from './config';
8
8
  import { CommonImmutablePoolState, ImmutablePoolStateMap } from './types';
9
9
  import { parseUnits } from 'ethers/lib/utils';
10
+ import { HooksConfigMap } from './hooks/balancer-hook-event-subscriber';
10
11
 
11
12
  interface PoolToken {
12
13
  address: string;
@@ -21,6 +22,9 @@ interface Pool {
21
22
  id: string;
22
23
  type: string;
23
24
  poolTokens: PoolToken[];
25
+ hook: {
26
+ address: string;
27
+ } | null;
24
28
  }
25
29
 
26
30
  interface QueryResponse {
@@ -44,7 +48,6 @@ function createQuery(
44
48
  const whereClause = {
45
49
  chainIn: networkString,
46
50
  protocolVersionIn: 3,
47
- hasHook: false,
48
51
  poolTypeIn: `[${poolTypesString}]`,
49
52
  ...(timestamp && { createTime: `{lt: ${timestamp}}` }),
50
53
  ...(disabledPoolIdsString && { idNotIn: `[${disabledPoolIdsString}]` }),
@@ -69,37 +72,53 @@ function createQuery(
69
72
  address
70
73
  }
71
74
  }
75
+ hook {
76
+ address
77
+ }
72
78
  }
73
79
  }
74
80
  `;
75
81
  }
76
82
 
77
- function toImmutablePoolStateMap(pools: Pool[]): ImmutablePoolStateMap {
78
- return pools.reduce((map, pool) => {
79
- const immutablePoolState: CommonImmutablePoolState = {
80
- poolAddress: pool.id,
81
- tokens: pool.poolTokens.map(t => t.address),
82
- tokensUnderlying: pool.poolTokens.map(t =>
83
- t.underlyingToken ? t.underlyingToken.address : null,
84
- ),
85
- weights: pool.poolTokens.map(t =>
86
- t.weight ? parseUnits(t.weight, 18).toBigInt() : 0n,
87
- ),
88
- poolType: pool.type,
89
- // TODO add scalingFactors once API provides them
90
- // scalingFactors: pool.poolTokens.map(t => parseUnits('1', 18).toBigInt()),
91
- // TODO Hook support will be added in future PR
92
- hookType: undefined,
93
- };
94
-
95
- map[pool.id] = immutablePoolState;
96
- return map;
97
- }, {} as ImmutablePoolStateMap);
83
+ function toImmutablePoolStateMap(
84
+ pools: Pool[],
85
+ hooksConfigMap: HooksConfigMap,
86
+ ): ImmutablePoolStateMap {
87
+ return (
88
+ pools
89
+ // First filter out pools with hooks that aren't in hooksMap
90
+ .filter(
91
+ pool =>
92
+ !pool.hook ||
93
+ (pool.hook && pool.hook.address.toLowerCase() in hooksConfigMap),
94
+ )
95
+ .reduce((map, pool) => {
96
+ const immutablePoolState: CommonImmutablePoolState = {
97
+ poolAddress: pool.id,
98
+ tokens: pool.poolTokens.map(t => t.address),
99
+ tokensUnderlying: pool.poolTokens.map(t =>
100
+ t.underlyingToken ? t.underlyingToken.address : null,
101
+ ),
102
+ weights: pool.poolTokens.map(t =>
103
+ t.weight ? parseUnits(t.weight, 18).toBigInt() : 0n,
104
+ ),
105
+ poolType: pool.type,
106
+ hookAddress: pool.hook ? pool.hook.address.toLowerCase() : undefined,
107
+ hookType: pool.hook
108
+ ? hooksConfigMap[pool.hook.address.toLowerCase()].type
109
+ : undefined,
110
+ supportsUnbalancedLiquidity: true,
111
+ };
112
+ map[pool.id] = immutablePoolState;
113
+ return map;
114
+ }, {} as ImmutablePoolStateMap)
115
+ );
98
116
  }
99
117
 
100
118
  // Any data from API will be immutable. Mutable data such as balances, etc will be fetched via onchain/event state.
101
119
  export async function getPoolsApi(
102
120
  network: number,
121
+ hooksConfigMap: HooksConfigMap,
103
122
  timestamp?: number,
104
123
  ): Promise<ImmutablePoolStateMap> {
105
124
  try {
@@ -121,7 +140,7 @@ export async function getPoolsApi(
121
140
  );
122
141
 
123
142
  const pools = response.data.data.poolGetAggregatorPools;
124
- return toImmutablePoolStateMap(pools);
143
+ return toImmutablePoolStateMap(pools, hooksConfigMap);
125
144
  } catch (error) {
126
145
  // console.error('Error executing GraphQL query:', error);
127
146
  throw error;
@@ -1,5 +1,6 @@
1
1
  import axios from 'axios';
2
2
  import { apiUrl, BalancerV3Config, disabledPoolIds } from './config';
3
+ import { HooksConfigMap } from './hooks/balancer-hook-event-subscriber';
3
4
 
4
5
  interface PoolToken {
5
6
  address: string;
@@ -16,6 +17,9 @@ export interface Pool {
16
17
  dynamicData: {
17
18
  totalLiquidity: string;
18
19
  };
20
+ hook: {
21
+ address: string;
22
+ } | null;
19
23
  }
20
24
 
21
25
  interface QueryResponse {
@@ -39,7 +43,6 @@ function createQuery(
39
43
  const whereClause = {
40
44
  chainIn: networkString,
41
45
  protocolVersionIn: 3,
42
- hasHook: false,
43
46
  idIn: `[${poolIdString}]`,
44
47
  ...(disabledPoolIdsString && { idNotIn: `[${disabledPoolIdsString}]` }),
45
48
  };
@@ -68,6 +71,9 @@ function createQuery(
68
71
  dynamicData {
69
72
  totalLiquidity
70
73
  }
74
+ hook {
75
+ address
76
+ }
71
77
  }
72
78
  }
73
79
  `;
@@ -77,6 +83,7 @@ export async function getTopPoolsApi(
77
83
  networkId: number,
78
84
  poolsFilter: string[],
79
85
  count: number,
86
+ hooksTypeMap: HooksConfigMap,
80
87
  ): Promise<Pool[]> {
81
88
  try {
82
89
  const query = createQuery(networkId, poolsFilter, count);
@@ -92,7 +99,11 @@ export async function getTopPoolsApi(
92
99
  },
93
100
  );
94
101
 
95
- const pools = response.data.data.poolGetAggregatorPools;
102
+ const pools = response.data.data.poolGetAggregatorPools.filter(
103
+ pool =>
104
+ !pool.hook ||
105
+ (pool.hook && pool.hook.address.toLowerCase() in hooksTypeMap),
106
+ );
96
107
  return pools;
97
108
  } catch (error) {
98
109
  // console.error('Error executing GraphQL query:', error);