Skip to content

Commit

Permalink
Merge pull request #583 from balancer/add-pools-refresh
Browse files Browse the repository at this point in the history
feat: Add a refresh method on pools that should efficiently refresh a…
  • Loading branch information
johngrantuk authored Jul 5, 2024
2 parents f94c6e9 + 5de2ba8 commit 3a39347
Show file tree
Hide file tree
Showing 10 changed files with 542 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// yarn test:only ./src/modules/data/liquidity-gauges/multicall.spec.ts
import { expect } from 'chai';
import { JsonRpcProvider } from '@ethersproject/providers';
import { Zero } from '@ethersproject/constants';
Expand Down Expand Up @@ -65,7 +66,7 @@ describe('Liquidity gauge multicall', () => {
const fetcher = new LiquidityGaugesMulticallRepository(multicall, 1);

const gauges = new LiquidityGaugesSubgraphRepository(
'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gauges'
'https://api.studio.thegraph.com/query/75376/balancer-gauges/version/latest'
);

let gaugeAddresses: string[];
Expand Down
42 changes: 39 additions & 3 deletions balancer-js/src/modules/data/pool/subgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class PoolsSubgraphRepository
public skip = 0;
private blockHeight: undefined | (() => Promise<number | undefined>);
private query: GraphQLQuery;
private isCustomQuery: boolean;

/**
* Repository with optional lazy loaded blockHeight
Expand All @@ -60,7 +61,7 @@ export class PoolsSubgraphRepository
},
},
};

this.isCustomQuery = !!options.query;
const args = Object.assign({}, options.query?.args || defaultArgs);
const attrs = Object.assign({}, options.query?.attrs || {});

Expand Down Expand Up @@ -121,8 +122,43 @@ export class PoolsSubgraphRepository
return pools.map((pool) => mapType(pool, this.chainId));
}

async find(id: string): Promise<Pool | undefined> {
return await this.findBy('id', id);
/**
* Find pool data for id
* @param id
* @param refresh If true will refetch from SG and update cache
* @returns
*/
async find(id: string, refresh = false): Promise<Pool | undefined> {
if (this.isCustomQuery) return await this.findBy('id', id);
// If we're not refreshing and the pool exists in caches then return
if (!refresh && this.pools) {
const cachedPool = (await this.pools).find((pool) => pool.id === id);
if (cachedPool) return cachedPool;
}

// Fetch pool data from SG, update cache and return
const logger = Logger.getInstance();

// SG fetch
logger.time(`fetching pool ${id}`);
const poolQuery = await this.client.Pool({ id });
logger.timeEnd(`fetching pool ${id}`);

if (!poolQuery.pool) return undefined;

const pool = mapType(poolQuery.pool, this.chainId);
// If the pool is already cached, replace it with the new one
logger.time(`updating cache`);
const pools = await this.pools;
if (pools) {
const index = pools.findIndex((p) => p.address === pool.address);
if (index !== -1) {
this.pools = Promise.resolve([...pools.splice(index, 1), pool]);
} else this.pools = Promise.resolve([...pools, pool]);
} else this.pools = Promise.resolve([pool]);
logger.timeEnd(`updating cache`);

return pool;
}

async findBy(param: PoolAttribute, value: string): Promise<Pool | undefined> {
Expand Down
2 changes: 1 addition & 1 deletion balancer-js/src/modules/data/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export * from './pool-shares/types';
export * from './gauge-shares/types';

export interface Findable<T, P = string, V = any> {
find: (id: string) => Promise<T | undefined>;
find: (id: string, refresh?: boolean) => Promise<T | undefined>;
findBy: (attribute: P, value: V) => Promise<T | undefined>;
}

Expand Down
3 changes: 2 additions & 1 deletion balancer-js/src/modules/pools/apr/apr.integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const usdStable =
const auraBALveBAL =
'0x3dd0843a028c86e0b760b1a76929d1c5ef93a2dd000200000000000000000249';

describe('APR tests', () => {
// APRs are offered via API now
describe.skip('APR tests', () => {
describe('pool with yield tokens', () => {
it('has tokenAprs', async () => {
const pool = await pools.find(ethStEth);
Expand Down
12 changes: 12 additions & 0 deletions balancer-js/src/modules/pools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,18 @@ export class Pools implements Findable<PoolWithMethods> {
return this.repositories.pools;
}

/**
* Fetches new data from subgraph for pool
* (Will update PoolsSubgraphRepository cache)
* @param pool
* @returns
*/
async refresh(poolId: string): Promise<PoolWithMethods | undefined> {
const poolRefreshed = await this.repositories.pools.find(poolId, true);
if (!poolRefreshed) return poolRefreshed;
return Pools.wrap(poolRefreshed, this.networkConfig);
}

/**
* Calculates APR on any pool data
*
Expand Down
8 changes: 4 additions & 4 deletions balancer-js/src/modules/subgraph/codegen.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
overwrite: true
generates:
src/modules/subgraph/generated/balancer-subgraph-types.ts:
schema: ${BALANCER_SUBGRAPH_URL:https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2}
schema: ${BALANCER_SUBGRAPH_URL:https://api.studio.thegraph.com/query/75376/balancer-v2/version/latest}
documents: 'src/modules/subgraph/balancer-v2/**/*.graphql'
plugins:
- typescript
Expand All @@ -13,11 +13,11 @@ generates:
Bytes: string
BigDecimal: string
src/modules/subgraph/generated/balancer-subgraph-schema.graphql:
schema: ${BALANCER_SUBGRAPH_URL:https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2}
schema: ${BALANCER_SUBGRAPH_URL:https://api.studio.thegraph.com/query/75376/balancer-v2/version/latest}
plugins:
- schema-ast
src/modules/subgraph/generated/balancer-gauges.ts:
schema: ${BALANCER_GAUGES_URL:https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gauges}
schema: ${BALANCER_GAUGES_URL:https://api.studio.thegraph.com/query/75376/balancer-gauges/version/latest}
documents: 'src/modules/subgraph/balancer-gauges/**/*.graphql'
plugins:
- typescript
Expand All @@ -31,7 +31,7 @@ generates:
namingConvention:
enumValues: keep
src/modules/subgraph/generated/balancer-gauges.graphql:
schema: ${BALANCER_GAUGES_URL:https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gauges}
schema: ${BALANCER_GAUGES_URL:https://api.studio.thegraph.com/query/75376/balancer-gauges/version/latest}
plugins:
- schema-ast
hooks:
Expand Down
94 changes: 94 additions & 0 deletions balancer-js/src/modules/subgraph/generated/balancer-gauges.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ directive @entity on OBJECT
"""Defined a Subgraph ID for an object type"""
directive @subgraphId(id: String!) on OBJECT

enum Aggregation_interval {
day
hour
}

scalar BigDecimal

scalar BigInt
Expand Down Expand Up @@ -99,6 +104,30 @@ enum GaugeFactory_orderBy {
numGauges
}

type GaugeInjector {
""" GaugeInjector contract address """
id: ID!
}

input GaugeInjector_filter {
"""Filter for the block changed event."""
_change_block: BlockChangedFilter
and: [GaugeInjector_filter]
id: ID
id_gt: ID
id_gte: ID
id_in: [ID!]
id_lt: ID
id_lte: ID
id_not: ID
id_not_in: [ID!]
or: [GaugeInjector_filter]
}

enum GaugeInjector_orderBy {
id
}

type GaugeShare {
""" User's balance of gauge deposit tokens """
balance: BigDecimal!
Expand Down Expand Up @@ -1084,6 +1113,34 @@ type Query {
"""
subgraphError: _SubgraphErrorPolicy_! = deny
): GaugeFactory
gaugeInjector(
"""
The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.
"""
block: Block_height
id: ID!

"""
Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.
"""
subgraphError: _SubgraphErrorPolicy_! = deny
): GaugeInjector
gaugeInjectors(
"""
The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.
"""
block: Block_height
first: Int = 100
orderBy: GaugeInjector_orderBy
orderDirection: OrderDirection
skip: Int = 0

"""
Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.
"""
subgraphError: _SubgraphErrorPolicy_! = deny
where: GaugeInjector_filter
): [GaugeInjector!]!
gaugeShare(
"""
The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.
Expand Down Expand Up @@ -1875,6 +1932,34 @@ type Subscription {
"""
subgraphError: _SubgraphErrorPolicy_! = deny
): GaugeFactory
gaugeInjector(
"""
The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.
"""
block: Block_height
id: ID!

"""
Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.
"""
subgraphError: _SubgraphErrorPolicy_! = deny
): GaugeInjector
gaugeInjectors(
"""
The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.
"""
block: Block_height
first: Int = 100
orderBy: GaugeInjector_orderBy
orderDirection: OrderDirection
skip: Int = 0

"""
Set to `allow` to receive data even if the subgraph has skipped over errors while syncing.
"""
subgraphError: _SubgraphErrorPolicy_! = deny
where: GaugeInjector_filter
): [GaugeInjector!]!
gaugeShare(
"""
The block at which the query should be executed. Can either be a `{ hash: Bytes }` value containing a block hash, a `{ number: Int }` containing the block number, or a `{ number_gte: Int }` containing the minimum block number. In the case of `number_gte`, the query will be executed on the latest block only if the subgraph has progressed to or past the minimum block number. Defaults to the latest block when omitted.
Expand Down Expand Up @@ -2257,6 +2342,12 @@ type Subscription {
): [VotingEscrow!]!
}

"""
A string representation of microseconds UNIX timestamp (16 digits)
"""
scalar Timestamp

type User {
""" List of gauge the user has shares """
gaugeShares(first: Int = 100, orderBy: GaugeShare_orderBy, orderDirection: OrderDirection, skip: Int = 0, where: GaugeShare_filter): [GaugeShare!]
Expand Down Expand Up @@ -2504,6 +2595,9 @@ type _Block_ {
"""The block number"""
number: Int!

"""The hash of the parent block"""
parentHash: Bytes

"""Integer representation of the timestamp stored in blocks for the chain"""
timestamp: Int
}
Expand Down
Loading

0 comments on commit 3a39347

Please sign in to comment.