diff --git a/balancer-js/src/modules/pricing/priceImpact.compare.spec.ts b/balancer-js/src/modules/pricing/priceImpact.compare.spec.ts index cc7c42e0a..78dc9e972 100644 --- a/balancer-js/src/modules/pricing/priceImpact.compare.spec.ts +++ b/balancer-js/src/modules/pricing/priceImpact.compare.spec.ts @@ -54,272 +54,272 @@ describe('Price impact comparison tests', async () => { pool = await testPoolHelper.getPool(); }); - context('Price impact comparison tests', async () => { - // Setup chain - beforeEach(async function () { - const balances = pool.tokens.map((token) => - parseFixed(initialBalance, token.decimals).toString() - ); - await forkSetup( - signer, - pool.tokensList, - slots, - balances, - jsonRpcUrl as string, - blockNumber - ); - pool = await testPoolHelper.getPool(); // update the pool after the forkSetup; - }); + // Setup chain + beforeEach(async function () { + const balances = pool.tokens.map((token) => + parseFixed(initialBalance, token.decimals).toString() + ); + await forkSetup( + signer, + pool.tokensList, + slots, + balances, + jsonRpcUrl as string, + blockNumber + ); + pool = await testPoolHelper.getPool(); // update the pool after the forkSetup; + }); - context('swap', async () => { - const assetInIndex = 0; - const assetOutIndex = 1; - let swapAmount: BigNumber; + context('swap', async () => { + const assetInIndex = 1; + const assetOutIndex = 0; + let swapAmount: BigNumber; - before(() => { - swapAmount = parseFixed('2', pool.tokens[assetInIndex].decimals); // 200 WETH - }); + before(() => { + swapAmount = parseFixed('200', pool.tokens[assetInIndex].decimals); // 200 WETH + }); - it('should calculate price impact - spot price method', async () => { - const swapAmounts = await queryBatchSwap( - vault, - SwapType.SwapExactIn, - [ - { - poolId: pool.id, - assetInIndex, - assetOutIndex, - amount: swapAmount.toString(), - userData: '0x', - }, - ], - pool.tokensList - ); + it('should calculate price impact - spot price method', async () => { + const swapAmounts = await queryBatchSwap( + vault, + SwapType.SwapExactIn, + [ + { + poolId: pool.id, + assetInIndex, + assetOutIndex, + amount: swapAmount.toString(), + userData: '0x', + }, + ], + pool.tokensList + ); - const amountIn = parseFloat( + const amountIn = parseFloat( + formatFixed( + swapAmounts[assetInIndex], + pool.tokens[assetInIndex].decimals + ) + ); + + const amountOut = + -1 * + parseFloat( formatFixed( - swapAmounts[assetInIndex], - pool.tokens[assetInIndex].decimals + swapAmounts[assetOutIndex], + pool.tokens[assetOutIndex].decimals ) ); - console.log(`amountIn: ${amountIn}`); - - const amountOut = - -1 * - parseFloat( - formatFixed( - swapAmounts[assetOutIndex], - pool.tokens[assetOutIndex].decimals - ) - ); - console.log(`amountOut: ${amountOut}`); - - const effectivePrice = amountIn / amountOut; - console.log(`effectivePrice: ${effectivePrice}`); - - const subgraphPool: SubgraphPoolBase = pool as SubgraphPoolBase; - - const spotPrice = await pricing.getSpotPrice( - pool.tokensList[assetInIndex], - pool.tokensList[assetOutIndex], - [subgraphPool] - ); - console.log(`spotPrice: ${spotPrice}`); - const priceRatio = parseFloat(spotPrice) / effectivePrice; - const priceImpact = 1 - priceRatio; - console.log(`priceImpact: ${priceImpact}`); - }); + const effectivePrice = amountIn / amountOut; - it('should calculate price impact - spot price method', async () => { - const swapAmounts = await queryBatchSwap( - vault, - SwapType.SwapExactIn, - [ - { - poolId: pool.id, - assetInIndex, - assetOutIndex, - amount: swapAmount.toString(), - userData: '0x', - }, - { - poolId: pool.id, - assetInIndex: assetOutIndex, - assetOutIndex: assetInIndex, - amount: '0', - userData: '0x', - }, - ], - pool.tokensList - ); - const diff = parseFloat( - formatFixed( - swapAmounts[assetInIndex], - pool.tokens[assetInIndex].decimals - ) - ); - console.log(`diff lost by price impact: ${diff}`); + const subgraphPool: SubgraphPoolBase = pool as SubgraphPoolBase; - const initialA = parseFloat( - formatFixed(swapAmount, pool.tokens[assetInIndex].decimals) - ); - console.log(`initialA: ${initialA}`); + const spotPrice = await pricing.getSpotPrice( + pool.tokensList[assetInIndex], + pool.tokensList[assetOutIndex], + [subgraphPool] + ); - const priceImpactABA = diff / initialA / 2; - console.log(`priceImpactABA : ${priceImpactABA}`); - }); + const priceRatio = parseFloat(spotPrice) / effectivePrice; + const priceImpact = 1 - priceRatio; + console.log(`priceImpactSpotPrice: ${priceImpact}`); }); - context('single token join', async () => { - let tokenIn: PoolToken; - let amountIn: BigNumber; + it('should calculate price impact - ABA method', async () => { + const swapAtoB = await queryBatchSwap( + vault, + SwapType.SwapExactIn, + [ + { + poolId: pool.id, + assetInIndex, + assetOutIndex, + amount: swapAmount.toString(), + userData: '0x', + }, + ], + pool.tokensList + ); + const B = BigNumber.from(-1).mul(swapAtoB[assetOutIndex]); + + const swapBtoA = await queryBatchSwap( + vault, + SwapType.SwapExactIn, + [ + { + poolId: pool.id, + assetInIndex: assetOutIndex, + assetOutIndex: assetInIndex, + amount: B.toString(), + userData: '0x', + }, + ], + pool.tokensList + ); + const finalA = parseFloat( + formatFixed( + BigNumber.from(-1).mul(swapBtoA[assetInIndex]), + pool.tokens[assetInIndex].decimals + ) + ); - before(() => { - tokenIn = pool.tokens[0]; - amountIn = parseFixed('10', tokenIn.decimals); - }); + const initialA = parseFloat( + formatFixed(swapAmount, pool.tokens[assetInIndex].decimals) + ); - it('should calculate price impact - spot price method', async () => { - const amountsIn = Array(pool.tokensList.length).fill('0'); - amountsIn[pool.tokensList.indexOf(tokenIn.address)] = - amountIn.toString(); + const priceImpactABA = + (initialA - finalA) / initialA / 2 - parseFloat(pool.swapFee); + console.log(`priceImpactABA : ${priceImpactABA}`); + }); + }); - const { priceImpact } = pool.buildJoin( - signerAddress, - pool.tokensList, - amountsIn, - slippage - ); + context('single token join', async () => { + let tokenIn: PoolToken; + let amountIn: BigNumber; - const priceImpactFloat = parseFloat( - formatFixed(BigNumber.from(priceImpact), 18) - ); - console.log(`priceImpactFloat: ${priceImpactFloat}`); - }); + before(() => { + tokenIn = pool.tokens[0]; + amountIn = parseFixed('10', tokenIn.decimals); + }); - it('should calculate price impact - ABA method', async () => { - const maxAmountsInByToken = new Map([ - [tokenIn.address, amountIn], - ]); + it('should calculate price impact - spot price method', async () => { + const amountsIn = Array(pool.tokensList.length).fill('0'); + amountsIn[pool.tokensList.indexOf(tokenIn.address)] = amountIn.toString(); - const joinParams = pool.buildQueryJoinExactIn({ - maxAmountsInByToken, - }); + const { priceImpact } = pool.buildJoin( + signerAddress, + pool.tokensList, + amountsIn, + slippage + ); - const { bptOut } = await balancerHelpers.callStatic.queryJoin( - ...joinParams - ); + const priceImpactFloat = parseFloat( + formatFixed(BigNumber.from(priceImpact), 18) + ); + console.log(`priceImpactSpotPrice: ${priceImpactFloat}`); + }); - const exitParams = pool.buildQueryExitToSingleToken({ - bptIn: bptOut, - tokenOut: tokenIn.address, - }); + it('should calculate price impact - ABA method', async () => { + const maxAmountsInByToken = new Map([ + [tokenIn.address, amountIn], + ]); - const { amountsOut } = await balancerHelpers.callStatic.queryExit( - ...exitParams - ); + const joinParams = pool.buildQueryJoinExactIn({ + maxAmountsInByToken, + }); + + const { bptOut } = await balancerHelpers.callStatic.queryJoin( + ...joinParams + ); - const initialA = parseFloat(formatFixed(amountIn, 8)); - const finalA = parseFloat(formatFixed(amountsOut[0], 8)); - const priceImpactABA = (initialA - finalA) / initialA / 2; - console.log(`priceImpactABA : ${priceImpactABA}`); + const exitParams = pool.buildQueryExitToSingleToken({ + bptIn: bptOut, + tokenOut: tokenIn.address, }); + + const { amountsOut } = await balancerHelpers.callStatic.queryExit( + ...exitParams + ); + + const initialA = parseFloat(formatFixed(amountIn, 8)); + const finalA = parseFloat(formatFixed(amountsOut[0], 8)); + const priceImpactABA = (initialA - finalA) / initialA / 2; + console.log(`priceImpactABA : ${priceImpactABA}`); }); + }); - context('unbalanced join - 2 tokens', async () => { - let amountsIn: BigNumber[]; + context('unbalanced join - 2 tokens', async () => { + let amountsIn: BigNumber[]; - before(() => { - amountsIn = pool.tokens.map((token) => - parseFixed('10000', token.decimals) - ); - }); + before(() => { + amountsIn = pool.tokens.map((token) => + parseFixed('10000', token.decimals) + ); + }); - it('should calculate price impact - spot price method', async () => { - const { priceImpact } = pool.buildJoin( - signerAddress, - pool.tokensList, - amountsIn.map((amount) => amount.toString()), - slippage - ); + it('should calculate price impact - spot price method', async () => { + const { priceImpact } = pool.buildJoin( + signerAddress, + pool.tokensList, + amountsIn.map((amount) => amount.toString()), + slippage + ); - const priceImpactFloat = parseFloat( - formatFixed(BigNumber.from(priceImpact), 18) - ); - console.log(`priceImpactFloat: ${priceImpactFloat}`); - }); + const priceImpactFloat = parseFloat( + formatFixed(BigNumber.from(priceImpact), 18) + ); + console.log(`priceImpactSpotPrice: ${priceImpactFloat}`); + }); - it('should calculate price impact - ABA method', async () => { - const maxAmountsInByToken = new Map( - amountsIn.map((a, i) => [pool.tokensList[i], a]) - ); + it('should calculate price impact - ABA method', async () => { + const maxAmountsInByToken = new Map( + amountsIn.map((a, i) => [pool.tokensList[i], a]) + ); - // query unbalanced join - const { bptOut } = await balancerHelpers.callStatic.queryJoin( - ...pool.buildQueryJoinExactIn({ - maxAmountsInByToken, - }) - ); + // query unbalanced join + const { bptOut } = await balancerHelpers.callStatic.queryJoin( + ...pool.buildQueryJoinExactIn({ + maxAmountsInByToken, + }) + ); - // calculate proportional amounts out - const { amountsOut } = await balancerHelpers.callStatic.queryExit( - ...pool.buildQueryExitProportionally({ - bptIn: bptOut, - }) - ); + // calculate proportional amounts out + const { amountsOut } = await balancerHelpers.callStatic.queryExit( + ...pool.buildQueryExitProportionally({ + bptIn: bptOut, + }) + ); - // diff between unbalanced and proportional amounts for token 1 - const diffs = amountsOut.map((a, i) => a.sub(amountsIn[i])); - const excessIndex = diffs.findIndex((a) => a.gt(0)); - const otherIndex = diffs.findIndex((a) => a.lt(0)); - const diff1 = amountsOut[excessIndex].sub(amountsIn[excessIndex]); - - // swap that diff to token 0 - const returnAmounts = await queryBatchSwap( - vault, - SwapType.SwapExactIn, - [ - { - poolId: pool.id, - assetInIndex: excessIndex, - assetOutIndex: otherIndex, - amount: diff1.toString(), - userData: '0x', - }, - ], - pool.tokensList - ); + // diff between unbalanced and proportional amounts for token 1 + const diffs = amountsOut.map((a, i) => a.sub(amountsIn[i])); + const excessIndex = diffs.findIndex((a) => a.gt(0)); + const otherIndex = diffs.findIndex((a) => a.lt(0)); + const diff1 = amountsOut[excessIndex].sub(amountsIn[excessIndex]); + + // swap that diff to token 0 + const returnAmounts = await queryBatchSwap( + vault, + SwapType.SwapExactIn, + [ + { + poolId: pool.id, + assetInIndex: excessIndex, + assetOutIndex: otherIndex, + amount: diff1.toString(), + userData: '0x', + }, + ], + pool.tokensList + ); - // calculate final token 0 amount (using sub because returnAmounts[0] is negative) - const token0Final = amountsOut[otherIndex].sub( - BigNumber.from(returnAmounts[otherIndex]) - ); + // calculate final token 0 amount (using sub because returnAmounts[0] is negative) + const token0Final = amountsOut[otherIndex].sub( + BigNumber.from(returnAmounts[otherIndex]) + ); - // diff between unbalanced and proportional amounts for token 0 - const diff0 = amountsIn[otherIndex].sub(token0Final); + // diff between unbalanced and proportional amounts for token 0 + const diff0 = amountsIn[otherIndex].sub(token0Final); - // query join with diff0 in order to get BPT difference between unbalanced and proportional - const diffAmounts = new Map([ - [pool.tokensList[otherIndex], diff0], - ]); + // query join with diff0 in order to get BPT difference between unbalanced and proportional + const diffAmounts = new Map([ + [pool.tokensList[otherIndex], diff0], + ]); - const { bptOut: bptOutDiff } = - await balancerHelpers.callStatic.queryJoin( - ...pool.buildQueryJoinExactIn({ - maxAmountsInByToken: diffAmounts, - }) - ); + const { bptOut: bptOutDiff } = await balancerHelpers.callStatic.queryJoin( + ...pool.buildQueryJoinExactIn({ + maxAmountsInByToken: diffAmounts, + }) + ); - const initialA = parseFloat( - formatFixed(bptOut, pool.tokens[otherIndex].decimals) - ); - const finalA = parseFloat( - formatFixed(bptOut.sub(bptOutDiff), pool.tokens[otherIndex].decimals) - ); - const priceImpactABA = (initialA - finalA) / initialA / 2; - console.log(`priceImpactABA : ${priceImpactABA}`); - }); + const initialA = parseFloat( + formatFixed(bptOut, pool.tokens[otherIndex].decimals) + ); + const finalA = parseFloat( + formatFixed(bptOut.sub(bptOutDiff), pool.tokens[otherIndex].decimals) + ); + const priceImpactABA = (initialA - finalA) / initialA / 2; + console.log(`priceImpactABA : ${priceImpactABA}`); }); }); });