Skip to content

Commit

Permalink
Merge pull request #348 from balancer-labs/configurable-connecting-to…
Browse files Browse the repository at this point in the history
…kens

Configurable connecting tokens
  • Loading branch information
John Grant authored Jan 25, 2023
2 parents a07e95f + 2367db2 commit c6b4050
Show file tree
Hide file tree
Showing 11 changed files with 312 additions and 89 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@balancer-labs/sor",
"version": "4.0.1-beta.18",
"version": "4.1.0-beta.0",
"license": "GPL-3.0-only",
"main": "dist/index.js",
"module": "dist/index.esm.js",
Expand Down
179 changes: 104 additions & 75 deletions src/routeProposal/filtering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ import { Zero } from '@ethersproject/constants';

const BOOSTED_PATHS_MAX_LENGTH = 7;

interface edgeDict {
[node: string]: [string, string, string][];
}

interface treeEdge {
edge: [string, string, string];
parentIndices: [number, number];
visitedNodes: string[];
}

export const filterPoolsByType = (
pools: SubgraphPoolBase[],
poolTypeFilter: PoolFilter
Expand Down Expand Up @@ -166,17 +176,20 @@ export function producePaths(
// We build this tree by adding at each step all the possible continuations for
// each branch. When a branch reaches tokenOut, we write down the corresponding path.
// We only allow paths up to length BOOSTED_PATHS_MAX_LENGTH = 7

export function getBoostedGraph(
tokenIn: string,
tokenOut: string,
poolsAllDict: PoolDictionary,
config: SorConfig
): edgeDict {
const wethAddress: string = config.weth.toLowerCase();
const graphPoolsSet: Set<PoolBase> = new Set();
const linearPools: PoolBase[] = [];
const phantomPools: PoolBase[] = [];
const connectingTokens = config.connectingTokens
? config.connectingTokens.map(
(connectingToken) => connectingToken.address
)
: [];
// Here we add all linear pools, take note of phantom pools,
// add LBP pools with tokenIn or tokenOut and their corresponding
// highest liquidity WETH connections
Expand All @@ -194,73 +207,34 @@ export function getBoostedGraph(
if (tokensList.includes(pool.address)) {
phantomPools.push(pool);
}
if (config.lbpRaisingTokens) {
const raisingTokens = config.lbpRaisingTokens.map((address) =>
address.toLowerCase()
if (config.lbpRaisingTokens && pool.isLBP) {
handleLBPCase(
graphPoolsSet,
config.lbpRaisingTokens,
pool,
tokenIn,
tokenOut,
connectingTokens,
poolsAllDict
);
if (pool.isLBP) {
const raisingTokenIn: string | undefined = getRaisingToken(
pool,
raisingTokens,
tokenIn
);
if (raisingTokenIn) {
graphPoolsSet.add(pool);
if (raisingTokenIn !== wethAddress) {
const bestRaisingTokenInToWeth =
getHighestLiquidityPool(
raisingTokenIn,
wethAddress,
poolsAllDict
);
if (bestRaisingTokenInToWeth) {
graphPoolsSet.add(
poolsAllDict[bestRaisingTokenInToWeth]
);
}
}
}
const raisingTokenOut: string | undefined = getRaisingToken(
pool,
raisingTokens,
tokenOut
);
if (raisingTokenOut) {
graphPoolsSet.add(pool);
if (raisingTokenOut !== wethAddress) {
const bestWethToRaisingTokenOut =
getHighestLiquidityPool(
wethAddress,
raisingTokenOut,
poolsAllDict
);
if (bestWethToRaisingTokenOut) {
graphPoolsSet.add(
poolsAllDict[bestWethToRaisingTokenOut]
);
}
}
}
}
}
}
}
// add highest liquidity pools with tokenIn and weth or tokenOut and weth
const bestTokenInToWeth = getHighestLiquidityPool(
tokenIn,
wethAddress,
poolsAllDict
);
if (bestTokenInToWeth) {
graphPoolsSet.add(poolsAllDict[bestTokenInToWeth]);
}
const bestWethToTokenOut = getHighestLiquidityPool(
wethAddress,
tokenOut,
poolsAllDict
);
if (bestWethToTokenOut) {
graphPoolsSet.add(poolsAllDict[bestWethToTokenOut]);
// add best pools tokenIn -> connectingToken and connectingToken -> tokenOut
// these can be part of a longer path so do not rely on being directly connected
for (const connectingToken of connectingTokens) {
addMostLiquidPoolToSet(
tokenIn,
connectingToken,
poolsAllDict,
graphPoolsSet
);
addMostLiquidPoolToSet(
connectingToken,
tokenOut,
poolsAllDict,
graphPoolsSet
);
}
if (linearPools.length == 0) return {};
const linearPoolsAddresses = linearPools.map((pool) => pool.address);
Expand Down Expand Up @@ -294,10 +268,6 @@ export function getBoostedGraph(
return edgeDict;
}

interface edgeDict {
[node: string]: [string, string, string][];
}

function getNodesAndEdges(pools: PoolBase[]): edgeDict {
const edgesFromNode: edgeDict = {};
for (const pool of pools) {
Expand All @@ -319,12 +289,6 @@ function getNodesAndEdges(pools: PoolBase[]): edgeDict {
return edgesFromNode;
}

interface treeEdge {
edge: [string, string, string];
parentIndices: [number, number];
visitedNodes: string[];
}

export function getBoostedPaths(
tokenIn: string,
tokenOut: string,
Expand Down Expand Up @@ -645,3 +609,68 @@ function getRaisingToken(
}
return theOtherToken;
}

function handleLBPCase(
graphPoolsSet: Set<PoolBase>,
lbpRaisingTokens: string[],
poolLbp: PoolBase,
tokenIn: string,
tokenOut: string,
connectingTokens: string[],
poolsAllDict: PoolDictionary
) {
// Tokens that will be used as LBP Base Token, e.g. USDC/DAI/WETH
const raisingTokens = lbpRaisingTokens.map((address) =>
address.toLowerCase()
);

if (raisingTokens.length === 0) return;

// Assuming tokenIn is the lbpToken find the corresponding base token if it exists
const raisingTokenIn: string | undefined = getRaisingToken(
poolLbp,
raisingTokens,
tokenIn
);
const raisingTokenOut: string | undefined = getRaisingToken(
poolLbp,
raisingTokens,
tokenOut
);
if (!raisingTokenIn && !raisingTokenOut) return;

// Add the LBP pool to the graph
graphPoolsSet.add(poolLbp);

// For each connecting token add most liquid pools with raisingToken and raisingTokenOut
for (const connectingToken of connectingTokens) {
if (raisingTokenIn && raisingTokenIn !== connectingToken) {
// raisingToken>[Pool]>connectingToken
addMostLiquidPoolToSet(
raisingTokenIn,
connectingToken,
poolsAllDict,
graphPoolsSet
);
}
if (raisingTokenOut && raisingTokenOut !== connectingToken) {
// connectingToken>[Pool]>raisingToken
addMostLiquidPoolToSet(
connectingToken,
raisingTokenOut,
poolsAllDict,
graphPoolsSet
);
}
}
}

function addMostLiquidPoolToSet(
tokenIn: string,
tokenOut: string,
pools: PoolDictionary,
graphPools: Set<PoolBase>
): void {
const pool = getHighestLiquidityPool(tokenIn, tokenOut, pools);
if (pool) graphPools.add(pools[pool]);
}
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface SorConfig {
chainId: number;
vault: string;
weth: string;
connectingTokens?: { symbol: string; address: string }[];
staBal3Pool?: { id: string; address: string };
usdcConnectingPool?: { id: string; usdc: string };
wETHwstETH?: { id: string; address: string };
Expand Down
26 changes: 26 additions & 0 deletions test/boostedPaths.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,32 @@ describe('generic boosted pools, path creation test', () => {
assert.equal(paths.length, 4);
});
});
context('using an alternative connecting token', () => {
const USDC = '0xe22da380ee6b445bb8273c81944adeb6e8450422'; // USDC
const GOLD = '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb';
it('USDC to GOLD', () => {
const [, , boostedPaths] = getPaths(
USDC,
GOLD,
SwapTypes.SwapExactIn,
genericBoostedPools.pools,
maxPools,
sorConfigTest
);
assert.equal(boostedPaths.length, 2);
});
it('GOLD to USDC', () => {
const [, , boostedPaths] = getPaths(
GOLD,
USDC,
SwapTypes.SwapExactIn,
genericBoostedPools.pools,
maxPools,
sorConfigTest
);
assert.equal(boostedPaths.length, 2);
});
});
});

describe('generic boosted pools with wstETH, path creation test', () => {
Expand Down
6 changes: 6 additions & 0 deletions test/candidatePaths.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,12 @@ describe('Tests pools filtering and path processing', () => {
chainId: 1,
vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8',
weth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
connectingTokens: [
{
symbol: 'weth',
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
},
],
bbausd: {
id: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb20000000000000000000000fe',
address: '0x7b50775383d3d6f0215a8f290f2c9e2eebbeceb2',
Expand Down
4 changes: 2 additions & 2 deletions test/composableStablePool.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ describe('composable stable pool', () => {
// parsePoolPairData contains pool's allBalances and allBalancesScaled
// both already multiplied by the price rates.
const poolPairData = composableStablePool.parsePoolPairData(
ADDRESSES[Network.MAINNET].bbausdt2.address,
ADDRESSES[Network.MAINNET].bbausd2.address
ADDRESSES[Network.MAINNET].bbausdt.address,
ADDRESSES[Network.MAINNET].bbausd.address
);
it('token -> BPT spot price with no rate', () => {
// spot prices
Expand Down
38 changes: 38 additions & 0 deletions test/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ export const sorConfigTest: SorConfig = {
chainId: 99,
weth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
vault: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
connectingTokens: [
{
symbol: 'weth',
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
},
{
symbol: 'conn',
address: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
},
],
wETHwstETH: {
id: 'wETH-wstETH',
address: '0x0000000000000000000000000000000000222222',
Expand All @@ -25,6 +35,12 @@ export const sorConfigTestStaBal = {
chainId: 99,
weth: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
vault: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
connectingTokens: [
{
symbol: 'weth',
address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
},
],
usdcConnectingPool: {
id: 'usdcConnecting',
usdc: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174',
Expand All @@ -38,18 +54,40 @@ export const sorConfigTestStaBal = {
export const sorConfigEth: SorConfig = {
chainId: 1,
weth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
connectingTokens: [
{
symbol: 'wstEth',
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
},
{
symbol: 'wEth',
address: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0',
},
],
vault: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
};

export const sorConfigKovan: SorConfig = {
chainId: 42,
weth: '0xdFCeA9088c8A88A76FF74892C1457C17dfeef9C1',
connectingTokens: [
{
symbol: 'weth',
address: '0xdFCeA9088c8A88A76FF74892C1457C17dfeef9C1',
},
],
vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8',
};

export const sorConfigFullKovan: SorConfig = {
chainId: 42,
weth: '0xdFCeA9088c8A88A76FF74892C1457C17dfeef9C1',
connectingTokens: [
{
symbol: 'weth',
address: '0xdFCeA9088c8A88A76FF74892C1457C17dfeef9C1',
},
],
vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8',
lbpRaisingTokens: [
'0xdfcea9088c8a88a76ff74892c1457c17dfeef9c1',
Expand Down
6 changes: 6 additions & 0 deletions test/linear.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ describe('linear pool tests', () => {
const config = {
chainId: 99,
weth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
connectingTokens: [
{
symbol: 'weth',
address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
},
],
vault: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
};
it('getPathsUsingLinearPool return empty paths', () => {
Expand Down
Loading

0 comments on commit c6b4050

Please sign in to comment.