@paraswap/dex-lib 4.0.3 → 4.0.5-balancer-v3.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 (57) hide show
  1. package/build/dex/balancer-v3/balancer-v3-pool.d.ts +1 -0
  2. package/build/dex/balancer-v3/balancer-v3-pool.js +29 -11
  3. package/build/dex/balancer-v3/balancer-v3-pool.js.map +1 -1
  4. package/build/dex/balancer-v3/config.js +1 -5
  5. package/build/dex/balancer-v3/config.js.map +1 -1
  6. package/build/dex/balancer-v3/getOnChainState.d.ts +9 -0
  7. package/build/dex/balancer-v3/getOnChainState.js +38 -5
  8. package/build/dex/balancer-v3/getOnChainState.js.map +1 -1
  9. package/build/dex/balancer-v3/types.d.ts +1 -0
  10. package/build/dex/bebop/bebop.js +1 -1
  11. package/build/dex/bebop/bebop.js.map +1 -1
  12. package/build/dex/cables/cables.d.ts +4 -2
  13. package/build/dex/cables/cables.js +90 -155
  14. package/build/dex/cables/cables.js.map +1 -1
  15. package/build/dex/cables/constants.d.ts +0 -1
  16. package/build/dex/cables/constants.js +2 -3
  17. package/build/dex/cables/constants.js.map +1 -1
  18. package/build/dex/cables/rate-fetcher.js +26 -10
  19. package/build/dex/cables/rate-fetcher.js.map +1 -1
  20. package/build/dex/cables/types.d.ts +15 -28
  21. package/build/dex/cables/types.js +2 -13
  22. package/build/dex/cables/types.js.map +1 -1
  23. package/build/dex/dexalot/dexalot.js.map +1 -1
  24. package/build/dex/index.js +2 -0
  25. package/build/dex/index.js.map +1 -1
  26. package/build/executor/Executor01BytecodeBuilder.js +11 -6
  27. package/build/executor/Executor01BytecodeBuilder.js.map +1 -1
  28. package/build/executor/Executor02BytecodeBuilder.js +11 -6
  29. package/build/executor/Executor02BytecodeBuilder.js.map +1 -1
  30. package/build/executor/Executor03BytecodeBuilder.js +11 -6
  31. package/build/executor/Executor03BytecodeBuilder.js.map +1 -1
  32. package/build/types.d.ts +1 -0
  33. package/package.json +1 -1
  34. package/src/abi/cables/CablesMainnetRFQ.json +1083 -0
  35. package/src/dex/balancer-v3/balancer-v3-e2e.test.ts +30 -6
  36. package/src/dex/balancer-v3/balancer-v3-integration.test.ts +229 -1
  37. package/src/dex/balancer-v3/balancer-v3-pool.ts +52 -10
  38. package/src/dex/balancer-v3/config.ts +1 -5
  39. package/src/dex/balancer-v3/getOnChainState.ts +80 -6
  40. package/src/dex/balancer-v3/types.ts +1 -0
  41. package/src/dex/bebop/bebop.ts +1 -1
  42. package/src/dex/cables/cables-e2e.test.ts +207 -0
  43. package/src/dex/cables/cables-integration.test.ts +391 -0
  44. package/src/dex/cables/cables.ts +823 -0
  45. package/src/dex/cables/config.ts +13 -0
  46. package/src/dex/cables/constants.ts +33 -0
  47. package/src/dex/cables/rate-fetcher.ts +212 -0
  48. package/src/dex/cables/types.ts +113 -0
  49. package/src/dex/cables/validators.test.ts +151 -0
  50. package/src/dex/cables/validators.ts +61 -0
  51. package/src/dex/dexalot/dexalot.ts +1 -0
  52. package/src/dex/index.ts +2 -0
  53. package/src/executor/Executor01BytecodeBuilder.ts +15 -11
  54. package/src/executor/Executor02BytecodeBuilder.ts +13 -9
  55. package/src/executor/Executor03BytecodeBuilder.ts +16 -9
  56. package/src/types.ts +1 -0
  57. package/tests/constants-e2e.ts +13 -2
@@ -216,8 +216,8 @@ describe('BalancerV3 E2E', () => {
216
216
  const tokenASymbol: string = 'WXDAI';
217
217
  const tokenBSymbol: string = 'COW';
218
218
 
219
- const tokenAAmount: string = '1000000000000000000';
220
- const tokenBAmount: string = '1000000000000000000';
219
+ const tokenAAmount: string = '100000000000000000';
220
+ const tokenBAmount: string = '100000000000000000';
221
221
  const nativeTokenAmount = '100000000000000';
222
222
 
223
223
  testForNetwork(
@@ -233,12 +233,12 @@ describe('BalancerV3 E2E', () => {
233
233
  });
234
234
 
235
235
  describe('Weighed Path', () => {
236
- const tokenASymbol: string = 'USDCe';
237
- const tokenBSymbol: string = 'sDAI';
236
+ const tokenASymbol: string = 'sDAI';
237
+ const tokenBSymbol: string = 'XDAI';
238
238
 
239
- const tokenAAmount: string = '1000000';
239
+ const tokenAAmount: string = '100000000000000000';
240
240
  const tokenBAmount: string = '100000000000000000';
241
- const nativeTokenAmount = '0';
241
+ const nativeTokenAmount = '100000000000000000';
242
242
 
243
243
  testForNetwork(
244
244
  network,
@@ -272,4 +272,28 @@ describe('BalancerV3 E2E', () => {
272
272
  );
273
273
  });
274
274
  });
275
+
276
+ describe('Mainnet', () => {
277
+ const network = Network.MAINNET;
278
+
279
+ describe('Stable Path', () => {
280
+ const tokenASymbol: string = 'wUSDL';
281
+ const tokenBSymbol: string = 'USDC';
282
+
283
+ const tokenAAmount: string = '1000000000000000000';
284
+ const tokenBAmount: string = '10000000';
285
+ const nativeTokenAmount = '0';
286
+
287
+ testForNetwork(
288
+ network,
289
+ dexKey,
290
+ tokenASymbol,
291
+ tokenBSymbol,
292
+ tokenAAmount,
293
+ tokenBAmount,
294
+ nativeTokenAmount,
295
+ false,
296
+ );
297
+ });
298
+ });
275
299
  });
@@ -187,7 +187,7 @@ async function checkOnChainPricingNonMulti(
187
187
  // test match for each returned price
188
188
  for (const price of prices) {
189
189
  let expectedPrices: bigint[] = [];
190
- if (price.data.steps.length === 1)
190
+ if (price.data.steps.length === 1 && !price.data.steps[0].isBuffer)
191
191
  expectedPrices = await querySinglePathPrices(
192
192
  network,
193
193
  side,
@@ -831,6 +831,234 @@ describe('BalancerV3', function () {
831
831
  }
832
832
  });
833
833
  });
834
+
835
+ describe('Buffer, Nested Rate', () => {
836
+ /*
837
+ The Gnosis pool, 0x272d6be442e30d7c87390edeb9b96f1e84cecd8d uses a rate provider that is nested.
838
+ So unwrap rate does not equal rate between aave wsteth and eth.
839
+ This particular case the rate provider accounts for growth of wsteth in terms of weth and the additional aave yield.
840
+ This highlighted that rateProvider can not be used for buffer wrap/unwrap which instead should use erc4626 rate.
841
+ */
842
+ const dexHelper = new DummyDexHelper(network);
843
+
844
+ const tokens = Tokens[network];
845
+ const srcTokenSymbol = 'wstETH';
846
+ const destTokenSymbol = 'waGnowstETH';
847
+
848
+ const amountsForSell = [
849
+ 0n,
850
+ 1n * BI_POWS[tokens[srcTokenSymbol].decimals],
851
+ 100n * BI_POWS[tokens[srcTokenSymbol].decimals],
852
+ ];
853
+
854
+ const amountsForBuy = [
855
+ 0n,
856
+ 1n * BI_POWS[tokens[destTokenSymbol].decimals],
857
+ 100n * BI_POWS[tokens[destTokenSymbol].decimals],
858
+ ];
859
+
860
+ beforeAll(async () => {
861
+ blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
862
+ balancerV3 = new BalancerV3(network, dexKey, dexHelper);
863
+ if (balancerV3.initializePricing) {
864
+ await balancerV3.initializePricing(blockNumber);
865
+ }
866
+ });
867
+
868
+ it('getPoolIdentifiers and getPricesVolume SELL', async function () {
869
+ await testPricingOnNetwork(
870
+ balancerV3,
871
+ network,
872
+ dexKey,
873
+ blockNumber,
874
+ srcTokenSymbol,
875
+ destTokenSymbol,
876
+ SwapSide.SELL,
877
+ amountsForSell,
878
+ );
879
+ });
880
+
881
+ it('getPoolIdentifiers and getPricesVolume BUY', async function () {
882
+ await testPricingOnNetwork(
883
+ balancerV3,
884
+ network,
885
+ dexKey,
886
+ blockNumber,
887
+ srcTokenSymbol,
888
+ destTokenSymbol,
889
+ SwapSide.BUY,
890
+ amountsForBuy,
891
+ );
892
+ });
893
+ });
894
+ });
895
+
896
+ describe('Mainnet', () => {
897
+ const network = Network.MAINNET;
898
+ describe('Token/Underlying With Different Decimals', () => {
899
+ /*
900
+ Mainnet Pool, 0x5dd88b3aa3143173eb26552923922bdf33f50949 has an ERC4626 token with 18 decimals that uses a 6 decimal underlying.
901
+ Note for maths: Instead of manually adding support for each ERC4626 implementation (e.g. stata with Ray maths) we always use an
902
+ 18 decimal scaled rate and do 18 decimal maths to convert. We may end up loosing 100% accuracy but thats deemed acceptable.
903
+ */
904
+ describe.only('Buffer wrap 6decimal>18decimal', () => {
905
+ const dexHelper = new DummyDexHelper(network);
906
+
907
+ const tokens = Tokens[network];
908
+ const srcTokenSymbol = 'USDC';
909
+ const destTokenSymbol = 'steakUSDC';
910
+
911
+ const amountsForSell = [
912
+ 0n,
913
+ 1n * BI_POWS[tokens[srcTokenSymbol].decimals],
914
+ 10n * BI_POWS[tokens[srcTokenSymbol].decimals],
915
+ ];
916
+
917
+ const amountsForBuy = [
918
+ 0n,
919
+ 1n * BI_POWS[tokens[destTokenSymbol].decimals],
920
+ 10n * BI_POWS[tokens[destTokenSymbol].decimals],
921
+ ];
922
+
923
+ beforeAll(async () => {
924
+ blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
925
+ balancerV3 = new BalancerV3(network, dexKey, dexHelper);
926
+ if (balancerV3.initializePricing) {
927
+ await balancerV3.initializePricing(blockNumber);
928
+ }
929
+ });
930
+
931
+ it('getPoolIdentifiers and getPricesVolume SELL', async function () {
932
+ await testPricingOnNetwork(
933
+ balancerV3,
934
+ network,
935
+ dexKey,
936
+ blockNumber,
937
+ srcTokenSymbol,
938
+ destTokenSymbol,
939
+ SwapSide.SELL,
940
+ amountsForSell,
941
+ );
942
+ });
943
+
944
+ it('getPoolIdentifiers and getPricesVolume BUY', async function () {
945
+ await testPricingOnNetwork(
946
+ balancerV3,
947
+ network,
948
+ dexKey,
949
+ blockNumber,
950
+ srcTokenSymbol,
951
+ destTokenSymbol,
952
+ SwapSide.BUY,
953
+ amountsForBuy,
954
+ );
955
+ });
956
+ });
957
+ describe('Buffer unwrap 18decimal>6decimal', () => {
958
+ const dexHelper = new DummyDexHelper(network);
959
+
960
+ const tokens = Tokens[network];
961
+ const srcTokenSymbol = 'steakUSDC';
962
+ const destTokenSymbol = 'USDC';
963
+
964
+ const amountsForSell = [
965
+ 0n,
966
+ 1n * BI_POWS[tokens[srcTokenSymbol].decimals],
967
+ 10n * BI_POWS[tokens[srcTokenSymbol].decimals],
968
+ ];
969
+
970
+ const amountsForBuy = [
971
+ 0n,
972
+ 1n * BI_POWS[tokens[destTokenSymbol].decimals],
973
+ 10n * BI_POWS[tokens[destTokenSymbol].decimals],
974
+ ];
975
+
976
+ beforeAll(async () => {
977
+ blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
978
+ balancerV3 = new BalancerV3(network, dexKey, dexHelper);
979
+ if (balancerV3.initializePricing) {
980
+ await balancerV3.initializePricing(blockNumber);
981
+ }
982
+ });
983
+
984
+ it('getPoolIdentifiers and getPricesVolume SELL', async function () {
985
+ await testPricingOnNetwork(
986
+ balancerV3,
987
+ network,
988
+ dexKey,
989
+ blockNumber,
990
+ srcTokenSymbol,
991
+ destTokenSymbol,
992
+ SwapSide.SELL,
993
+ amountsForSell,
994
+ );
995
+ });
996
+
997
+ it('getPoolIdentifiers and getPricesVolume BUY', async function () {
998
+ await testPricingOnNetwork(
999
+ balancerV3,
1000
+ network,
1001
+ dexKey,
1002
+ blockNumber,
1003
+ srcTokenSymbol,
1004
+ destTokenSymbol,
1005
+ SwapSide.BUY,
1006
+ amountsForBuy,
1007
+ );
1008
+ });
1009
+ });
1010
+ describe('Full boosted path', () => {
1011
+ const dexHelper = new DummyDexHelper(network);
1012
+
1013
+ const tokens = Tokens[network];
1014
+ const srcTokenSymbol = 'wUSDL';
1015
+ const destTokenSymbol = 'USDC';
1016
+
1017
+ const amountsForSell = [
1018
+ 0n,
1019
+ 1n * BI_POWS[tokens[srcTokenSymbol].decimals],
1020
+ ];
1021
+
1022
+ const amountsForBuy = [
1023
+ 0n,
1024
+ 1n * BI_POWS[tokens[destTokenSymbol].decimals],
1025
+ ];
1026
+
1027
+ beforeAll(async () => {
1028
+ blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
1029
+ balancerV3 = new BalancerV3(network, dexKey, dexHelper);
1030
+ if (balancerV3.initializePricing) {
1031
+ await balancerV3.initializePricing(blockNumber);
1032
+ }
1033
+ });
1034
+
1035
+ it('getPoolIdentifiers and getPricesVolume SELL', async function () {
1036
+ await testPricingOnNetwork(
1037
+ balancerV3,
1038
+ network,
1039
+ dexKey,
1040
+ blockNumber,
1041
+ srcTokenSymbol,
1042
+ destTokenSymbol,
1043
+ SwapSide.SELL,
1044
+ amountsForSell,
1045
+ );
1046
+ });
1047
+
1048
+ it('getPoolIdentifiers and getPricesVolume BUY', async function () {
1049
+ await testPricingOnNetwork(
1050
+ balancerV3,
1051
+ network,
1052
+ dexKey,
1053
+ blockNumber,
1054
+ srcTokenSymbol,
1055
+ destTokenSymbol,
1056
+ SwapSide.BUY,
1057
+ amountsForBuy,
1058
+ );
1059
+ });
1060
+ });
1061
+ });
834
1062
  });
835
1063
  });
836
1064
 
@@ -14,7 +14,12 @@ import {
14
14
  } from './types';
15
15
  import { getPoolsApi } from './getPoolsApi';
16
16
  import vaultExtensionAbi_V3 from '../../abi/balancer-v3/vault-extension.json';
17
- import { decodeThrowError, getOnChainState } from './getOnChainState';
17
+ import {
18
+ decodeErc4626MultiCallData,
19
+ decodeThrowError,
20
+ getErc4626MultiCallData,
21
+ getOnChainState,
22
+ } from './getOnChainState';
18
23
  import { BalancerV3Config } from './config';
19
24
  import { SwapKind, Vault } from '@balancer-labs/balancer-maths';
20
25
  import {
@@ -25,7 +30,7 @@ import {
25
30
  } from './stablePool';
26
31
  import { BI_POWS } from '../../bigint-constants';
27
32
 
28
- const WAD = BI_POWS[18];
33
+ export const WAD = BI_POWS[18];
29
34
 
30
35
  export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
31
36
  handlers: {
@@ -65,6 +70,9 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
65
70
  'function getAmplificationParameter() external view returns (uint256 value, bool isUpdating, uint256 precision)',
66
71
  'function getAmplificationState() external view returns (tuple(uint64 startValue, uint64 endValue, uint32 startTime, uint32 endTime) amplificationState, uint256 precision)',
67
72
  ]),
73
+ ['ERC4626']: new Interface([
74
+ 'function convertToAssets(uint256 shares) external view returns (uint256 assets)',
75
+ ]),
68
76
  };
69
77
 
70
78
  this.logDecoder = (log: Log) => this.interfaces['VAULT'].parseLog(log);
@@ -445,11 +453,12 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
445
453
  if (!poolState) return;
446
454
 
447
455
  // Fetch onchain pool rates
448
- const poolRates = await this.getPoolRates(Object.keys(poolState));
456
+ const poolRates = await this.getPoolRates(poolState);
449
457
 
450
458
  // Update each pools rate
451
- poolRates.forEach(({ poolAddress, tokenRates }, i) => {
459
+ poolRates.forEach(({ poolAddress, tokenRates, erc4626Rates }, i) => {
452
460
  poolState[poolAddress].tokenRates = tokenRates;
461
+ poolState[poolAddress].erc4626Rates = erc4626Rates;
453
462
  });
454
463
 
455
464
  // Update state
@@ -457,9 +466,15 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
457
466
  this.setState(poolState, blockNumber);
458
467
  }
459
468
 
460
- private async getPoolRates(poolAddresses: string[]) {
469
+ private async getPoolRates(poolState: PoolStateMap) {
470
+ const erc4626MultiCallData = getErc4626MultiCallData(
471
+ this.interfaces['ERC4626'],
472
+ poolState,
473
+ );
474
+
475
+ const poolAddresses = Object.keys(poolState);
461
476
  // For each pool make the getPoolTokenRates call
462
- const multiCallData = poolAddresses.map(address => {
477
+ const poolsMultiCallData = poolAddresses.map(address => {
463
478
  return {
464
479
  target: BalancerV3Config.BalancerV3[this.network].vaultAddress,
465
480
  callData: this.interfaces['VAULT'].encodeFunctionData(
@@ -469,10 +484,13 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
469
484
  };
470
485
  });
471
486
  // 500 is an arbitrary number chosen based on the blockGasLimit
472
- const slicedMultiCallData = _.chunk(multiCallData, 500);
487
+ const slicedMultiCallData = _.chunk(
488
+ [...erc4626MultiCallData, ...poolsMultiCallData],
489
+ 500,
490
+ );
473
491
 
474
492
  // Make the multicall
475
- const multicallData = (
493
+ const multicallDataResult = (
476
494
  await Promise.all(
477
495
  slicedMultiCallData.map(async _multiCallData =>
478
496
  this.dexHelper.multiContract.methods
@@ -482,16 +500,34 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
482
500
  )
483
501
  ).flat();
484
502
 
503
+ const dataResultErc4626 = multicallDataResult.slice(
504
+ 0,
505
+ erc4626MultiCallData.length,
506
+ );
507
+ const dataResultPools = multicallDataResult.slice(
508
+ erc4626MultiCallData.length,
509
+ );
510
+
511
+ const tokensWithRates = decodeErc4626MultiCallData(
512
+ this.interfaces['ERC4626'],
513
+ erc4626MultiCallData,
514
+ dataResultErc4626,
515
+ );
516
+
485
517
  return poolAddresses.map((address, i) => {
486
518
  const tokenRateResult = decodeThrowError(
487
519
  this.interfaces['VAULT'],
488
520
  'getPoolTokenRates',
489
- multicallData[i],
521
+ dataResultPools[i],
490
522
  address,
491
523
  );
492
524
  return {
493
525
  poolAddress: address,
494
526
  tokenRates: tokenRateResult.tokenRates.map((r: string) => BigInt(r)),
527
+ erc4626Rates: poolState[address].tokens.map(t => {
528
+ if (!tokensWithRates[t]) return null;
529
+ return tokensWithRates[t];
530
+ }),
495
531
  };
496
532
  });
497
533
  }
@@ -522,12 +558,18 @@ export class BalancerV3EventPool extends StatefulEventSubscriber<PoolStateMap> {
522
558
  address && address.toLowerCase() === tokenAddress.toLowerCase(),
523
559
  );
524
560
  if (tokenIndex !== -1) {
561
+ if (poolState.erc4626Rates[tokenIndex] === null) {
562
+ this.logger.error(
563
+ `missing erc4626 token rate ${poolState.tokens[tokenIndex]}`,
564
+ );
565
+ return null;
566
+ }
525
567
  return {
526
568
  isBoosted: true,
527
569
  mainToken: poolState.tokens[tokenIndex],
528
570
  underlyingToken: tokenAddress,
529
571
  index: tokenIndex,
530
- rate: poolState.tokenRates[tokenIndex],
572
+ rate: poolState.erc4626Rates[tokenIndex]!,
531
573
  };
532
574
  }
533
575
  }
@@ -10,11 +10,7 @@ export enum SUPPORTED_POOLS {
10
10
 
11
11
  export const disabledPoolIds: Record<string, Record<number, string[]>> = {
12
12
  BalancerV3: {
13
- [Network.GNOSIS]: [
14
- // pools with rate provider that returns nested rate instead of wrap/unwrap rate
15
- '0x6e6bb18449fcf15b79efa2cfa70acf7593088029',
16
- '0x272d6be442e30d7c87390edeb9b96f1e84cecd8d',
17
- ],
13
+ [Network.GNOSIS]: [],
18
14
  },
19
15
  };
20
16
 
@@ -8,6 +8,7 @@ import {
8
8
  import { BalancerV3Config } from './config';
9
9
  import { Interface, Result } from '@ethersproject/abi';
10
10
  import { IDexHelper } from '../../dex-helper';
11
+ import { WAD } from './balancer-v3-pool';
11
12
 
12
13
  interface callData {
13
14
  target: string;
@@ -85,7 +86,7 @@ const poolOnChain: Record<
85
86
  poolAddress: string,
86
87
  data: any,
87
88
  startIndex: number,
88
- ): CommonMutableState => {
89
+ ): Omit<CommonMutableState, 'erc4626Rates'> => {
89
90
  const resultTokenRates = decodeThrowError(
90
91
  contractInterface,
91
92
  'getPoolTokenRates',
@@ -259,6 +260,52 @@ export function decodeThrowError(
259
260
  );
260
261
  }
261
262
 
263
+ export function getErc4626MultiCallData(
264
+ erc4626Interface: Interface,
265
+ immutablePoolStateMap: ImmutablePoolStateMap,
266
+ ): callData[] {
267
+ // We want to query rate for each unique ERC4626 token
268
+ const uniqueErc4626Tokens = Array.from(
269
+ new Set(
270
+ Object.values(immutablePoolStateMap).flatMap(pool =>
271
+ pool.tokens.filter((_, index) => pool.tokensUnderlying[index] !== null),
272
+ ),
273
+ ),
274
+ );
275
+
276
+ // query result for 1e18 (this maintains correct scaling for different token decimals in maths)
277
+ const erc4626MultiCallData: callData[] = uniqueErc4626Tokens.map(token => {
278
+ return {
279
+ target: token,
280
+ callData: erc4626Interface.encodeFunctionData('convertToAssets', [WAD]),
281
+ };
282
+ });
283
+ return erc4626MultiCallData;
284
+ }
285
+
286
+ export function decodeErc4626MultiCallData(
287
+ erc4626Interface: Interface,
288
+ erc4626MultiCallData: callData[],
289
+ dataResultErc4626: any[],
290
+ ) {
291
+ return Object.fromEntries(
292
+ erc4626MultiCallData.map((multiCallData, i) => {
293
+ const rate = decodeThrowError(
294
+ erc4626Interface,
295
+ 'convertToAssets',
296
+ dataResultErc4626[i],
297
+ multiCallData.target,
298
+ );
299
+ if (!rate)
300
+ throw new Error(
301
+ `Failed to get result for convertToAssets for ${multiCallData.target}`,
302
+ );
303
+
304
+ return [multiCallData.target, BigInt(rate[0])];
305
+ }),
306
+ );
307
+ }
308
+
262
309
  // Any data from API will be immutable. Mutable data such as balances, etc will be fetched via onchain/event state.
263
310
  export async function getOnChainState(
264
311
  network: number,
@@ -269,7 +316,13 @@ export async function getOnChainState(
269
316
  },
270
317
  blockNumber?: number,
271
318
  ): Promise<PoolStateMap> {
272
- const multiCallData = Object.entries(immutablePoolStateMap)
319
+ const erc4626MultiCallData = getErc4626MultiCallData(
320
+ interfaces['ERC4626'],
321
+ immutablePoolStateMap,
322
+ );
323
+
324
+ // query pool specific onchain data, e.g. totalSupply, etc
325
+ const poolsMultiCallData = Object.entries(immutablePoolStateMap)
273
326
  .map(([address, pool]) => {
274
327
  return [
275
328
  ...poolOnChain['COMMON'].encode(network, interfaces['VAULT'], address),
@@ -283,9 +336,12 @@ export async function getOnChainState(
283
336
  .flat();
284
337
 
285
338
  // 500 is an arbitrary number chosen based on the blockGasLimit
286
- const slicedMultiCallData = _.chunk(multiCallData, 500);
339
+ const slicedMultiCallData = _.chunk(
340
+ [...erc4626MultiCallData, ...poolsMultiCallData],
341
+ 500,
342
+ );
287
343
 
288
- const multicallData = (
344
+ const multicallDataResult = (
289
345
  await Promise.all(
290
346
  slicedMultiCallData.map(async _multiCallData =>
291
347
  dexHelper.multiContract.methods
@@ -295,20 +351,34 @@ export async function getOnChainState(
295
351
  )
296
352
  ).flat();
297
353
 
354
+ const dataResultErc4626 = multicallDataResult.slice(
355
+ 0,
356
+ erc4626MultiCallData.length,
357
+ );
358
+ const dataResultPools = multicallDataResult.slice(
359
+ erc4626MultiCallData.length,
360
+ );
361
+
362
+ const tokensWithRates = decodeErc4626MultiCallData(
363
+ interfaces['ERC4626'],
364
+ erc4626MultiCallData,
365
+ dataResultErc4626,
366
+ );
367
+
298
368
  let i = 0;
299
369
  const poolStateMap = Object.fromEntries(
300
370
  Object.entries(immutablePoolStateMap).map(([address, pool]) => {
301
371
  const commonMutableData = poolOnChain['COMMON'].decode(
302
372
  interfaces['VAULT'],
303
373
  address,
304
- multicallData,
374
+ dataResultPools,
305
375
  i,
306
376
  ) as CommonMutableState;
307
377
  i = i + poolOnChain['COMMON'].count;
308
378
  const poolMutableData = poolOnChain[pool.poolType].decode(
309
379
  interfaces[pool.poolType],
310
380
  address,
311
- multicallData,
381
+ dataResultPools,
312
382
  i,
313
383
  );
314
384
  i = i + poolOnChain[pool.poolType].count;
@@ -318,6 +388,10 @@ export async function getOnChainState(
318
388
  ...pool,
319
389
  ...commonMutableData,
320
390
  ...poolMutableData,
391
+ erc4626Rates: pool.tokens.map(t => {
392
+ if (!tokensWithRates[t]) return null;
393
+ return tokensWithRates[t];
394
+ }),
321
395
  },
322
396
  ];
323
397
  }),
@@ -18,6 +18,7 @@ export type CommonImmutablePoolState = {
18
18
  // Mutable data types available on all pools (Available via onchain calls/events)
19
19
  export interface CommonMutableState {
20
20
  tokenRates: bigint[];
21
+ erc4626Rates: (bigint | null)[];
21
22
  balancesLiveScaled18: bigint[];
22
23
  swapFee: bigint;
23
24
  aggregateSwapFee: bigint;
@@ -723,7 +723,7 @@ export class Bebop extends SimpleExchange implements IDex<BebopData> {
723
723
  }
724
724
  }
725
725
 
726
- if (side == SwapSide.SELL) {
726
+ if (side === SwapSide.SELL) {
727
727
  const requiredAmount = BigInt(optimalSwapExchange.destAmount);
728
728
  const quoteAmount = BigInt(
729
729
  response.buyTokens[utils.getAddress(destToken.address)].amount,