@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.
- package/build/dex/balancer-v3/balancer-v3-pool.d.ts +1 -0
- package/build/dex/balancer-v3/balancer-v3-pool.js +29 -11
- package/build/dex/balancer-v3/balancer-v3-pool.js.map +1 -1
- package/build/dex/balancer-v3/config.js +1 -5
- package/build/dex/balancer-v3/config.js.map +1 -1
- package/build/dex/balancer-v3/getOnChainState.d.ts +9 -0
- package/build/dex/balancer-v3/getOnChainState.js +38 -5
- package/build/dex/balancer-v3/getOnChainState.js.map +1 -1
- package/build/dex/balancer-v3/types.d.ts +1 -0
- package/build/dex/bebop/bebop.js +1 -1
- package/build/dex/bebop/bebop.js.map +1 -1
- package/build/dex/cables/cables.d.ts +4 -2
- package/build/dex/cables/cables.js +90 -155
- package/build/dex/cables/cables.js.map +1 -1
- package/build/dex/cables/constants.d.ts +0 -1
- package/build/dex/cables/constants.js +2 -3
- package/build/dex/cables/constants.js.map +1 -1
- package/build/dex/cables/rate-fetcher.js +26 -10
- package/build/dex/cables/rate-fetcher.js.map +1 -1
- package/build/dex/cables/types.d.ts +15 -28
- package/build/dex/cables/types.js +2 -13
- package/build/dex/cables/types.js.map +1 -1
- package/build/dex/dexalot/dexalot.js.map +1 -1
- package/build/dex/index.js +2 -0
- package/build/dex/index.js.map +1 -1
- package/build/executor/Executor01BytecodeBuilder.js +11 -6
- package/build/executor/Executor01BytecodeBuilder.js.map +1 -1
- package/build/executor/Executor02BytecodeBuilder.js +11 -6
- package/build/executor/Executor02BytecodeBuilder.js.map +1 -1
- package/build/executor/Executor03BytecodeBuilder.js +11 -6
- package/build/executor/Executor03BytecodeBuilder.js.map +1 -1
- package/build/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/abi/cables/CablesMainnetRFQ.json +1083 -0
- package/src/dex/balancer-v3/balancer-v3-e2e.test.ts +30 -6
- package/src/dex/balancer-v3/balancer-v3-integration.test.ts +229 -1
- package/src/dex/balancer-v3/balancer-v3-pool.ts +52 -10
- package/src/dex/balancer-v3/config.ts +1 -5
- package/src/dex/balancer-v3/getOnChainState.ts +80 -6
- package/src/dex/balancer-v3/types.ts +1 -0
- package/src/dex/bebop/bebop.ts +1 -1
- package/src/dex/cables/cables-e2e.test.ts +207 -0
- package/src/dex/cables/cables-integration.test.ts +391 -0
- package/src/dex/cables/cables.ts +823 -0
- package/src/dex/cables/config.ts +13 -0
- package/src/dex/cables/constants.ts +33 -0
- package/src/dex/cables/rate-fetcher.ts +212 -0
- package/src/dex/cables/types.ts +113 -0
- package/src/dex/cables/validators.test.ts +151 -0
- package/src/dex/cables/validators.ts +61 -0
- package/src/dex/dexalot/dexalot.ts +1 -0
- package/src/dex/index.ts +2 -0
- package/src/executor/Executor01BytecodeBuilder.ts +15 -11
- package/src/executor/Executor02BytecodeBuilder.ts +13 -9
- package/src/executor/Executor03BytecodeBuilder.ts +16 -9
- package/src/types.ts +1 -0
- 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 = '
|
|
220
|
-
const tokenBAmount: string = '
|
|
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 = '
|
|
237
|
-
const tokenBSymbol: string = '
|
|
236
|
+
const tokenASymbol: string = 'sDAI';
|
|
237
|
+
const tokenBSymbol: string = 'XDAI';
|
|
238
238
|
|
|
239
|
-
const tokenAAmount: string = '
|
|
239
|
+
const tokenAAmount: string = '100000000000000000';
|
|
240
240
|
const tokenBAmount: string = '100000000000000000';
|
|
241
|
-
const nativeTokenAmount = '
|
|
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 {
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
487
|
+
const slicedMultiCallData = _.chunk(
|
|
488
|
+
[...erc4626MultiCallData, ...poolsMultiCallData],
|
|
489
|
+
500,
|
|
490
|
+
);
|
|
473
491
|
|
|
474
492
|
// Make the multicall
|
|
475
|
-
const
|
|
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
|
-
|
|
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.
|
|
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
|
|
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(
|
|
339
|
+
const slicedMultiCallData = _.chunk(
|
|
340
|
+
[...erc4626MultiCallData, ...poolsMultiCallData],
|
|
341
|
+
500,
|
|
342
|
+
);
|
|
287
343
|
|
|
288
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
package/src/dex/bebop/bebop.ts
CHANGED
|
@@ -723,7 +723,7 @@ export class Bebop extends SimpleExchange implements IDex<BebopData> {
|
|
|
723
723
|
}
|
|
724
724
|
}
|
|
725
725
|
|
|
726
|
-
if (side
|
|
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,
|