Skip to content

Commit

Permalink
Merge pull request paraswap#294 from paraswap/fix/905-fix-balancer-v2…
Browse files Browse the repository at this point in the history
…-issues

BACK-905: Fix BalancerV2 ComposableStable issue
  • Loading branch information
Verisana authored Feb 2, 2023
2 parents eb30ca7 + a9faef2 commit 6b84384
Show file tree
Hide file tree
Showing 12 changed files with 305 additions and 97 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@paraswap/dex-lib",
"version": "2.9.53",
"version": "2.9.55",
"main": "build/index.js",
"types": "build/index.d.ts",
"repository": "https://github.com/paraswap/paraswap-dex-lib",
Expand Down
11 changes: 0 additions & 11 deletions src/dex/balancer-v2/LinearPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,11 +346,6 @@ export class LinearPool extends BasePool {
target: pool.address,
callData: this.poolInterface.encodeFunctionData('getScalingFactors'),
});
//getScalingFactors does not include the rate for the phantom bpt, need to fetch it separately
poolCallData.push({
target: pool.address,
callData: this.poolInterface.encodeFunctionData('getRate'),
});
// returns lowerTarget, upperTarget
poolCallData.push({
target: pool.address,
Expand Down Expand Up @@ -389,12 +384,6 @@ export class LinearPool extends BasePool {
data[startIndex++],
pool.address,
)[0];
const rate = decodeThrowError(
this.poolInterface,
'getRate',
data[startIndex++],
pool.address,
)[0];
const [lowerTarget, upperTarget] = decodeThrowError(
this.poolInterface,
'getTargets',
Expand Down
19 changes: 1 addition & 18 deletions src/dex/balancer-v2/PhantomStablePool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,6 @@ export class PhantomStablePool extends BasePool {
target: pool.address,
callData: this.poolInterface.encodeFunctionData('getScalingFactors'),
},
{
target: pool.address,
callData: this.poolInterface.encodeFunctionData('getRate'),
},
{
target: pool.address,
callData: this.poolInterface.encodeFunctionData(
Expand Down Expand Up @@ -373,30 +369,17 @@ export class PhantomStablePool extends BasePool {
data[startIndex++],
pool.address,
)[0];
const rate = decodeThrowError(
this.poolInterface,
'getRate',
data[startIndex++],
pool.address,
)[0];
const amp = decodeThrowError(
this.poolInterface,
'getAmplificationParameter',
data[startIndex++],
pool.address,
);

const bptIndex = pool.tokens.findIndex(
t => t.address.toLowerCase() === pool.address.toLowerCase(),
);

const tokens = poolTokens.tokens.map((address: string, idx: number) => ({
address: address.toLowerCase(),
balance: BigInt(poolTokens.balances[idx].toString()),
scalingFactor:
idx === bptIndex
? BigInt(rate.toString())
: BigInt(scalingFactors[idx].toString()),
scalingFactor: BigInt(scalingFactors[idx].toString()),
}));

const poolState: PoolState = {
Expand Down
148 changes: 94 additions & 54 deletions src/dex/balancer-v2/balancer-v2-integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,61 +50,24 @@ const amounts = [0n, BI_POWS[18], 2000000000000000000n];
const dexKey = 'BalancerV2';

describe('BalancerV2', function () {
describe('BeetsFi', () => {
it('FTM -> BOO: getPoolIdentifiers and getPricesVolume', async () => {
const dexKey = 'BeetsFi';
const network = Network.FANTOM;
const srcToken = Tokens[network]['FTM'];
const destToken = Tokens[network]['BOO'];
const amounts = [0n, BI_POWS[18]];
describe('ComposableStable', () => {
it('USDC -> USDT getPoolIdentifiers and getPricesVolume', async () => {
const network = Network.MAINNET;
const srcToken = Tokens[network]['USDC'];
const destToken = Tokens[network]['USDT'];
const amounts = [0n, 10000001000000n];

const dexHelper = new DummyDexHelper(network);
// const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();
const blockNumber = 54734626;
const beetsFi = new BalancerV2(network, dexKey, dexHelper);

await beetsFi.initializePricing(blockNumber);

const pools = await beetsFi.getPoolIdentifiers(
srcToken,
destToken,
SwapSide.SELL,
blockNumber,
);
console.log('Pool Identifiers: ', pools);
const blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
// You will need blockTimestamp to check onchain calculation, because
// it depends on timestamp. If you have different values, they are incomparable
// const block = await dexHelper.web3Provider.eth.getBlock(blockNumber);

expect(pools.length).toBeGreaterThan(0);
const balancerV2 = new BalancerV2(network, dexKey, dexHelper);

const poolPrices = await beetsFi.getPricesVolume(
srcToken,
destToken,
amounts,
SwapSide.SELL,
blockNumber,
pools,
);
console.log('Pool Prices: ', poolPrices);
await balancerV2.initializePricing(blockNumber);

expect(poolPrices).not.toBeNull();
checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey);

await beetsFi.releaseResources();
});
it('WETH -> FTM: getPoolIdentifiers and getPricesVolume', async () => {
const dexKey = 'BeetsFi';
const network = Network.FANTOM;
const srcToken = Tokens[network]['WETH'];
const destToken = Tokens[network]['FTM'];
const amounts = [0n, BI_POWS[18]];

const dexHelper = new DummyDexHelper(network);
// const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();
const blockNumber = 54782005;
const beetsFi = new BalancerV2(network, dexKey, dexHelper);

await beetsFi.initializePricing(blockNumber);

const pools = await beetsFi.getPoolIdentifiers(
const pools = await balancerV2.getPoolIdentifiers(
srcToken,
destToken,
SwapSide.SELL,
Expand All @@ -114,7 +77,7 @@ describe('BalancerV2', function () {

expect(pools.length).toBeGreaterThan(0);

const poolPrices = await beetsFi.getPricesVolume(
const poolPrices = await balancerV2.getPricesVolume(
srcToken,
destToken,
amounts,
Expand All @@ -127,11 +90,9 @@ describe('BalancerV2', function () {
expect(poolPrices).not.toBeNull();
checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey);

await beetsFi.releaseResources();
await balancerV2.releaseResources();
});
});

describe('ComposableStable', () => {
it('getPoolIdentifiers and getPricesVolume', async () => {
const dexHelper = new DummyDexHelper(Network.POLYGON);
const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();
Expand Down Expand Up @@ -397,3 +358,82 @@ describe('BalancerV2', function () {
});
});
});

describe('BeetsFi', () => {
it('FTM -> BOO: getPoolIdentifiers and getPricesVolume', async () => {
const dexKey = 'BeetsFi';
const network = Network.FANTOM;
const srcToken = Tokens[network]['FTM'];
const destToken = Tokens[network]['BOO'];
const amounts = [0n, BI_POWS[18]];

const dexHelper = new DummyDexHelper(network);
const blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
const beetsFi = new BalancerV2(network, dexKey, dexHelper);

await beetsFi.initializePricing(blockNumber);

const pools = await beetsFi.getPoolIdentifiers(
srcToken,
destToken,
SwapSide.SELL,
blockNumber,
);
console.log('Pool Identifiers: ', pools);

expect(pools.length).toBeGreaterThan(0);

const poolPrices = await beetsFi.getPricesVolume(
srcToken,
destToken,
amounts,
SwapSide.SELL,
blockNumber,
pools,
);
console.log('Pool Prices: ', poolPrices);

expect(poolPrices).not.toBeNull();
checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey);

await beetsFi.releaseResources();
});
it('WETH -> FTM: getPoolIdentifiers and getPricesVolume', async () => {
const dexKey = 'BeetsFi';
const network = Network.FANTOM;
const srcToken = Tokens[network]['WETH'];
const destToken = Tokens[network]['FTM'];
const amounts = [0n, BI_POWS[18]];

const dexHelper = new DummyDexHelper(network);
const blockNumber = await dexHelper.web3Provider.eth.getBlockNumber();
const beetsFi = new BalancerV2(network, dexKey, dexHelper);

await beetsFi.initializePricing(blockNumber);

const pools = await beetsFi.getPoolIdentifiers(
srcToken,
destToken,
SwapSide.SELL,
blockNumber,
);
console.log('Pool Identifiers: ', pools);

expect(pools.length).toBeGreaterThan(0);

const poolPrices = await beetsFi.getPricesVolume(
srcToken,
destToken,
amounts,
SwapSide.SELL,
blockNumber,
pools,
);
console.log('Pool Prices: ', poolPrices);

expect(poolPrices).not.toBeNull();
checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey);

await beetsFi.releaseResources();
});
});
21 changes: 13 additions & 8 deletions src/dex/balancer-v2/balancer-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ import {
poolGetMainTokens,
poolGetPathForTokenInOut,
} from './utils';
import { MIN_USD_LIQUIDITY_TO_FETCH } from './constants';
import {
MIN_USD_LIQUIDITY_TO_FETCH,
STABLE_GAS_COST,
VARIABLE_GAS_COST_PER_CYCLE,
} from './constants';

const fetchAllPools = `query ($count: Int) {
pools: pools(
Expand Down Expand Up @@ -158,11 +162,11 @@ export class BalancerV2EventPool extends StatefulEventSubscriber<PoolStateMap> {
The difference of note for swaps is ComposableStable must use 'actualSupply' instead of VirtualSupply.
VirtualSupply could be calculated easily whereas actualSupply cannot hence the use of onchain call.
*/
// const composableStable = new PhantomStablePool(
// this.vaultAddress,
// this.vaultInterface,
// true,
// );
const composableStable = new PhantomStablePool(
this.vaultAddress,
this.vaultInterface,
true,
);
const linearPool = new LinearPool(this.vaultAddress, this.vaultInterface);

this.pools = {};
Expand All @@ -177,7 +181,7 @@ export class BalancerV2EventPool extends StatefulEventSubscriber<PoolStateMap> {
// Beets uses "Linear" generically for all linear pool types
this.pools[BalancerPoolTypes.Linear] = linearPool;
this.pools[BalancerPoolTypes.StablePhantom] = stablePhantomPool;
// this.pools[BalancerPoolTypes.ComposableStable] = composableStable;
this.pools[BalancerPoolTypes.ComposableStable] = composableStable;
this.vaultDecoder = (log: Log) => this.vaultInterface.parseLog(log);
this.addressesSubscribed = [vaultAddress];

Expand Down Expand Up @@ -760,7 +764,8 @@ export class BalancerV2
},
poolAddresses: [poolAddress],
exchange: this.dexKey,
gasCost: 150 * 1000 * (path.length - 1),
gasCost:
STABLE_GAS_COST + VARIABLE_GAS_COST_PER_CYCLE * path.length,
poolIdentifier: `${this.dexKey}_${poolAddress}`,
};

Expand Down
9 changes: 9 additions & 0 deletions src/dex/balancer-v2/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
export const MIN_USD_LIQUIDITY_TO_FETCH = 100n;

// Let's take this trade as an example:
// https://dashboard.tenderly.co/paraswap/paraswap/fork/e4c81946-fd6e-4299-b35c-c47b775e3c05/simulation/8839462c-6239-4ae1-9ed0-8013f89b41de/gas-usage

// 271719 - 57856 - 79098 - 51041 = 83724 ~ 84k
export const STABLE_GAS_COST = 84_000;

// I see three pools used in trade: (57856 + 79098 + 51041) / 3 = 62665 ~ 63k
export const VARIABLE_GAS_COST_PER_CYCLE = 63_000;
2 changes: 1 addition & 1 deletion src/dex/balancer-v2/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export enum BalancerPoolTypes {
StablePhantom = 'StablePhantom',
ERC4626Linear = 'ERC4626Linear',
Linear = 'Linear',
// ComposableStable = 'ComposableStable',
ComposableStable = 'ComposableStable',
}

export type TokenState = {
Expand Down
4 changes: 2 additions & 2 deletions src/dex/balancer-v2/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ function isLinearPool(poolType: string) {

function isPhantomStablePool(poolType: string) {
return (
poolType === BalancerPoolTypes.StablePhantom
// || poolType === BalancerPoolTypes.ComposableStable
poolType === BalancerPoolTypes.StablePhantom ||
poolType === BalancerPoolTypes.ComposableStable
);
}

Expand Down
7 changes: 7 additions & 0 deletions src/dex/uniswap-v2/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,13 @@ export const UniswapV2Config: DexConfigMap<DexParams> = {
poolGasCost: 90 * 1000,
feeCode: 25,
},
[Network.MAINNET]: {
factoryAddress: '0x1097053Fd2ea711dad45caCcc45EfF7548fCB362',
initCode:
'0x57224589c67f3f30a6b0d7a1b54cf3153ab84563bc609ef41dfb34f8b2974d2d',
poolGasCost: 90 * 1000,
feeCode: 25,
},
},
PaintSwap: {
[Network.FANTOM]: {
Expand Down
Loading

0 comments on commit 6b84384

Please sign in to comment.