From 8e71b8b658749cd67eb6bc55793260f6a773daf4 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 31 Jan 2025 10:09:56 +0000 Subject: [PATCH 1/6] feat: Update API queries to fetch nested ERC4626 addresses. --- src/dex/balancer-v3/balancer-v3.ts | 15 +++++++++++++-- src/dex/balancer-v3/getPoolsApi.ts | 5 +++++ src/dex/balancer-v3/getTopPoolsApi.ts | 2 ++ src/dex/balancer-v3/types.ts | 13 +++++++++---- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3.ts b/src/dex/balancer-v3/balancer-v3.ts index fb1ecfbb3..dd9092b7b 100644 --- a/src/dex/balancer-v3/balancer-v3.ts +++ b/src/dex/balancer-v3/balancer-v3.ts @@ -177,7 +177,9 @@ export class BalancerV3 extends SimpleExchange implements IDex { hasTokens(pool: DeepReadonly, tokens: string[]): boolean { return tokens.every( token => - pool.tokens.includes(token) || pool.tokensUnderlying.includes(token), + pool.tokens.includes(token) || + pool.tokensUnderlying.includes(token) || + pool.tokensNestedERC4626Underlying.includes(token), ); } @@ -586,11 +588,20 @@ export class BalancerV3 extends SimpleExchange implements IDex { .filter(t => !!t) .filter(t => t?.address !== tokenAddress) as Token[]; + const nestedUnderlyingTokens = pool.poolTokens + .map(t => ({ + address: t.underlyingToken?.underlyingTokenAddress, + decimals: t.underlyingToken?.decimals, + })) + .filter(item => !!item.address) as Token[]; + return { exchange: this.dexKey, address: pool.address, liquidityUSD: parseFloat(pool.dynamicData.totalLiquidity), - connectorTokens: tokens.concat(underlyingTokens), + connectorTokens: tokens + .concat(underlyingTokens) + .concat(nestedUnderlyingTokens), }; }); } diff --git a/src/dex/balancer-v3/getPoolsApi.ts b/src/dex/balancer-v3/getPoolsApi.ts index 4056bf802..ed059421f 100644 --- a/src/dex/balancer-v3/getPoolsApi.ts +++ b/src/dex/balancer-v3/getPoolsApi.ts @@ -14,6 +14,7 @@ interface PoolToken { isErc4626: boolean; underlyingToken: { address: string; + underlyingTokenAddress: string | null; } | null; } @@ -67,6 +68,7 @@ function createQuery( isErc4626 underlyingToken { address + underlyingTokenAddress } } } @@ -82,6 +84,9 @@ function toImmutablePoolStateMap(pools: Pool[]): ImmutablePoolStateMap { tokensUnderlying: pool.poolTokens.map(t => t.underlyingToken ? t.underlyingToken.address : null, ), + tokensNestedERC4626Underlying: pool.poolTokens.map(t => + t.underlyingToken ? t.underlyingToken.underlyingTokenAddress : null, + ), weights: pool.poolTokens.map(t => t.weight ? parseUnits(t.weight, 18).toBigInt() : 0n, ), diff --git a/src/dex/balancer-v3/getTopPoolsApi.ts b/src/dex/balancer-v3/getTopPoolsApi.ts index 26db2d0ba..002dd0bba 100644 --- a/src/dex/balancer-v3/getTopPoolsApi.ts +++ b/src/dex/balancer-v3/getTopPoolsApi.ts @@ -7,6 +7,7 @@ interface PoolToken { underlyingToken?: { address: string; decimals: number; + underlyingTokenAddress: string; }; } @@ -63,6 +64,7 @@ function createQuery( underlyingToken { address decimals + underlyingTokenAddress } } dynamicData { diff --git a/src/dex/balancer-v3/types.ts b/src/dex/balancer-v3/types.ts index f573c48dc..bc3e7d8c0 100644 --- a/src/dex/balancer-v3/types.ts +++ b/src/dex/balancer-v3/types.ts @@ -9,6 +9,7 @@ export type CommonImmutablePoolState = { tokens: string[]; // For boosted pools underlying is the unwrapped token, e.g. USDC/DAI tokensUnderlying: (string | null)[]; + tokensNestedERC4626Underlying: (string | null)[]; weights: bigint[]; // TODO re-introduce this once added to API // scalingFactors: bigint[]; @@ -19,6 +20,7 @@ export type CommonImmutablePoolState = { export interface CommonMutableState { tokenRates: bigint[]; erc4626Rates: (bigint | null)[]; + erc4626NestedRates: (bigint | null)[]; balancesLiveScaled18: bigint[]; swapFee: bigint; aggregateSwapFee: bigint; @@ -78,10 +80,13 @@ export type DexParams = { balancerBatchRouterAddress: string; }; +export enum TokenType { + MainToken = 1, + ERC4626, + ERC4626Nested, +} + export type TokenInfo = { - isBoosted: boolean; - underlyingToken: string | null; - mainToken: string; index: number; - rate: bigint; + type: TokenType; }; From 7c00f5df809417ddf4cd457f3636b33693b755bc Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 31 Jan 2025 10:11:19 +0000 Subject: [PATCH 2/6] feat: Update ERC4626 onchain rate call to include nested. --- src/dex/balancer-v3/getOnChainState.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/dex/balancer-v3/getOnChainState.ts b/src/dex/balancer-v3/getOnChainState.ts index 025936621..4c5ee7639 100644 --- a/src/dex/balancer-v3/getOnChainState.ts +++ b/src/dex/balancer-v3/getOnChainState.ts @@ -86,7 +86,7 @@ const poolOnChain: Record< poolAddress: string, data: any, startIndex: number, - ): Omit => { + ): Omit => { const resultTokenRates = decodeThrowError( contractInterface, 'getPoolTokenRates', @@ -267,8 +267,17 @@ export function getErc4626MultiCallData( // We want to query rate for each unique ERC4626 token const uniqueErc4626Tokens = Array.from( new Set( - Object.values(immutablePoolStateMap).flatMap(pool => - pool.tokens.filter((_, index) => pool.tokensUnderlying[index] !== null), + Object.values(immutablePoolStateMap).flatMap( + pool => + [ + // Get tokens with corresponding non-null tokensUnderlying + ...pool.tokens.filter( + (_, index) => pool.tokensUnderlying[index] !== null, + ), + ...pool.tokensUnderlying.filter( + (_, index) => pool.tokensNestedERC4626Underlying[index] !== null, + ), + ] as string[], ), ), ); @@ -392,6 +401,10 @@ export async function getOnChainState( if (!tokensWithRates[t]) return null; return tokensWithRates[t]; }), + erc4626NestedRates: pool.tokensUnderlying.map(t => { + if (!t || !tokensWithRates[t]) return null; + return tokensWithRates[t]; + }), }, ]; }), From da6416206b02f1792fa51014ff7eace27486c09e Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 31 Jan 2025 10:12:45 +0000 Subject: [PATCH 3/6] feat: Handle extra wrap/unwrap steps for nested ERC4626. --- src/dex/balancer-v3/balancer-v3-pool.ts | 241 ++++++++++++++++-------- 1 file changed, 161 insertions(+), 80 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-pool.ts b/src/dex/balancer-v3/balancer-v3-pool.ts index 783520f7b..c51f4f855 100644 --- a/src/dex/balancer-v3/balancer-v3-pool.ts +++ b/src/dex/balancer-v3/balancer-v3-pool.ts @@ -11,6 +11,7 @@ import { StableMutableState, Step, TokenInfo, + TokenType, } from './types'; import { getPoolsApi } from './getPoolsApi'; import vaultExtensionAbi_V3 from '../../abi/balancer-v3/vault-extension.json'; @@ -543,11 +544,8 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { ); if (tokenIndex !== -1) { return { - isBoosted: false, - mainToken: tokenAddress, - underlyingToken: null, index: tokenIndex, - rate: poolState.tokenRates[tokenIndex], + type: TokenType.MainToken, }; } @@ -558,18 +556,23 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { address && address.toLowerCase() === tokenAddress.toLowerCase(), ); if (tokenIndex !== -1) { - if (poolState.erc4626Rates[tokenIndex] === null) { - this.logger.error( - `missing erc4626 token rate ${poolState.tokens[tokenIndex]}`, - ); - return null; - } return { - isBoosted: true, - mainToken: poolState.tokens[tokenIndex], - underlyingToken: tokenAddress, index: tokenIndex, - rate: poolState.erc4626Rates[tokenIndex]!, + type: TokenType.ERC4626, + }; + } + } + + // Check in nested underlying tokens if available + if (poolState.tokensNestedERC4626Underlying) { + tokenIndex = poolState.tokensNestedERC4626Underlying.findIndex( + address => + address && address.toLowerCase() === tokenAddress.toLowerCase(), + ); + if (tokenIndex !== -1) { + return { + index: tokenIndex, + type: TokenType.ERC4626Nested, }; } } @@ -593,104 +596,182 @@ export class BalancerV3EventPool extends StatefulEventSubscriber { * https://docs-v3.balancer.fi/concepts/vault/buffer.html */ getSteps(pool: PoolState, tokenIn: TokenInfo, tokenOut: TokenInfo): Step[] { - if (tokenIn.isBoosted && tokenOut.isBoosted) { - return [ - // Wrap tokenIn underlying to main token - this.getWrapStep(tokenIn), - // Swap main > main - this.getSwapStep(pool, tokenIn, tokenOut), - // Unwrap tokenOut main to underlying token - this.getUnwrapStep(tokenOut), - ]; - } else if (tokenIn.isBoosted) { - if ( - tokenIn.mainToken.toLowerCase() === tokenOut.mainToken.toLowerCase() - ) { - // wrap, token > erc4626 - // tokenIn is boosted, e.g. isn't pool token and must be wrapped - return [this.getWrapStep(tokenIn)]; + // This is a single buffer wrap/unwrap + if (tokenIn.index === tokenOut.index) { + return this.singleBufferStep(pool, tokenIn, tokenOut); + } + + // Create steps based on token types + const steps: Step[] = []; + + // Handle input token wrapping if needed + if (this.needsBuffer(tokenIn)) { + if (tokenIn.type === TokenType.ERC4626Nested) { + steps.push(this.getWrapStepNested(pool, tokenIn)); } - return [ - // Wrap tokenIn underlying to main token - this.getWrapStep(tokenIn), - // Swap main > main - this.getSwapStep(pool, tokenIn, tokenOut), - ]; - } else if (tokenOut.isBoosted) { - if ( - tokenIn.mainToken.toLowerCase() === tokenOut.mainToken.toLowerCase() - ) { - // unwrap, stata > token - // token out is boosted, e.g. isn't pool token - return [this.getUnwrapStep(tokenOut)]; + steps.push(this.getWrapStep(pool, tokenIn)); + } + + // Add main swap step + steps.push(this.getSwapStep(pool, tokenIn, tokenOut)); + + // Handle output token unwrapping if needed + if (this.needsBuffer(tokenOut)) { + steps.push(this.getUnwrapStep(pool, tokenOut)); + if (tokenOut.type === TokenType.ERC4626Nested) { + steps.push(this.getUnwrapStepNested(pool, tokenOut)); } - return [ - // Swap main > main - this.getSwapStep(pool, tokenIn, tokenOut), - // Unwrap tokenOut main to underlying token - this.getUnwrapStep(tokenOut), - ]; - } else { - return [ - // Swap main > main - this.getSwapStep(pool, tokenIn, tokenOut), - ]; } + + return steps; + } + + private singleBufferStep( + pool: PoolState, + tokenIn: TokenInfo, + tokenOut: TokenInfo, + ): Step[] { + if (tokenIn.type === TokenType.ERC4626) { + // wrap, token > erc4626 + // tokenIn is boosted, e.g. isn't pool token and must be wrapped + return [this.getWrapStep(pool, tokenIn)]; + } + if (tokenOut.type === TokenType.ERC4626) { + // unwrap, erc4626 > token + // tokenOut is boosted, e.g. isn't pool token and must be unwrapped + return [this.getUnwrapStep(pool, tokenOut)]; + } + throw new Error(`Error get step with same token index`); + } + + private needsBuffer(token: TokenInfo): boolean { + return ( + token.type === TokenType.ERC4626 || token.type === TokenType.ERC4626Nested + ); } - getWrapStep(token: TokenInfo): Step { - if (!token.underlyingToken) + private validateUnderlyingToken(pool: PoolState, tokenIndex: number): void { + if (!pool.tokensUnderlying[tokenIndex] || !pool.erc4626Rates[tokenIndex]) { throw new Error( - `Buffer wrap: token has no underlying. ${token.mainToken}`, + `Underlying Token Error: token at index ${tokenIndex}. ${pool.tokensUnderlying[tokenIndex]} ${pool.erc4626Rates[tokenIndex]}`, ); - // Vault expects pool to be the ERC4626 wrapped token, e.g. aUSDC + } + } + + private validateNestedUnderlyingToken( + pool: PoolState, + tokenIndex: number, + ): void { + if ( + !pool.tokensUnderlying[tokenIndex] || + !pool.tokensNestedERC4626Underlying[tokenIndex] || + !pool.erc4626NestedRates[tokenIndex] + ) { + throw new Error( + `NestedUnderlying Token Error: token at index ${tokenIndex}. ${pool.tokensUnderlying[tokenIndex]} ${pool.tokensNestedERC4626Underlying[tokenIndex]} ${pool.erc4626NestedRates[tokenIndex]}`, + ); + } + } + + getWrapStepNested(pool: PoolState, token: TokenInfo): Step { + this.validateNestedUnderlyingToken(pool, token.index); + + const underlyingToken = pool.tokensUnderlying[token.index] as string; + const nestedUnderlyingToken = pool.tokensNestedERC4626Underlying[ + token.index + ] as string; + return { - pool: token.mainToken, + pool: underlyingToken, isBuffer: true, swapInput: { - tokenIn: token.underlyingToken, - tokenOut: token.mainToken, + tokenIn: nestedUnderlyingToken, + tokenOut: underlyingToken, }, poolState: { poolType: 'Buffer', - rate: token.rate, - poolAddress: token.mainToken, - tokens: [token.mainToken, token.underlyingToken], // staticToken & underlying + rate: pool.erc4626NestedRates[token.index] as bigint, + poolAddress: underlyingToken, + tokens: [nestedUnderlyingToken, underlyingToken], }, }; } - getUnwrapStep(token: TokenInfo): Step { - if (!token.underlyingToken) - throw new Error( - `Buffer unwrap: token has no underlying. ${token.mainToken}`, - ); - // Vault expects pool to be the ERC4626 wrapped token, e.g. aUSDC + getWrapStep(pool: PoolState, token: TokenInfo): Step { + this.validateUnderlyingToken(pool, token.index); + + const wrappedToken = pool.tokens[token.index]; + const underlyingToken = pool.tokensUnderlying[token.index] as string; + + return { + pool: wrappedToken, + isBuffer: true, + swapInput: { + tokenIn: underlyingToken, + tokenOut: wrappedToken, + }, + poolState: { + poolType: 'Buffer', + rate: pool.erc4626Rates[token.index] as bigint, + poolAddress: wrappedToken, + tokens: [wrappedToken, underlyingToken], + }, + }; + } + + getUnwrapStepNested(pool: PoolState, token: TokenInfo): Step { + this.validateNestedUnderlyingToken(pool, token.index); + + const underlyingToken = pool.tokensUnderlying[token.index] as string; + const nestedUnderlyingToken = pool.tokensNestedERC4626Underlying[ + token.index + ] as string; + + return { + pool: underlyingToken, + isBuffer: true, + swapInput: { + tokenIn: underlyingToken, + tokenOut: nestedUnderlyingToken, + }, + poolState: { + poolType: 'Buffer', + rate: pool.erc4626NestedRates[token.index] as bigint, + poolAddress: underlyingToken, + tokens: [nestedUnderlyingToken, underlyingToken], + }, + }; + } + + getUnwrapStep(pool: PoolState, token: TokenInfo): Step { + this.validateUnderlyingToken(pool, token.index); + + const wrappedToken = pool.tokens[token.index]; + const underlyingToken = pool.tokensUnderlying[token.index] as string; + return { - pool: token.mainToken, + pool: wrappedToken, isBuffer: true, swapInput: { - tokenIn: token.mainToken, - tokenOut: token.underlyingToken, + tokenIn: wrappedToken, + tokenOut: underlyingToken, }, poolState: { poolType: 'Buffer', - // TODO: for ERC4626 fetch the wrap/unwrap rate - rate: token.rate, - poolAddress: token.mainToken, - tokens: [token.mainToken, token.underlyingToken], // staticToken & underlying + rate: pool.erc4626Rates[token.index] as bigint, + poolAddress: wrappedToken, + tokens: [wrappedToken, underlyingToken], }, }; } getSwapStep(pool: PoolState, tokenIn: TokenInfo, tokenOut: TokenInfo): Step { - // A normal swap between two tokens in a pool return { pool: pool.poolAddress, isBuffer: false, swapInput: { - tokenIn: tokenIn.mainToken, - tokenOut: tokenOut.mainToken, + tokenIn: pool.tokens[tokenIn.index], + tokenOut: pool.tokens[tokenOut.index], }, poolState: pool, }; From c86a24b8913f331643d9479556064a7ee7bf7c8e Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 31 Jan 2025 10:13:45 +0000 Subject: [PATCH 4/6] feat: Update getGasCost to handle extra nested buffer steps. --- src/dex/balancer-v3/getGasCost.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/dex/balancer-v3/getGasCost.ts b/src/dex/balancer-v3/getGasCost.ts index 1dc97b786..455d1646f 100644 --- a/src/dex/balancer-v3/getGasCost.ts +++ b/src/dex/balancer-v3/getGasCost.ts @@ -14,15 +14,7 @@ const PARTIAL_BOOSTED_SWAP_GAS_COST = 259815; const BUFFER_WRAP_UNWRAP_GAS_COST = 155921; export function getGasCost(steps: Step[]): number { - if (steps.length === 2) { - // Partial boosted/buffer swap: - // token[wrap]wrappedToken[swap]wrappedToken or - // wrappedToken[swap]wrappedToken[unwrap]token - return PARTIAL_BOOSTED_SWAP_GAS_COST; - } else if (steps.length === 3) { - // Full boosted/buffer swap: token[wrap]wrappedToken[swap]wrappedToken[unwrap]token - return FULL_BOOSTED_SWAP_GAS_COST; - } else { + if (steps.length === 1) { switch (steps[0].poolState.poolType) { case 'WEIGHTED': return WEIGHTED_GAS_COST; @@ -33,5 +25,18 @@ export function getGasCost(steps: Step[]): number { default: return WEIGHTED_GAS_COST; } + } else if (steps.length === 2) { + // Partial boosted/buffer swap: + // token[wrap]wrappedToken[swap]wrappedToken or + // wrappedToken[swap]wrappedToken[unwrap]token + return PARTIAL_BOOSTED_SWAP_GAS_COST; + } else if (steps.length === 3) { + // Full boosted/buffer swap: token[wrap]wrappedToken[swap]wrappedToken[unwrap]token + return FULL_BOOSTED_SWAP_GAS_COST; + } else { + return ( + FULL_BOOSTED_SWAP_GAS_COST + + (steps.length - 3) * BUFFER_WRAP_UNWRAP_GAS_COST + ); } } From f723e275d84867e161c5c00dfe48dec9566c29f5 Mon Sep 17 00:00:00 2001 From: johngrantuk Date: Fri, 31 Jan 2025 10:14:37 +0000 Subject: [PATCH 5/6] test: Add tests for mainnet USDC<>USDL pool which has nested ERC4626. --- .../balancer-v3-integration.test.ts | 137 +++++++++++++++++- tests/constants-e2e.ts | 15 ++ 2 files changed, 150 insertions(+), 2 deletions(-) diff --git a/src/dex/balancer-v3/balancer-v3-integration.test.ts b/src/dex/balancer-v3/balancer-v3-integration.test.ts index 0a2b71014..ca675f41a 100644 --- a/src/dex/balancer-v3/balancer-v3-integration.test.ts +++ b/src/dex/balancer-v3/balancer-v3-integration.test.ts @@ -205,10 +205,29 @@ async function checkOnChainPricingNonMulti( price, amounts, ); - expect(price.prices).toEqual(expectedPrices); + price.prices.forEach((p, i) => { + expect(areBigIntsWithinPercent(p, expectedPrices[i], 0.001)).toEqual( + true, + ); + }); } } +// Helper function to check if two BigInts are within a given percentage +export function areBigIntsWithinPercent( + value1: bigint, + value2: bigint, + percent: number, +): boolean { + if (percent < 0) { + throw new Error('Percent must be non-negative'); + } + const difference = value1 > value2 ? value1 - value2 : value2 - value1; + const percentFactor = BigInt(Math.floor(percent * 1e8)); + const tolerance = (value2 * percentFactor) / BigInt(1e10); + return difference <= tolerance; +} + async function testPricingOnNetwork( balancerV3: BalancerV3, network: Network, @@ -901,7 +920,7 @@ describe('BalancerV3', function () { Note for maths: Instead of manually adding support for each ERC4626 implementation (e.g. stata with Ray maths) we always use an 18 decimal scaled rate and do 18 decimal maths to convert. We may end up loosing 100% accuracy but thats deemed acceptable. */ - describe.only('Buffer wrap 6decimal>18decimal', () => { + describe('Buffer wrap 6decimal>18decimal', () => { const dexHelper = new DummyDexHelper(network); const tokens = Tokens[network]; @@ -1059,6 +1078,120 @@ describe('BalancerV3', function () { }); }); }); + + describe('Nested ERC4626', () => { + /* + Pool has csUSDL which has nested ERC4626. USDL swaps can be enabled by simply adding extra buffer step. + https://balancer.fi/pools/ethereum/v3/0x10a04efba5b880e169920fd4348527c64fb29d4d + csUSDC: 0x7204b7dbf9412567835633b6f00c3edc3a8d6330 + - USDC: 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 + csUSDL: 0xbeefc011e94f43b8b7b455ebab290c7ab4e216f1 + - wUSDL: 0x7751e2f4b8ae93ef6b79d86419d42fe3295a4559 + - USDL: 0xbdc7c08592ee4aa51d06c27ee23d5087d65adbcd + */ + describe('Nested underlying as token in', () => { + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'USDL'; + const destTokenSymbol = 'USDC'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; + + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + ); + }); + + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + ); + }); + }); + describe('Nested underlying as token out', () => { + const dexHelper = new DummyDexHelper(network); + + const tokens = Tokens[network]; + const srcTokenSymbol = 'USDC'; + const destTokenSymbol = 'USDL'; + + const amountsForSell = [ + 0n, + 1n * BI_POWS[tokens[srcTokenSymbol].decimals], + ]; + + const amountsForBuy = [ + 0n, + 1n * BI_POWS[tokens[destTokenSymbol].decimals], + ]; + + beforeAll(async () => { + blockNumber = await dexHelper.web3Provider.eth.getBlockNumber(); + balancerV3 = new BalancerV3(network, dexKey, dexHelper); + if (balancerV3.initializePricing) { + await balancerV3.initializePricing(blockNumber); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.SELL, + amountsForSell, + ); + }); + + it('getPoolIdentifiers and getPricesVolume BUY', async function () { + await testPricingOnNetwork( + balancerV3, + network, + dexKey, + blockNumber, + srcTokenSymbol, + destTokenSymbol, + SwapSide.BUY, + amountsForBuy, + ); + }); + }); + }); }); }); diff --git a/tests/constants-e2e.ts b/tests/constants-e2e.ts index 1f6c30739..ad549b093 100644 --- a/tests/constants-e2e.ts +++ b/tests/constants-e2e.ts @@ -581,6 +581,21 @@ export const Tokens: { decimals: 6, symbol: 'USUALM', }, + USDL: { + address: '0xbdC7c08592Ee4aa51D06C27Ee23D5087D65aDbcD', + decimals: 18, + symbol: 'USDL', + }, + csUSDL: { + address: '0xbEeFc011e94f43b8B7b455eBaB290C7Ab4E216f1', + decimals: 18, + symbol: 'csUSDL', + }, + csUSDC: { + address: '0x7204b7dbf9412567835633b6f00c3edc3a8d6330', + decimals: 18, + symbol: 'csUSDC', + }, }, [Network.POLYGON]: { jGBP: { From f5482f318cf64509d2907c6144106573a4a3ecd5 Mon Sep 17 00:00:00 2001 From: Alexander Burkut Date: Fri, 31 Jan 2025 15:30:21 +0300 Subject: [PATCH 6/6] 4.0.24-bal-v3-nested-erc4626.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f786835ef..0d2045bf5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@paraswap/dex-lib", - "version": "4.0.23", + "version": "4.0.24-bal-v3-nested-erc4626.0", "main": "build/index.js", "types": "build/index.d.ts", "repository": "https://github.com/paraswap/paraswap-dex-lib",