Skip to content

Commit

Permalink
Merge branch 'feat/subgraph-resiliancy' into v3/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffywu committed Apr 11, 2024
2 parents 4f10ada + f6e29cf commit b9ca116
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 45 deletions.
4 changes: 3 additions & 1 deletion packages/core-entities/src/base/base-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export abstract class BaseRegistry<T> {
private _intervalMS = new Map<Network, number>();
private _intervalSubscription = new Map<Network, Subscription>();

protected defaultFreshnessIntervals = 1;

/** Emits a network when a network has completed its first refresh */
protected networkRegistered = new BehaviorSubject<Network | null>(null);

Expand Down Expand Up @@ -285,7 +287,7 @@ export abstract class BaseRegistry<T> {
public getLatestFromSubject(
network: Network,
key: string,
checkFreshness = 1
checkFreshness = this.defaultFreshnessIntervals
) {
// Don't check freshness if no interval is set
const intervalMS = this._intervalMS.get(network);
Expand Down
21 changes: 13 additions & 8 deletions packages/core-entities/src/client/account-registry-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,19 @@ export class AccountRegistryClient extends ClientRegistry<AccountDefinition> {
address: string,
account: AccountDefinition
) {
const [txnHistory, balanceStatements] = await Promise.all([
this.fetchTransactionHistory(network, address),
this.fetchBalanceStatements(network, address),
]);

// Set the balance statement and txn history
account.balanceStatement = balanceStatements.finalResults[address];
account.accountHistory = txnHistory.finalResults[address];
try {
const [txnHistory, balanceStatements] = await Promise.all([
this.fetchTransactionHistory(network, address),
this.fetchBalanceStatements(network, address),
]);

// Set the balance statement and txn history
account.balanceStatement = balanceStatements.finalResults[address];
account.accountHistory = txnHistory.finalResults[address];
} catch (e) {
account.balanceStatement = undefined;
account.accountHistory = undefined;
}

return account;
}
Expand Down
10 changes: 8 additions & 2 deletions packages/core-entities/src/client/client-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ export abstract class ClientRegistry<T> extends BaseRegistry<T> {
return value;
}

protected async _fetch<T>(network: Network, urlSuffix?: string): Promise<T> {
public static async fetch<T>(
cacheUrl: string,
urlSuffix?: string
): Promise<T> {
const _fetch = USE_CROSS_FETCH ? crossFetch : fetch;
const cacheUrl = this.cacheURL(network);
const result = await _fetch(
urlSuffix ? `${cacheUrl}/${urlSuffix}` : cacheUrl
);
Expand All @@ -61,6 +63,10 @@ export abstract class ClientRegistry<T> extends BaseRegistry<T> {
return JSON.parse(body, ClientRegistry.reviver);
}

protected async _fetch<T>(network: Network, urlSuffix?: string): Promise<T> {
return ClientRegistry.fetch(this.cacheURL(network), urlSuffix);
}

protected async _refresh(
network: Network,
blockNumber?: number
Expand Down
3 changes: 3 additions & 0 deletions packages/core-entities/src/client/configuration-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export class ConfigurationClient extends ClientRegistry<AllConfigurationQuery> {

constructor(cacheHostname: string) {
super(cacheHostname);
// Don't enforce freshness intervals if the subgraph happens to go down. Configuration
// data does not change very often
this.defaultFreshnessIntervals = 0;

// Ensures that all subject keys get registered
this.subjectRegistered.asObservable().subscribe((s) => {
Expand Down
7 changes: 7 additions & 0 deletions packages/core-entities/src/client/token-registry-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import { Routes } from '../server';
import { TokenType } from '../.graphclient';

export class TokenRegistryClient extends ClientRegistry<TokenDefinition> {
constructor(cacheHostname: string) {
super(cacheHostname);
// Don't enforce freshness intervals if the subgraph happens to go down. Token
// data does not change very often
this.defaultFreshnessIntervals = 0;
}

protected cachePath() {
return Routes.Tokens;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core-entities/src/config/whitelisted-vaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const whitelistedVaults = (network: Network) => {
// "[USDC]:GHO_USDT_xUSDC":
'0xeeb885af7c8075aa3b93e2f95e1c0bd51c758f91',
// "[rETH]:xrETH_weETH"
// '0x32d82a1c8618c7be7fe85b2f1c44357a871d52d1',
'0x32d82a1c8618c7be7fe85b2f1c44357a871d52d1',
// "[ETH]:ezETH_xWETH":
'0x914255c0c289aea36e378ebb5e28293b5ed278ca',
];
Expand Down
79 changes: 46 additions & 33 deletions packages/core-entities/src/server/oracle-registry-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ import {
ZERO_ADDRESS,
} from '@notional-finance/util';
import { BigNumber, Contract } from 'ethers';
import { OracleDefinition, CacheSchema } from '..';
import { OracleDefinition, CacheSchema, ClientRegistry } from '..';
import { loadGraphClientDeferred, ServerRegistry } from './server-registry';
import { fiatOracles } from '../config/fiat-config';
import { TypedDocumentNode } from '@apollo/client/core';
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
import { AllOraclesQuery } from '../.graphclient';
import { vaultOverrides } from './vault-overrides';

// NOTE: this is currently hardcoded because we cannot access the worker
// process environment directly here.
const NX_DATA_URL = 'https://data-dev.notional.finance';

export class OracleRegistryServer extends ServerRegistry<OracleDefinition> {
public override hasAllNetwork(): boolean {
return true;
Expand All @@ -48,39 +52,48 @@ export class OracleRegistryServer extends ServerRegistry<OracleDefinition> {
const { AllOraclesDocument, AllOraclesByBlockDocument } =
await loadGraphClientDeferred();

return this._fetchUsingGraph(
network,
(blockNumber !== undefined
? AllOraclesByBlockDocument
: AllOraclesDocument) as TypedDocumentNode<AllOraclesQuery, unknown>,
(r) => {
return r.oracles.reduce((obj, v) => {
obj[v.id] = {
id: v.id,
oracleAddress: v.oracleAddress as string,
network,
oracleType: v.oracleType,
base: v.base.id,
baseDecimals: v.base.decimals,
quote: v.quote.id,
quoteCurrencyId: v.quote.currencyId,
decimals: v.decimals,
latestRate: {
rate: BigNumber.from(v.latestRate),
timestamp: v.lastUpdateTimestamp,
blockNumber: blockNumber || v.lastUpdateBlockNumber,
},
};
try {
return this._fetchUsingGraph(
network,
(blockNumber !== undefined
? AllOraclesByBlockDocument
: AllOraclesDocument) as TypedDocumentNode<AllOraclesQuery, unknown>,
(r) => {
return r.oracles.reduce((obj, v) => {
obj[v.id] = {
id: v.id,
oracleAddress: v.oracleAddress as string,
network,
oracleType: v.oracleType,
base: v.base.id,
baseDecimals: v.base.decimals,
quote: v.quote.id,
quoteCurrencyId: v.quote.currencyId,
decimals: v.decimals,
latestRate: {
rate: BigNumber.from(v.latestRate),
timestamp: v.lastUpdateTimestamp,
blockNumber: blockNumber || v.lastUpdateBlockNumber,
},
};

return obj;
}, {} as Record<string, OracleDefinition>);
},
{
blockNumber,
skip: 0,
},
'oracles'
);
return obj;
}, {} as Record<string, OracleDefinition>);
},
{
blockNumber,
skip: 0,
},
'oracles'
);
} catch (e) {
console.error(e);
// If the subgraph has failed, get the previous cache schema and return it, we still
// want to continue to update the latest rates
return ClientRegistry.fetch<CacheSchema<OracleDefinition>>(
`${NX_DATA_URL}/${network}/oracles`
);
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/notionable/src/global/global-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export interface NotionalError {

/** Account state is written on a per network basis */
export interface AccountState {
isSubgraphDown: boolean;
isAccountReady: boolean;
portfolioLiquidationPrices?: ReturnType<
AccountRiskProfile['getAllLiquidationPrices']
Expand Down
3 changes: 3 additions & 0 deletions packages/notionable/src/global/sagas/on-wallet-connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ function onAccountUpdates$(global$: Observable<GlobalState>) {
const vaultHoldings = calculateVaultHoldings(a);

n[a.network] = {
isSubgraphDown:
a.balanceStatement === undefined &&
a.accountHistory === undefined,
isAccountReady: true,
riskProfile,
accountDefinition: a,
Expand Down

0 comments on commit b9ca116

Please sign in to comment.