Fix Beethoven X Cache Issue [TKR-486] (#519)

* Replace Beethoven X subgraph url and add a test

* Simplify PoolsCacheMap type

* Make `BalancerV2PoolsCache` optional for Beethoven X

* Update CHANGELOG.json
This commit is contained in:
Kyu 2022-07-26 09:54:05 -07:00 committed by GitHub
parent a5babb9a34
commit 6ca14ed7b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 57 deletions

View File

@ -9,6 +9,10 @@
{
"note": "Add Synthetix support`",
"pr": 518
},
{
"note": "Replace Beethoven X subgraph URL",
"pr": 519
}
]
},

View File

@ -2201,13 +2201,6 @@ export const BALANCER_V2_SUBGRAPH_URL_BY_CHAIN = valueByChainId(
null,
);
export const BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN = valueByChainId<string>(
{
[ChainId.Fantom]: 'https://graph-node.beets-ftm-node.com/subgraphs/name/beethovenx',
},
'https://graph-node.beets-ftm-node.com/subgraphs/name/beethovenx',
);
export const UNISWAPV3_CONFIG_BY_CHAIN_ID = valueByChainId(
{
[ChainId.Mainnet]: {

View File

@ -6,15 +6,15 @@ import { gql, request } from 'graphql-request';
import { DEFAULT_WARNING_LOGGER } from '../../../constants';
import { LogFunction } from '../../../types';
import {
BALANCER_MAX_POOLS_FETCHED,
BALANCER_TOP_POOLS_FETCHED,
BALANCER_V2_SUBGRAPH_URL_BY_CHAIN,
} from '../constants';
import { BALANCER_MAX_POOLS_FETCHED, BALANCER_TOP_POOLS_FETCHED } from '../constants';
import { parsePoolData } from './balancer_sor_v2';
import { CacheValue, PoolsCache } from './pools_cache';
const BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN = new Map<ChainId, string>([
[ChainId.Fantom, 'https://api.thegraph.com/subgraphs/name/beethovenxfi/beethovenx'],
]);
// tslint:disable-next-line:custom-no-magic-numbers
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
@ -29,6 +29,15 @@ interface BalancerPoolResponse {
}
export class BalancerV2PoolsCache extends PoolsCache {
public static createBeethovenXPoolCache(chainId: ChainId): BalancerV2PoolsCache | undefined {
const subgraphUrl = BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN.get(chainId);
if (subgraphUrl === undefined) {
return undefined;
}
return new BalancerV2PoolsCache(subgraphUrl);
}
private static _parseSubgraphPoolData(pool: any, takerToken: string, makerToken: string): Pool {
const tToken = pool.tokens.find((t: any) => t.address === takerToken);
const mToken = pool.tokens.find((t: any) => t.address === makerToken);
@ -50,8 +59,7 @@ export class BalancerV2PoolsCache extends PoolsCache {
}
constructor(
chainId: ChainId,
private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL_BY_CHAIN[chainId]!,
private readonly subgraphUrl: string,
private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED,
private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED,
private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER,
@ -63,19 +71,6 @@ export class BalancerV2PoolsCache extends PoolsCache {
setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2);
}
// protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> {
// try {
// const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools;
// // Sort by maker token balance (descending)
// const pools = parsePoolData(poolData, takerToken, makerToken).sort((a, b) =>
// b.balanceOut.minus(a.balanceOut).toNumber(),
// );
// return pools.length > this.maxPoolsFetched ? pools.slice(0, this.maxPoolsFetched) : pools;
// } catch (err) {
// return [];
// }
// }
protected async _fetchTopPoolsAsync(): Promise<BalancerPoolResponse[]> {
const query = gql`
query fetchTopPools($topPoolsFetched: Int!) {

View File

@ -29,7 +29,6 @@ import {
BANCOR_REGISTRY_BY_CHAIN_ID,
BANCORV3_NETWORK_BY_CHAIN_ID,
BANCORV3_NETWORK_INFO_BY_CHAIN_ID,
BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN,
BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN,
COMPOUND_API_URL_BY_CHAIN_ID,
DODOV1_CONFIG_BY_CHAIN_ID,
@ -57,7 +56,7 @@ import {
} from './constants';
import { getGeistInfoForPair } from './geist_utils';
import { getLiquidityProvidersForPair } from './liquidity_provider_utils';
import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache, PoolsCache } from './pools_cache';
import { BalancerPoolsCache, BalancerV2PoolsCache, CreamPoolsCache } from './pools_cache';
import { BalancerV2SwapInfoCache } from './pools_cache/balancer_v2_utils_new';
import { SamplerContractOperation } from './sampler_contract_operation';
import { SamplerNoOperation } from './sampler_no_operation';
@ -96,7 +95,6 @@ import {
PsmInfo,
ShellFillData,
SourceQuoteOperation,
SourcesWithPoolsCache,
SynthetixFillData,
UniswapV2FillData,
UniswapV3FillData,
@ -115,9 +113,12 @@ export const TWO_HOP_SOURCE_FILTERS = SourceFilters.all().exclude([
*/
export const BATCH_SOURCE_FILTERS = SourceFilters.all().exclude([ERC20BridgeSource.MultiHop, ERC20BridgeSource.Native]);
export type PoolsCacheMap = { [key in Exclude<SourcesWithPoolsCache, ERC20BridgeSource.BalancerV2>]: PoolsCache } & {
export interface PoolsCacheMap {
[ERC20BridgeSource.Balancer]: BalancerPoolsCache;
[ERC20BridgeSource.BalancerV2]: BalancerV2SwapInfoCache | undefined;
};
[ERC20BridgeSource.Beethovenx]: BalancerV2PoolsCache | undefined;
[ERC20BridgeSource.Cream]: CreamPoolsCache;
}
// tslint:disable:no-inferred-empty-object-type no-unbound-method
@ -154,10 +155,7 @@ export class SamplerOperations {
this.poolsCaches = poolsCaches
? poolsCaches
: {
[ERC20BridgeSource.Beethovenx]: new BalancerV2PoolsCache(
chainId,
BEETHOVEN_X_SUBGRAPH_URL_BY_CHAIN[chainId],
),
[ERC20BridgeSource.Beethovenx]: BalancerV2PoolsCache.createBeethovenXPoolCache(chainId),
[ERC20BridgeSource.Balancer]: new BalancerPoolsCache(),
[ERC20BridgeSource.Cream]: new CreamPoolsCache(),
[ERC20BridgeSource.BalancerV2]:
@ -1625,8 +1623,11 @@ export class SamplerOperations {
);
}
case ERC20BridgeSource.Beethovenx: {
const poolIds =
this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
const cache = this.poolsCaches[source];
if (cache === undefined) {
return [];
}
const poolIds = cache.getCachedPoolAddressesForPair(takerToken, makerToken) || [];
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
if (vault === NULL_ADDRESS) {
@ -1984,8 +1985,11 @@ export class SamplerOperations {
);
}
case ERC20BridgeSource.Beethovenx: {
const poolIds =
this.poolsCaches[source].getCachedPoolAddressesForPair(takerToken, makerToken) || [];
const cache = this.poolsCaches[source];
if (cache === undefined) {
return [];
}
const poolIds = cache.getCachedPoolAddressesForPair(takerToken, makerToken) || [];
const vault = BEETHOVEN_X_VAULT_ADDRESS_BY_CHAIN[this.chainId];
if (vault === NULL_ADDRESS) {

View File

@ -108,11 +108,6 @@ export enum ERC20BridgeSource {
// Optimism
Velodrome = 'Velodrome',
}
export type SourcesWithPoolsCache =
| ERC20BridgeSource.Balancer
| ERC20BridgeSource.BalancerV2
| ERC20BridgeSource.Beethovenx
| ERC20BridgeSource.Cream;
// tslint:disable: enum-naming
/**

View File

@ -17,8 +17,6 @@ const expect = chai.expect;
const usdcAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
const daiAddress = '0x6b175474e89094c44da98b954eedeac495271d0f';
const wethAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
const wbtcAddress = '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599';
const balAddress = '0xba100000625a3754423978a60c9317c58a424e3d';
const creamAddress = '0x2ba592f78db6436527729929aaf6c908497cb200';
const timeoutMs = 5000;
@ -43,22 +41,26 @@ describe('Pools Caches for Balancer-based sampling', () => {
[daiAddress, wethAddress],
];
await Promise.all(
// tslint:disable-next-line:promise-function-async
pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
pairs.map(async ([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
);
});
});
describe('BalancerV2PoolsCache', () => {
const cache = new BalancerV2PoolsCache(ChainId.Mainnet);
it('fetches pools', async () => {
it('fetches pools (Beethoven X - Fantom)', async () => {
const cache = BalancerV2PoolsCache.createBeethovenXPoolCache(ChainId.Fantom);
const wftmAddress = '0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83';
const beetsAddress = '0xf24bcf4d1e507740041c9cfd2dddb29585adce1e';
const fantomWethAddress = '0x74b23882a30290451a17c44f4f05243b6b58c76d';
const pairs = [
[wethAddress, wbtcAddress],
[wethAddress, balAddress],
[wftmAddress, beetsAddress],
[wftmAddress, fantomWethAddress],
];
expect(cache).not.null();
await Promise.all(
// tslint:disable-next-line:promise-function-async
pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
pairs.map(async ([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache!, takerToken, makerToken)),
);
});
});
@ -71,8 +73,7 @@ describe('Pools Caches for Balancer-based sampling', () => {
[creamAddress, wethAddress],
];
await Promise.all(
// tslint:disable-next-line:promise-function-async
pairs.map(([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
pairs.map(async ([takerToken, makerToken]) => fetchAndAssertPoolsAsync(cache, takerToken, makerToken)),
);
});
});