@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
@@ -0,0 +1,226 @@
1
+ import {
2
+ EventFragment,
3
+ Fragment,
4
+ FunctionFragment,
5
+ Interface,
6
+ } from '@ethersproject/abi';
7
+ import _ from 'lodash';
8
+ import { DeepReadonly } from 'ts-essentials';
9
+ import { Log, Logger } from '../../../types';
10
+ import { catchParseLogError } from '../../../utils';
11
+ import { StatefulEventSubscriber } from '../../../stateful-event-subscriber';
12
+ import { IDexHelper } from '../../../dex-helper/idex-helper';
13
+ import { loadHooksConfig } from './loadHooksConfig';
14
+ import {
15
+ DirectionalFee,
16
+ DirectionalFeeConfig,
17
+ DirectionalFeeHookState,
18
+ getDirectionalFeeHookState,
19
+ } from './directionalFeeHook';
20
+ import exitFeeHookAbi from '../../../abi/balancer-v3/directionalFeeHook.json';
21
+ import {
22
+ getStableSurgeHookState,
23
+ maxSurgeFeePercentageChangedEvent,
24
+ StableSurge,
25
+ StableSurgeConfig,
26
+ StableSurgeHookState,
27
+ thresholdSurgePercentageChangedEvent,
28
+ } from './stableSurgeHook';
29
+ import stableSurgeHookAbi from '../../../abi/balancer-v3/stableSurgeHook.json';
30
+
31
+ // Add each supported hook state here
32
+ export type HookState = DirectionalFeeHookState | StableSurgeHookState;
33
+
34
+ export type HookStateMap = {
35
+ [address: string]: HookState;
36
+ };
37
+
38
+ export type HookConfig = DirectionalFeeConfig | StableSurgeConfig;
39
+
40
+ export type HooksConfigMap = {
41
+ [hookAddress: string]: HookConfig;
42
+ };
43
+
44
+ /**
45
+ * This will handle events/state for each supported hook contract. State is used during swap calculations.
46
+ * Each hook should have its own implementation file for state typing, fetching state and handling events.
47
+ */
48
+ export class BalancerEventHook extends StatefulEventSubscriber<HookStateMap> {
49
+ handlers: {
50
+ [event: string]: (
51
+ event: any,
52
+ state: DeepReadonly<HookStateMap>,
53
+ log: Readonly<Log>,
54
+ ) => DeepReadonly<HookStateMap> | null;
55
+ } = {};
56
+
57
+ interfaces: Interface[];
58
+ logDecoder: (log: Log) => any;
59
+
60
+ addressesSubscribed: string[];
61
+
62
+ hooksConfigMap: HooksConfigMap;
63
+
64
+ constructor(
65
+ readonly parentName: string,
66
+ protected network: number,
67
+ protected dexHelper: IDexHelper,
68
+ logger: Logger,
69
+ ) {
70
+ super(parentName, 'Balancer_Hooks', dexHelper, logger);
71
+
72
+ // Load supported hooks from config file
73
+ this.hooksConfigMap = loadHooksConfig(network);
74
+
75
+ // Add each hook ABI here
76
+ this.interfaces = [
77
+ new Interface(exitFeeHookAbi),
78
+ new Interface(stableSurgeHookAbi),
79
+ ];
80
+ this.logDecoder = (log: Log) =>
81
+ this.combineInterfaces(this.interfaces).parseLog(log);
82
+
83
+ // Subscribe to all hooks
84
+ this.addressesSubscribed = Object.keys(this.hooksConfigMap);
85
+
86
+ // StableSurgeHook events
87
+ this.handlers['ThresholdSurgePercentageChanged'] =
88
+ thresholdSurgePercentageChangedEvent.bind(this);
89
+ this.handlers['MaxSurgeFeePercentageChanged'] =
90
+ maxSurgeFeePercentageChangedEvent.bind(this);
91
+ }
92
+
93
+ /**
94
+ * The function is called every time any of the subscribed
95
+ * addresses release log. The function accepts the current
96
+ * state, updates the state according to the log, and returns
97
+ * the updated state.
98
+ * @param state - Current state of event subscriber
99
+ * @param log - Log released by one of the subscribed addresses
100
+ * @returns Updates state of the event subscriber after the log
101
+ */
102
+ protected processLog(
103
+ state: DeepReadonly<HookStateMap>,
104
+ log: Readonly<Log>,
105
+ ): DeepReadonly<HookStateMap> | null {
106
+ try {
107
+ const event = this.logDecoder(log);
108
+ if (event.name in this.handlers) {
109
+ return this.handlers[event.name](event, state, log);
110
+ }
111
+ } catch (e) {
112
+ catchParseLogError(e, this.logger);
113
+ }
114
+
115
+ return null;
116
+ }
117
+
118
+ /**
119
+ * The function generates state using on-chain calls. This
120
+ * function is called to regenerate state if the event based
121
+ * system fails to fetch events and the local state is no
122
+ * more correct.
123
+ * @param blockNumber - Blocknumber for which the state should
124
+ * should be generated
125
+ * @returns state of the event subscriber at blocknumber
126
+ */
127
+ async generateState(
128
+ blockNumber: number,
129
+ ): Promise<DeepReadonly<HookStateMap>> {
130
+ // Only hooks that are supported will be called
131
+ const hookState: HookStateMap = {};
132
+
133
+ await Promise.all(
134
+ Object.keys(this.hooksConfigMap).map(async hookAddress => {
135
+ const hookConfig = this.hooksConfigMap[hookAddress];
136
+ if (hookConfig.type === DirectionalFee.type) {
137
+ hookState[hookAddress] = await getDirectionalFeeHookState();
138
+ } else if (hookConfig.type === StableSurge.type) {
139
+ hookState[hookAddress] = await getStableSurgeHookState(
140
+ this.interfaces[1],
141
+ hookAddress,
142
+ hookConfig.factory,
143
+ this.dexHelper,
144
+ blockNumber,
145
+ );
146
+ }
147
+ }),
148
+ );
149
+
150
+ // for (const hookAddress in this.hooksConfigMap) {
151
+ // const hookConfig = this.hooksConfigMap[hookAddress];
152
+ // if (hookConfig.type === DirectionalFee.type) {
153
+ // hookState[hookAddress] = await getDirectionalFeeHookState();
154
+ // } else if (hookConfig.type === StableSurge.type) {
155
+ // hookState[hookAddress] = await getStableSurgeHookState(
156
+ // this.interfaces[1],
157
+ // hookAddress,
158
+ // hookConfig.factory,
159
+ // this.dexHelper,
160
+ // blockNumber,
161
+ // );
162
+ // }
163
+ // }
164
+
165
+ return hookState;
166
+ }
167
+
168
+ async updateHookState() {
169
+ // Not all hooks need updated, only ones with settings/state that can't be handled by events
170
+ const blockNumber = await this.dexHelper.provider.getBlockNumber();
171
+ const currentState =
172
+ (_.cloneDeep(this.getStaleState()) as HookStateMap) || {};
173
+
174
+ await Promise.all(
175
+ Object.keys(this.hooksConfigMap).map(async hookAddress => {
176
+ const hookConfig = this.hooksConfigMap[hookAddress];
177
+ // StableSurge can have new registered pools with associated hook state
178
+ if (hookConfig.type === StableSurge.type) {
179
+ currentState[hookAddress] = await getStableSurgeHookState(
180
+ this.interfaces[1],
181
+ hookAddress,
182
+ hookConfig.factory,
183
+ this.dexHelper,
184
+ blockNumber,
185
+ );
186
+ }
187
+ }),
188
+ );
189
+
190
+ this.setState(currentState, blockNumber);
191
+ }
192
+
193
+ combineInterfaces = (interfaces: Interface[]): Interface => {
194
+ // Use a Map to store unique fragments, keyed by their string representation
195
+ const uniqueFragments = new Map<string, Fragment>();
196
+
197
+ interfaces.forEach((interfaceInstance: Interface) => {
198
+ interfaceInstance.fragments.forEach((fragment: Fragment) => {
199
+ let key: string;
200
+
201
+ if (fragment instanceof FunctionFragment) {
202
+ // For functions, use the signature as the key
203
+ // This includes name and parameter types
204
+ key = fragment.format();
205
+ } else if (fragment instanceof EventFragment) {
206
+ // For events, use the signature as the key
207
+ key = fragment.format();
208
+ } else {
209
+ // For other fragment types (like errors), use their string representation
210
+ key = fragment.toString();
211
+ }
212
+
213
+ // Only add if we haven't seen this signature before
214
+ if (!uniqueFragments.has(key)) {
215
+ uniqueFragments.set(key, fragment);
216
+ }
217
+ });
218
+ });
219
+
220
+ // Convert the Map values back to an array
221
+ const dedupedFragments = Array.from(uniqueFragments.values());
222
+
223
+ // Create a new interface with the deduped fragments
224
+ return new Interface(dedupedFragments);
225
+ };
226
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Each supported hook should implement its own version of this file making it easy to retrieve required onchain state.
3
+ */
4
+ import _ from 'lodash';
5
+ import { Log } from '../../../types';
6
+ import { DeepReadonly } from 'ts-essentials';
7
+ import { HookStateMap } from './balancer-hook-event-subscriber';
8
+
9
+ export const DirectionalFee = {
10
+ type: 'DirectionalFee' as const,
11
+ };
12
+
13
+ export type DirectionalFeeConfig = {
14
+ type: typeof DirectionalFee.type;
15
+ address: string;
16
+ };
17
+
18
+ export type DirectionalFeeHookState = {
19
+ test: string; // Note - this is just a dummy example as this specific test hook doesn't have any required state but is used to prove concept
20
+ };
21
+
22
+ /**
23
+ * Retrieve any initial hook state required.
24
+ * @returns
25
+ */
26
+ export async function getDirectionalFeeHookState(): Promise<DirectionalFeeHookState> {
27
+ // Note - for other hooks this function would retrieve any initial state using onchain calls
28
+ return { test: 'initial' };
29
+ }
30
+
31
+ /**
32
+ * Handles the event emitted when a new hook is registered.
33
+ * @param event
34
+ * @param state
35
+ * @param log
36
+ * @returns
37
+ */
38
+ export function exitFeeHookExampleRegisteredEvent(
39
+ event: any,
40
+ state: DeepReadonly<HookStateMap>,
41
+ log: Readonly<Log>,
42
+ ): DeepReadonly<HookStateMap> | null {
43
+ // Note - This is a non-important event but demos the use case. Other hooks would implement this for any state changes required for swap maths.
44
+ const hookAddress = event.args.hooksContract.toLowerCase();
45
+ if (!state[hookAddress]) {
46
+ return null;
47
+ }
48
+ const newState = _.cloneDeep(state) as HookStateMap;
49
+ newState[hookAddress] = { test: event.args.pool };
50
+ return newState;
51
+ }
@@ -0,0 +1,12 @@
1
+ import { BalancerV3Config } from './../config';
2
+ import { HooksConfigMap } from './balancer-hook-event-subscriber';
3
+
4
+ export function loadHooksConfig(network: number): HooksConfigMap {
5
+ const hooks = BalancerV3Config.BalancerV3[network].hooks;
6
+
7
+ if (!hooks) return {};
8
+
9
+ return Object.fromEntries(
10
+ hooks.map(hook => [hook.address.toLowerCase(), hook]),
11
+ );
12
+ }
@@ -0,0 +1,163 @@
1
+ import _ from 'lodash';
2
+ import { Log } from '../../../types';
3
+ import { DeepReadonly } from 'ts-essentials';
4
+ import { HookStateMap } from './balancer-hook-event-subscriber';
5
+ import { Interface } from '@ethersproject/abi';
6
+ import { Contract } from 'ethers';
7
+ import { IDexHelper } from '../../../dex-helper';
8
+ import { callData, decodeThrowError } from '../getOnChainState';
9
+
10
+ export const StableSurge = {
11
+ type: 'StableSurge' as const,
12
+ };
13
+
14
+ export type StableSurgeConfig = {
15
+ type: typeof StableSurge.type;
16
+ factory: string;
17
+ address: string;
18
+ };
19
+
20
+ export type StableSurgePoolSetting = {
21
+ surgeThresholdPercentage: bigint;
22
+ maxSurgeFeePercentage: bigint;
23
+ };
24
+
25
+ export type StableSurgeHookState = Record<string, StableSurgePoolSetting>;
26
+
27
+ /**
28
+ * Retrieve any initial hook state required.
29
+ * @returns
30
+ */
31
+ export async function getStableSurgeHookState(
32
+ hookInterface: Interface,
33
+ hookAddress: string,
34
+ factoryAddress: string,
35
+ dexHelper: IDexHelper,
36
+ blockNumber: number,
37
+ ): Promise<StableSurgeHookState> {
38
+ // Find all pools with hook
39
+ const resolverContract = new Contract(
40
+ factoryAddress,
41
+ ['function getPools() external view returns (address[])'],
42
+ dexHelper.provider,
43
+ );
44
+ const pools = (await resolverContract.callStatic.getPools({
45
+ blockTag: blockNumber,
46
+ })) as string[];
47
+ const surgeThresholdCallData: callData[] = pools.flatMap(pool => {
48
+ return [
49
+ {
50
+ target: hookAddress,
51
+ callData: hookInterface.encodeFunctionData(
52
+ 'getSurgeThresholdPercentage',
53
+ [pool],
54
+ ),
55
+ },
56
+ {
57
+ target: hookAddress,
58
+ callData: hookInterface.encodeFunctionData('getMaxSurgeFeePercentage', [
59
+ pool,
60
+ ]),
61
+ },
62
+ ];
63
+ });
64
+
65
+ // 500 is an arbitrary number chosen based on the blockGasLimit
66
+ const slicedMultiCallData = _.chunk(surgeThresholdCallData, 500);
67
+
68
+ const multicallDataResult = (
69
+ await Promise.all(
70
+ slicedMultiCallData.map(async _multiCallData =>
71
+ dexHelper.multiContract.methods
72
+ .tryAggregate(false, _multiCallData)
73
+ .call({}, blockNumber),
74
+ ),
75
+ )
76
+ ).flat();
77
+
78
+ return mapPoolsToDecodedData(hookInterface, pools, multicallDataResult);
79
+ }
80
+
81
+ function mapPoolsToDecodedData(
82
+ hookInterface: Interface,
83
+ pools: string[],
84
+ data: any[],
85
+ ): StableSurgeHookState {
86
+ return pools.reduce((acc, pool, index) => {
87
+ const dataIndex = index * 2;
88
+
89
+ // Ensure we have enough data
90
+ if (dataIndex + 1 >= data.length) {
91
+ throw new Error(`Insufficient data for pool ${pool}`);
92
+ }
93
+
94
+ // Decode the corresponding data pairs
95
+ const decodedX = decodeThrowError(
96
+ hookInterface,
97
+ 'getSurgeThresholdPercentage',
98
+ data[dataIndex],
99
+ 'n/a',
100
+ );
101
+ const decodedY = decodeThrowError(
102
+ hookInterface,
103
+ 'getMaxSurgeFeePercentage',
104
+ data[dataIndex + 1],
105
+ 'n/a',
106
+ );
107
+ // Add to accumulator
108
+ acc[pool.toLowerCase()] = {
109
+ surgeThresholdPercentage: decodedX[0].toBigInt(),
110
+ maxSurgeFeePercentage: decodedY[0].toBigInt(),
111
+ };
112
+
113
+ return acc;
114
+ }, {} as StableSurgeHookState);
115
+ }
116
+
117
+ /**
118
+ * Handles the event emitted when threshold surge percentage changed.
119
+ * @param event
120
+ * @param state
121
+ * @param log
122
+ * @returns
123
+ */
124
+ export function thresholdSurgePercentageChangedEvent(
125
+ event: any,
126
+ state: DeepReadonly<HookStateMap>,
127
+ log: Readonly<Log>,
128
+ ): DeepReadonly<HookStateMap> | null {
129
+ // ThresholdSurgePercentageChanged(pool, newSurgeThresholdPercentage)
130
+ const hookAddress = log.address.toLowerCase();
131
+ if (!state[hookAddress]) {
132
+ return null;
133
+ }
134
+ const newState = _.cloneDeep(state) as HookStateMap;
135
+ (newState[hookAddress] as StableSurgeHookState)[
136
+ event.args.pool.toLowerCase()
137
+ ].surgeThresholdPercentage = BigInt(event.args.newSurgeThresholdPercentage);
138
+ return newState;
139
+ }
140
+
141
+ /**
142
+ * Handles the event emitted when max surge fee percentage changed.
143
+ * @param event
144
+ * @param state
145
+ * @param log
146
+ * @returns
147
+ */
148
+ export function maxSurgeFeePercentageChangedEvent(
149
+ event: any,
150
+ state: DeepReadonly<HookStateMap>,
151
+ log: Readonly<Log>,
152
+ ): DeepReadonly<HookStateMap> | null {
153
+ // MaxSurgeFeePercentageChanged(pool, newMaxSurgeFeePercentage)
154
+ const hookAddress = log.address.toLowerCase();
155
+ if (!state[hookAddress]) {
156
+ return null;
157
+ }
158
+ const newState = _.cloneDeep(state) as HookStateMap;
159
+ (newState[hookAddress] as StableSurgeHookState)[
160
+ event.args.pool.toLowerCase()
161
+ ].maxSurgeFeePercentage = BigInt(event.args.newMaxSurgeFeePercentage);
162
+ return newState;
163
+ }
@@ -1,5 +1,6 @@
1
1
  import { BufferState } from '@balancer-labs/balancer-maths';
2
2
  import { Address } from '../../types';
3
+ import { HookConfig } from './hooks/balancer-hook-event-subscriber';
3
4
 
4
5
  // Immutable data types available on all pools (Available from API)
5
6
  export type CommonImmutablePoolState = {
@@ -12,7 +13,9 @@ export type CommonImmutablePoolState = {
12
13
  weights: bigint[];
13
14
  // TODO re-introduce this once added to API
14
15
  // scalingFactors: bigint[];
16
+ hookAddress: string | undefined;
15
17
  hookType: string | undefined;
18
+ supportsUnbalancedLiquidity: boolean;
16
19
  };
17
20
 
18
21
  // Mutable data types available on all pools (Available via onchain calls/events)
@@ -26,8 +29,6 @@ export interface CommonMutableState {
26
29
  isPoolPaused: boolean;
27
30
  // TODO remove this once API provides it
28
31
  scalingFactors: bigint[];
29
- // TODO remove this once API provides it
30
- hasHook: boolean;
31
32
  }
32
33
 
33
34
  type CommonPoolState = CommonImmutablePoolState & CommonMutableState;
@@ -76,6 +77,7 @@ export type DexParams = {
76
77
  // https://github.com/balancer/balancer-v3-monorepo/blob/main/pkg/interfaces/contracts/vault/IRouter.sol
77
78
  balancerRouterAddress: string;
78
79
  balancerBatchRouterAddress: string;
80
+ hooks?: HookConfig[];
79
81
  };
80
82
 
81
83
  export type TokenInfo = {
@@ -1694,6 +1694,10 @@ export const Tokens: {
1694
1694
  address: '0xC768c589647798a6EE01A91FdE98EF2ed046DBD6',
1695
1695
  decimals: 6,
1696
1696
  },
1697
+ waBasGHO: {
1698
+ address: '0x88b1Cd4b430D95b406E382C3cDBaE54697a0286E',
1699
+ decimals: 18,
1700
+ },
1697
1701
  aaveUSDC: {
1698
1702
  address: '0x4e65fe4dba92790696d040ac24aa414708f5c0ab',
1699
1703
  decimals: 6,
@@ -2145,7 +2149,7 @@ export const Holders: {
2145
2149
  DOG: '0xbe3ab8a87730684ef1e476064c2e43c3e982f8e8',
2146
2150
  stataUSDC: '0x88Cac91ADDE2208039A227B373C2A692C0700547',
2147
2151
  aaveUSDC: '0x5DE3c5BE52D7aDbdC3aEFe2eA061A2ECE0C7d766',
2148
- waBasUSDC: '0xC768c589647798a6EE01A91FdE98EF2ed046DBD6',
2152
+ waBasUSDC: '0x450C01300B83bE379113256038b4Dd3b45d23B5e',
2149
2153
  USDM: '0x426c4966fC76Bf782A663203c023578B744e4C5E',
2150
2154
  crvUSD: '0xBbAbDB1385deA5285113581A7024d6DC04131101',
2151
2155
  cbETH: '0x50e011dD1e2b4906F1534623cD134B30422bb11E',
@@ -2156,6 +2160,7 @@ export const Holders: {
2156
2160
  waBaswstETH: '0x854B004700885A61107B458f11eCC169A019b764',
2157
2161
  sUSDS: '0xC9716E991396AA933Fa7A481003a5953bcBabC17',
2158
2162
  smUSDC: '0x88457F47c9BEC8379eB90d8dC3592F79084e555d',
2163
+ waBasGHO: '0x450C01300B83bE379113256038b4Dd3b45d23B5e',
2159
2164
  },
2160
2165
  [Network.SEPOLIA]: {
2161
2166
  bal: '0xDb4ff41B4C1222c2b1869A67Be115070688989a2',