Skip to content

Commit

Permalink
Merge pull request #523 from balancer/generalised-exit-phantom-tests
Browse files Browse the repository at this point in the history
Generalised exit phantom tests
  • Loading branch information
johngrantuk authored Aug 18, 2023
2 parents e21b74e + aadc392 commit d2c08af
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 81 deletions.
12 changes: 12 additions & 0 deletions balancer-js/src/lib/utils/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,16 @@ export class Logger {
console.error(`[ERROR] ${message}`);
}
}

time(message: string): void {
if (this.enableLogging) {
console.time(`[TIME] ${message}`);
}
}

timeEnd(message: string): void {
if (this.enableLogging) {
console.timeEnd(`[TIME] ${message}`);
}
}
}
9 changes: 7 additions & 2 deletions balancer-js/src/modules/data/pool/subgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { GraphQLQuery, Pool } from '@/types';
import { Network } from '@/lib/constants/network';
import { PoolsQueryVariables } from '../../subgraph/subgraph';
import { mapType } from './subgraph-helpers';
import { Logger } from '@/lib/utils/logger';

interface PoolsSubgraphRepositoryOptions {
url: string;
Expand Down Expand Up @@ -76,7 +77,8 @@ export class PoolsSubgraphRepository
* @returns Promise resolving to pools list
*/
private async fetchAllPools(): Promise<Pool[]> {
console.time('fetching pools');
const logger = Logger.getInstance();
logger.time('fetching pools');

if (this.blockHeight) {
this.query.args.block = { number: await this.blockHeight() };
Expand All @@ -88,14 +90,16 @@ export class PoolsSubgraphRepository
const { pool0, pool1000, pool2000 } = await this.client.AllPools(
formattedQuery
);
console.timeEnd('fetching pools');
logger.timeEnd('fetching pools');

return [...pool0, ...pool1000, ...pool2000].map((pool) =>
mapType(pool, this.chainId)
);
}

async fetch(options?: PoolsRepositoryFetchOptions): Promise<Pool[]> {
const logger = Logger.getInstance();
logger.time('fetching pools');
if (options?.skip) {
this.query.args.skip = options.skip;
}
Expand All @@ -112,6 +116,7 @@ export class PoolsSubgraphRepository
const { pools } = await this.client.Pools(formattedQuery);

this.skip = (options?.skip || 0) + pools.length;
logger.timeEnd('fetching pools');

return pools.map((pool) => mapType(pool, this.chainId));
}
Expand Down
22 changes: 14 additions & 8 deletions balancer-js/src/modules/data/pool/subgraphOnChain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Pool } from '@/types';
import { getOnChainBalances } from '../../../modules/sor/pool-data/onChainData';
import { PoolsSubgraphRepository } from './subgraph';
import { isSameAddress } from '@/lib/utils';
import { Logger } from '@/lib/utils/logger';

interface PoolsSubgraphOnChainRepositoryOptions {
provider: Provider;
Expand Down Expand Up @@ -59,35 +60,40 @@ export class PoolsSubgraphOnChainRepository
* @returns Promise resolving to pools list
*/
private async fetchDefault(): Promise<Pool[]> {
console.time('fetching pools SG');
const pools = await this.poolsSubgraph.all();
console.timeEnd('fetching pools SG');
const filteredPools = this.filterPools(pools);
console.time(`fetching onchain ${filteredPools.length} pools`);

const logger = Logger.getInstance();
logger.time(`fetching onchain ${filteredPools.length} pools`);

const onchainPools = await getOnChainBalances(
filteredPools,
this.multicall,
this.vault,
this.provider
);
console.timeEnd(`fetching onchain ${filteredPools.length} pools`);

logger.timeEnd(`fetching onchain ${filteredPools.length} pools`);

return onchainPools;
}

async fetch(options?: PoolsRepositoryFetchOptions): Promise<Pool[]> {
console.time('fetching pools SG');
const pools = await this.poolsSubgraph.fetch(options);
console.timeEnd('fetching pools SG');
const filteredPools = this.filterPools(pools);
console.time(`fetching onchain ${filteredPools.length} pools`);

const logger = Logger.getInstance();
logger.time(`fetching onchain ${filteredPools.length} pools`);

const onchainPools = await getOnChainBalances(
filteredPools,
this.multicall,
this.vault,
this.provider
);
console.timeEnd(`fetching onchain ${filteredPools.length} pools`);

logger.timeEnd(`fetching onchain ${filteredPools.length} pools`);

return onchainPools;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ describe('generalised exit execution', async function () {
const network = Network.MAINNET;
const pool = ADDRESSES[network].bbausd;
const slippage = '10'; // 10 bps = 0.1%
let unwrappingTokensAmountsOut: string[];
let unwrappingTokensGasUsed: BigNumber;
let mainTokensAmountsOut: string[];
let mainTokensGasUsed: BigNumber;
const poolAddresses = Object.values(ADDRESSES[network]).map(
(address) => address.address
);
Expand All @@ -33,25 +29,9 @@ describe('generalised exit execution', async function () {
// Amount smaller than the underlying main token balance, which will cause the exit to be done directly
const mainExitAmount = unwrapExitAmount.div(amountRatio);

context('exit by unwrapping tokens', async () => {
it('should exit via unwrapping', async () => {
const { expectedAmountsOut, gasUsed } = await testFlow(
pool,
slippage,
unwrapExitAmount.toString(),
[ADDRESSES[network].DAI.address],
network,
blockNo,
poolAddresses
);
unwrappingTokensAmountsOut = expectedAmountsOut;
unwrappingTokensGasUsed = gasUsed;
});
});

context('exit to main tokens directly', async () => {
it('should exit to main tokens directly', async () => {
const { expectedAmountsOut, gasUsed } = await testFlow(
await testFlow(
pool,
slippage,
mainExitAmount.toString(),
Expand All @@ -60,24 +40,6 @@ describe('generalised exit execution', async function () {
blockNo,
poolAddresses
);
mainTokensAmountsOut = expectedAmountsOut;
mainTokensGasUsed = gasUsed;
});
});

context('exit by unwrapping vs exit to main tokens', async () => {
it('should return similar amounts (proportional to the input)', async () => {
mainTokensAmountsOut.forEach((amount, i) => {
const unwrappedAmount = BigNumber.from(
unwrappingTokensAmountsOut[i]
).div(amountRatio);
expect(
accuracy(unwrappedAmount, BigNumber.from(amount))
).to.be.closeTo(1, 1e-4); // inaccuracy should not be over 1 bps
});
});
it('should spend more gas when unwrapping tokens', async () => {
expect(unwrappingTokensGasUsed.gt(mainTokensGasUsed)).to.be.true;
});
});
});
Expand Down
41 changes: 12 additions & 29 deletions balancer-js/src/modules/exits/exits.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -676,35 +676,18 @@ export class Exit {
break;
}
case 'batchSwap': {
if (node.children.length === 1) {
const { modelRequest, encodedCall, assets, amounts } =
this.createSwap(
node,
exitChild as Node,
i,
minAmountOut,
sender,
recipient
);
modelRequests.push(modelRequest);
calls.push(encodedCall);
this.updateDeltas(deltas, assets, amounts);
} else {
const exitChildren = node.children.map((n) => n);
// TODO - is it correct to use minAmountsOutProportional?
const { modelRequest, encodedCall, assets, amounts } =
this.createBatchSwap(
node,
exitChildren,
i,
minAmountsOutProportional,
sender,
recipient
);
modelRequests.push(modelRequest);
calls.push(encodedCall);
this.updateDeltas(deltas, assets, amounts);
}
const { modelRequest, encodedCall, assets, amounts } =
this.createSwap(
node,
exitChild as Node,
i,
minAmountOut,
sender,
recipient
);
modelRequests.push(modelRequest);
calls.push(encodedCall);
this.updateDeltas(deltas, assets, amounts);
break;
}
case 'exitPool': {
Expand Down
2 changes: 1 addition & 1 deletion balancer-js/src/modules/graph/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ export class PoolGraph {
*/
static isProportionalPools(nodes: Node[]): boolean {
return nodes.every((node) => {
if (node.exitAction === 'exitPool') return node.isProportionalExit;
if (node.children.length > 1) return node.isProportionalExit;
else return true;
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
} from '@/lib/graphql/args-builder';

import { isSameAddress } from '@/lib/utils';
import { Logger } from '@/lib/utils/logger';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function mapPools(pools: any[]): SubgraphPoolBase[] {
Expand Down Expand Up @@ -87,14 +88,17 @@ export class SubgraphPoolDataService implements PoolDataService {
return mapped;
}

console.time(`fetching on-chain balances for ${mapped.length} pools`);
const logger = Logger.getInstance();
logger.time(`fetching on-chain balances for ${mapped.length} pools`);

const onChainBalances = await getOnChainBalances(
mapped,
this.network.addresses.contracts.multicall,
this.network.addresses.contracts.vault,
this.provider
);
console.timeEnd(`fetching on-chain balances for ${mapped.length} pools`);

logger.timeEnd(`fetching on-chain balances for ${mapped.length} pools`);

return onChainBalances;
}
Expand Down

0 comments on commit d2c08af

Please sign in to comment.