Skip to content

Commit

Permalink
Merge pull request #521 from balancer/generalised-exit-phantom
Browse files Browse the repository at this point in the history
Generalised exit phantom
  • Loading branch information
johngrantuk authored Aug 18, 2023
2 parents 9c95c69 + d2c08af commit 56108ec
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 16 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 @@ -15,6 +15,34 @@ const blockNo = TEST_BLOCK[Network.MAINNET];

describe('generalised exit execution', async function () {
this.timeout(120000); // Sets timeout for all tests within this scope to 2 minutes
context('aaveLinear V1 - bbausd', async () => {
const network = Network.MAINNET;
const pool = ADDRESSES[network].bbausd;
const slippage = '10'; // 10 bps = 0.1%
const poolAddresses = Object.values(ADDRESSES[network]).map(
(address) => address.address
);

const amountRatio = 10;
// Amount greater than the underlying main token balance, which will cause the exit to be unwrapped
const unwrapExitAmount = parseFixed('1273000', pool.decimals);
// Amount smaller than the underlying main token balance, which will cause the exit to be done directly
const mainExitAmount = unwrapExitAmount.div(amountRatio);

context('exit to main tokens directly', async () => {
it('should exit to main tokens directly', async () => {
await testFlow(
pool,
slippage,
mainExitAmount.toString(),
[],
network,
blockNo,
poolAddresses
);
});
});
});

context('ERC4626 - bbausd3', async () => {
if (!TEST_BBAUSD3) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const poolAddresses = Object.values(ADDRESSES[network]).map(
);
const addresses = ADDRESSES[network];

describe.skip('generalised exit execution', async function () {
describe('generalised exit execution', async function () {
this.timeout(120000); // Sets timeout for all tests within this scope to 2 minutes

/*
Expand Down
111 changes: 109 additions & 2 deletions balancer-js/src/modules/exits/exits.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import { AssetHelpers, subSlippage } from '@/lib/utils';
import { PoolGraph, Node } from '@/modules/graph/graph';
import { Join } from '@/modules/joins/joins.module';
import { calcPriceImpact } from '@/modules/pricing/priceImpact';
import { EncodeUnwrapInput, Relayer } from '@/modules/relayer/relayer.module';
import {
EncodeUnwrapInput,
OutputReference,
Relayer,
EncodeBatchSwapInput,
} from '@/modules/relayer/relayer.module';
import {
Simulation,
SimulationType,
Expand All @@ -20,9 +25,13 @@ import {
SingleSwap,
Swap,
SwapType,
BatchSwapStep,
} from '@/modules/swaps/types';
import { ExitPoolRequest as ExitPoolModelRequest } from '@/modules/vaultModel/poolModel/exit';
import { SwapRequest } from '@/modules/vaultModel/poolModel/swap';
import {
BatchSwapRequest,
SwapRequest,
} from '@/modules/vaultModel/poolModel/swap';
import { UnwrapRequest } from '@/modules/vaultModel/poolModel/unwrap';
import { Requests, VaultModel } from '@/modules/vaultModel/vaultModel.module';
import { ComposableStablePoolEncoder } from '@/pool-composable-stable';
Expand Down Expand Up @@ -858,6 +867,104 @@ export class Exit {
return { modelRequest, encodedCall, assets, amounts };
}

private createBatchSwap(
node: Node,
exitChildren: Node[],
exitPathIndex: number,
minAmountsOut: string[],
sender: string,
recipient: string
): {
modelRequest: BatchSwapRequest;
encodedCall: string;
assets: string[];
amounts: string[];
} {
const isRootNode = !node.parent;
const amountIn = isRootNode
? node.index
: Relayer.toChainedReference(
this.getOutputRef(exitPathIndex, node.index)
).toString();

const tokensOut = exitChildren.map((n) => n.address);
const assets = [...tokensOut, node.address];
// TODO - setting these right?
const limits = [...minAmountsOut];
limits.push(amountIn);
const batchSwapSteps: BatchSwapStep[] = [];
const outputReferences: OutputReference[] = [];
exitChildren.forEach((child, i) => {
// TODO - Is this correct?
const amount = child.proportionOfParent
.mul(amountIn)
.div(WeiPerEther)
.toString();
const swapStep: BatchSwapStep = {
poolId: node.id,
assetInIndex: assets.length - 1,
assetOutIndex: i,
amount,
userData: '0x',
};
batchSwapSteps.push(swapStep);
// TODO - Is this right?
outputReferences.push({
index: i,
key: Relayer.toChainedReference(this.getOutputRef(0, child.index)),
});
});

const total = batchSwapSteps.reduce((acc, swap) => {
return acc.add(swap.amount);
}, BigNumber.from(0));
const dust = BigNumber.from(amountIn).sub(total);
batchSwapSteps[0].amount = dust.add(batchSwapSteps[0].amount).toString();

const fromInternalBalance = this.receivesFromInternal(node);
// TODO - This is assuming that all exit to same, is this right?
const toInternalBalance = this.receivesFromInternal(exitChildren[0]);

const funds: FundManagement = {
sender,
recipient,
fromInternalBalance,
toInternalBalance,
};

const call: EncodeBatchSwapInput = {
swapType: SwapType.SwapExactIn,
swaps: batchSwapSteps,
assets,
funds,
limits,
deadline: BigNumber.from(Math.ceil(Date.now() / 1000) + 3600), // 1 hour from now
value: '0', // TODO: check if swap with ETH is possible in this case and handle it
outputReferences,
};
debugLog('\nBatchSwap:');
debugLog(JSON.stringify(call));

const encodedCall = Relayer.encodeBatchSwap(call);

const modelRequest = VaultModel.mapBatchSwapRequest(call);

// If node isn't rootNode, the swap is part of a chain and shouldn't be considered for user deltas
const bptIn = !isRootNode ? '0' : amountIn;
// If child exit action is not output, the swap is part of a chain and shouldn't be considered for user deltas
const userTokensOut = exitChildren.map((child, i) => {
const userTokenOutAmount =
child.exitAction !== 'output'
? '0'
: BigNumber.from(minAmountsOut[i]).mul(-1).toString(); // needs to be negative because it's handled by the vault model as an amount going out of the vault
return userTokenOutAmount;
});

const amounts = [...userTokensOut, bptIn];

return { modelRequest, encodedCall, assets, amounts };
}

private createExitPool(
node: Node,
exitChild: Node,
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
18 changes: 18 additions & 0 deletions balancer-js/src/test/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,24 @@ export const ADDRESSES = {
symbol: 'bbausd',
slot: 0,
},
bbausdcV1: {
address: '0x9210F1204b5a24742Eba12f710636D76240dF3d0',
decimals: 18,
symbol: 'bbausdc',
slot: 0,
},
bbausdtV1: {
address: '0x2BBf681cC4eb09218BEe85EA2a5d3D13Fa40fC0C',
decimals: 18,
symbol: 'bbausdt',
slot: 0,
},
bbadaiV1: {
address: '0x804CdB9116a10bB78768D3252355a1b18067bF8f',
decimals: 18,
symbol: 'bbadai',
slot: 0,
},
bbausd2: {
id: '0xa13a9247ea42d743238089903570127dda72fe4400000000000000000000035d',
address: '0xa13a9247ea42d743238089903570127dda72fe44',
Expand Down

0 comments on commit 56108ec

Please sign in to comment.