diff --git a/modules/sor/balancer-sor.integration.test.ts b/modules/sor/balancer-sor.integration.test.ts index 523bcf62..1e495657 100644 --- a/modules/sor/balancer-sor.integration.test.ts +++ b/modules/sor/balancer-sor.integration.test.ts @@ -1,6 +1,6 @@ // yarn vitest balancer-sor.integration.test.ts -import { ExactInQueryOutput, Swap, SwapKind, Token, Address, Path } from '@balancer/sdk'; +import { ExactInQueryOutput, Swap, SwapKind, Token, Address, Path, RemoveLiquidity, RemoveLiquiditySingleTokenExactInInput, RemoveLiquidityConfig, RemoveLiquidityInput, PoolState, RemoveLiquidityKind, BalancerApi, InputAmount } from '@balancer/sdk'; import { PathWithAmount } from './sorV2/lib/path'; import { sorGetPathsWithPools } from './sorV2/lib/static'; @@ -24,8 +24,8 @@ import { sepolia } from 'viem/chains'; * * In order to properly compare SOR quotes vs SDK queries, we need to setup test data from a specific blockNumber. * Although the API does not provide that functionality, we can use subgraph to achieve it. - * These tests run against the 6th testnet deployment and these are their respective subgraphs: - * - data common to all pools: [balancer subgraph](https://api.studio.thegraph.com/proxy/31386/balancer-v3-sepolia-6th/version/latest/graphql) + * These tests run against the 8th testnet deployment and these are their respective subgraphs: + * - data common to all pools: [balancer subgraph](https://api.studio.thegraph.com/query/31386/balancer-v3-sepolia-8th/version/latest/graphql) * - tokens (address, balance, decimals) * - totalShares * - swapFee @@ -33,7 +33,7 @@ import { sepolia } from 'viem/chains'; * - weight * - amp * The only item missing from subgraph is priceRate, which can be fetched from a Tenderly simulation (getPoolTokenRates) - * against the VaultExplorer contract (0x72ebafddc4c7d3eb702c81295d90a8b29f008a03). + * against the VaultExplorer contract (0xe233Bb87383fF2F41290F94fDc9280b831B914C8). * * TODO: improve test data setup by creating a script that fetches all necessary data automatically for a given blockNumber. */ @@ -49,7 +49,7 @@ describe('Balancer SOR Integration Tests', () => { beforeAll(async () => { // start fork to run queries against - ({ rpcUrl } = await startFork(ANVIL_NETWORKS.SEPOLIA, undefined, BigInt(6422808))); + ({ rpcUrl } = await startFork(ANVIL_NETWORKS.SEPOLIA, undefined, BigInt(6800628))); client = createTestClient({ mode: 'anvil', chain: sepolia, @@ -71,25 +71,25 @@ describe('Balancer SOR Integration Tests', () => { const WETH = prismaPoolTokenFactory.build({ address: '0x7b79995e5f793a07bc00c21412e50ecae098e7f9', dynamicData: prismaPoolTokenDynamicDataFactory.build({ - balance: '0.005', + balance: '0.003685129604782161', weight: '0.5', }), }); const BAL = prismaPoolTokenFactory.build({ address: '0xb19382073c7a0addbb56ac6af1808fa49e377b75', dynamicData: prismaPoolTokenDynamicDataFactory.build({ - balance: '5', + balance: '7.177760324210846589', weight: '0.5', }), }); const prismaWeightedPool = prismaPoolFactory.build({ - address: '0x03bf996c7bd45b3386cb41875761d45e27eab284', + address: '0xec1b5ca86c83c7a85392063399e7d2170d502e00', type: 'WEIGHTED', protocolVersion, tokens: [WETH, BAL], dynamicData: prismaPoolDynamicDataFactory.build({ - totalShares: '0.158113883008415798', - swapFee: '0.1', + totalShares: '0.162376133413841997', + swapFee: '0.01', }), }); @@ -134,28 +134,28 @@ describe('Balancer SOR Integration Tests', () => { describe('Stable Pool Path', () => { beforeAll(async () => { // setup mock pool data - const poolAddress = '0x302b75a27e5e157f93c679dd7a25fdfcdbc1473c'; + const poolAddress = '0x9A80F41E59af098ac33650D67496f865bB91a2cE'; const stataUSDC = prismaPoolTokenFactory.build({ - address: '0x8a88124522dbbf1e56352ba3de1d9f78c143751e', + address: '0x8A88124522dbBF1E56352ba3DE1d9F78C143751e', token: { decimals: 6 }, dynamicData: prismaPoolTokenDynamicDataFactory.build({ balance: '500', - priceRate: '1.046992819427282715', + priceRate: '1.101720100012191991', }), }); const stataDAI = prismaPoolTokenFactory.build({ - address: '0xde46e43f46ff74a23a65ebb0580cbe3dfe684a17', + address: '0xDE46e43F46ff74A23a65EBb0580cbe3dFE684a17', token: { decimals: 18 }, dynamicData: prismaPoolTokenDynamicDataFactory.build({ balance: '500', - priceRate: '1.101882285912091736', + priceRate: '1.124839700241484058', }), }); const prismaStablePool = prismaPoolFactory.stable('1000').build({ address: poolAddress, tokens: [stataUSDC, stataDAI], dynamicData: prismaPoolDynamicDataFactory.build({ - totalShares: '1054.451151293881721519', + totalShares: '1094.497798261138107409', swapFee: '0.01', }), }); @@ -209,42 +209,46 @@ describe('Balancer SOR Integration Tests', () => { }); describe('Add/Remove Liquidity Paths', () => { - let stataUSDC: ReturnType; + let stataEthUSDC: ReturnType; let WETH: ReturnType; - let nestedPool: ReturnType; + let boostedPool: ReturnType; let weightedPool: ReturnType; beforeAll(async () => { // setup mock pool data - const nestedPoolAddress = '0x302b75a27e5e157f93c679dd7a25fdfcdbc1473c'; - stataUSDC = prismaPoolTokenFactory.build({ + // Pool 1. this pool is supposed to have a staticAToken and a staticAToken + // for deploy-8 this is 0x9a80f41e59af098ac33650d67496f865bb91a2ce + // this pool is a StablePool (Since 2 yb tokens it is a boosted pool) + const boostedPoolAddress = '0x9a80f41e59af098ac33650d67496f865bb91a2ce'; + stataEthUSDC = prismaPoolTokenFactory.build({ address: '0x8a88124522dbbf1e56352ba3de1d9f78c143751e', token: { decimals: 6 }, dynamicData: prismaPoolTokenDynamicDataFactory.build({ balance: '500', - priceRate: '1.046992819427282715', + priceRate: '1.101721555107859546', }), }); - const DAI = prismaPoolTokenFactory.build({ + const stataEthDAI = prismaPoolTokenFactory.build({ address: '0xde46e43f46ff74a23a65ebb0580cbe3dfe684a17', token: { decimals: 18 }, dynamicData: prismaPoolTokenDynamicDataFactory.build({ balance: '500', - priceRate: '1.101882285912091736', + priceRate: '1.124841965535161789', }), }); - nestedPool = prismaPoolFactory.stable('1000').build({ - address: nestedPoolAddress, - tokens: [stataUSDC, DAI], + boostedPool = prismaPoolFactory.stable('1000').build({ + address: boostedPoolAddress, + tokens: [stataEthUSDC, stataEthDAI], dynamicData: prismaPoolDynamicDataFactory.build({ - totalShares: '1054.451151293881721519', + totalShares: '1094.497798261138107409', swapFee: '0.01', }), }); - const weightedPoolAddress = '0x9e4fd17682b3f15e50c9fddfa08aa12974d0acf5'; - const DAI_USDC_BPT = prismaPoolTokenFactory.build({ - address: '0x302b75a27e5e157f93c679dd7a25fdfcdbc1473c', + // Pool 2. this pool is supposed to have the BPT of pool 1 and WETH. + const weightedPoolAddress = '0xcdcada7a6472ab90b6ea4494d966b00b9933f079'; + const stataEthUSDC_stataEthDAI_BPT = prismaPoolTokenFactory.build({ + address: '0x9a80f41e59af098ac33650d67496f865bb91a2ce', token: { decimals: 18 }, dynamicData: prismaPoolTokenDynamicDataFactory.build({ balance: '100', @@ -259,7 +263,7 @@ describe('Balancer SOR Integration Tests', () => { }); weightedPool = prismaPoolFactory.build({ address: weightedPoolAddress, - tokens: [DAI_USDC_BPT, WETH], + tokens: [stataEthUSDC_stataEthDAI_BPT, WETH], dynamicData: prismaPoolDynamicDataFactory.build({ totalShares: '1.732050807568842627', swapFee: '0.01', @@ -267,14 +271,14 @@ describe('Balancer SOR Integration Tests', () => { }); }); - // usdc [add] bpt [swap] weth + // statA [add] bpt [swap] weth describe('Add Liquidity Path', () => { beforeAll(async () => { // get SOR paths const tIn = new Token( - parseFloat(chainToIdMap[stataUSDC.token.chain]), - stataUSDC.address as Address, - stataUSDC.token.decimals, + parseFloat(chainToIdMap[stataEthUSDC.token.chain]), + stataEthUSDC.address as Address, + stataEthUSDC.token.decimals, ); const tOut = new Token( parseFloat(chainToIdMap[WETH.token.chain]), @@ -287,7 +291,7 @@ describe('Balancer SOR Integration Tests', () => { tOut, SwapKind.GivenIn, amountIn, - [nestedPool, weightedPool], + [boostedPool, weightedPool], protocolVersion, )) as PathWithAmount[]; @@ -328,9 +332,9 @@ describe('Balancer SOR Integration Tests', () => { WETH.token.decimals, ); const tOut = new Token( - parseFloat(chainToIdMap[stataUSDC.token.chain]), - stataUSDC.address as Address, - stataUSDC.token.decimals, + parseFloat(chainToIdMap[stataEthUSDC.token.chain]), + stataEthUSDC.address as Address, + stataEthUSDC.token.decimals, ); const amountIn = parseEther('0.0001'); paths = (await sorGetPathsWithPools( @@ -338,7 +342,7 @@ describe('Balancer SOR Integration Tests', () => { tOut, SwapKind.GivenIn, amountIn, - [nestedPool, weightedPool], + [boostedPool, weightedPool], protocolVersion, )) as PathWithAmount[]; @@ -373,28 +377,28 @@ describe('Balancer SOR Integration Tests', () => { describe('Buffer Pool Path', () => { beforeAll(async () => { // setup mock pool data - const poolAddress = '0x302b75a27e5e157f93c679dd7a25fdfcdbc1473c'; + const poolAddress = '0x9a80f41e59af098ac33650d67496f865bb91a2ce'; const stataUSDC = prismaPoolTokenFactory.build({ address: '0x8a88124522dbbf1e56352ba3de1d9f78c143751e', - token: { decimals: 6, underlyingTokenAddress: '0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8' }, + token: { decimals: 6, underlyingTokenAddress: '0x94a9d9ac8a22534e3faca9f4e7f2e2cf85d5e4c8' }, // getBufferAsset dynamicData: prismaPoolTokenDynamicDataFactory.build({ balance: '500', - priceRate: '1.046992819427282715', + priceRate: '1.094921710475361768', }), }); const stataDAI = prismaPoolTokenFactory.build({ address: '0xde46e43f46ff74a23a65ebb0580cbe3dfe684a17', - token: { decimals: 18, underlyingTokenAddress: '0xff34b3d4aee8ddcd6f9afffb6fe49bd371b8a357' }, + token: { decimals: 18, underlyingTokenAddress: '0xff34b3d4aee8ddcd6f9afffb6fe49bd371b8a357' }, // getBufferAsset dynamicData: prismaPoolTokenDynamicDataFactory.build({ balance: '500', - priceRate: '1.101882285912091736', + priceRate: '1.114418956516329020', }), }); const prismaStablePool = prismaPoolFactory.stable('1000').build({ address: poolAddress, tokens: [stataUSDC, stataDAI], dynamicData: prismaPoolDynamicDataFactory.build({ - totalShares: '1054.451151293881721519', + totalShares: '1094.497798261138107409', swapFee: '0.01', }), }); @@ -517,27 +521,27 @@ describe('Balancer SOR Integration Tests', () => { }); // this pool has an exitFee hook prismaWeightedPool = prismaPoolFactory.build({ - address: '0xc7436329da34B54fAD1400f400931751E1D06Cf8', + address: '0x8fc07bcf9b88ace84c7523248dc4a85f638c9536', type: 'WEIGHTED', protocolVersion, tokens: [WETH, BAL], dynamicData: prismaPoolDynamicDataFactory.build({ totalShares: '0.158113883008415798', - swapFee: '0.1', + swapFee: '0.01', }), hook: exitFeeHook, }); prismaStablePool = prismaPoolFactory.stable('1000').build({ - address: '0x302b75a27e5e157f93c679dd7a25fdfcdbc1473c', + address: '0x9a80f41e59af098ac33650d67496f865bb91a2ce', tokens: [stataUSDC, stataDAI], dynamicData: prismaPoolDynamicDataFactory.build({ - totalShares: '1054.451151293881721519', + totalShares: '1094.497798261138107409', swapFee: '0.01', }), hook: exitFeeHook, }); }) - test.only('SOR quote should match swap query with hooks', async () => { + test.skip('SOR quote should match swap query with hooks', async () => { // This test does not trigger the ExitFeeHook, as the ExitFee is // applied on RemoveLiquidity operations const tIn = new Token( @@ -550,13 +554,13 @@ describe('Balancer SOR Integration Tests', () => { WETH.address as Address, WETH.token.decimals, ); - const amountIn = BigInt(1000e6); + const amountIn = BigInt(1e18); paths = (await sorGetPathsWithPools( tIn, tOut, SwapKind.GivenIn, amountIn, - [prismaStablePool, prismaWeightedPool], + [prismaStablePool, prismaWeightedPool], //both pools have hooks. protocolVersion, )) as PathWithAmount[]; @@ -585,7 +589,7 @@ describe('Balancer SOR Integration Tests', () => { }); test.skip('SOR quote should match swap query with hook logic used', async () => { // This test applies the hook logic, as a BPT -> Token Swap will trigger - // a RemoveLiquidity operation. + // a RemoveLiquidity operation. const tIn = new Token( parseFloat('11155111'), prismaWeightedPool.address as Address, @@ -596,13 +600,13 @@ describe('Balancer SOR Integration Tests', () => { WETH.address as Address, WETH.token.decimals, ); - const amountIn = BigInt(1000e6); + const amountIn = BigInt(1e18); paths = (await sorGetPathsWithPools( tIn, tOut, SwapKind.GivenIn, amountIn, - [prismaStablePool, prismaWeightedPool], + [prismaWeightedPool], protocolVersion, )) as PathWithAmount[]; @@ -623,11 +627,6 @@ describe('Balancer SOR Integration Tests', () => { paths: swapPaths, swapKind: SwapKind.GivenIn, }); - - const returnAmountSOR = getOutputAmount(paths); - const queryOutput = await sdkSwap.query(rpcUrl); - const returnAmountQuery = (queryOutput as ExactInQueryOutput).expectedAmountOut; - expect(returnAmountQuery.amount).toEqual(returnAmountSOR.amount); }); }); afterAll(async () => {