Skip to content

Commit 0cb5dfe

Browse files
feat(payment-detection): option to use TheGraph Network with API key (#1610)
1 parent e6f64ba commit 0cb5dfe

File tree

2 files changed

+133
-27
lines changed

2 files changed

+133
-27
lines changed

packages/payment-detection/src/thegraph/client.ts

Lines changed: 87 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
import { CurrencyTypes } from '@requestnetwork/types';
33
import { NearChains } from '@requestnetwork/currency';
44
import { GraphQLClient } from 'graphql-request';
5-
import { Block_Height, Maybe, getSdk } from './generated/graphql';
5+
import { Block_Height, getSdk, Maybe } from './generated/graphql';
66
import { getSdk as getNearSdk } from './generated/graphql-near';
77
import { RequestConfig } from 'graphql-request/src/types';
88

99
const THE_GRAPH_STUDIO_URL =
1010
'https://api.studio.thegraph.com/query/67444/request-payments-$NETWORK/version/latest';
1111

12+
const THE_GRAPH_EXPLORER_URL =
13+
'https://gateway.thegraph.com/api/$API_KEY/subgraphs/id/$SUBGRAPH_ID';
14+
1215
const THE_GRAPH_ALCHEMY_URL =
1316
'https://subgraph.satsuma-prod.com/e2e4905ab7c8/request-network--434873/request-payments-$NETWORK/api';
1417

@@ -21,6 +24,39 @@ const THE_GRAPH_URL_MANTLE =
2124
const THE_GRAPH_URL_CORE =
2225
'https://thegraph.coredao.org/subgraphs/name/requestnetwork/request-payments-core';
2326

27+
const THE_GRAPH_ALCHEMY_CHAINS: CurrencyTypes.ChainName[] = [
28+
'arbitrum-one',
29+
'avalanche',
30+
'base',
31+
'bsc',
32+
'fantom',
33+
'mainnet',
34+
'matic',
35+
'sepolia',
36+
'optimism',
37+
'zksyncera',
38+
];
39+
40+
const THE_GRAPH_EXPLORER_SUBGRAPH_ID: Partial<Record<CurrencyTypes.ChainName, string>> = {
41+
['arbitrum-one']: '3MtDdHbzvBVNBpzUTYXGuDDLgTd1b8bPYwoH1Hdssgp9',
42+
avalanche: 'A27V4PeZdKHeyuBkehdBJN8cxNtzVpXvYoqkjHUHRCFp',
43+
base: 'CcTtKy6BustyyVZ5XvFD4nLnbkgMBT1vcAEJ3sAx6bRe',
44+
bsc: '4PScFUi3CFDbop9XzT6gCDtD4RR8kRzyrzSjrHoXHZBt',
45+
celo: '5ts3PHjMcH2skCgKtvLLNE64WLjbhE5ipruvEcgqyZqC',
46+
fantom: '6AwmiYo5eY36W526ZDQeAkNBjXjXKYcMLYyYHeM67xAb',
47+
fuse: 'EHSpUBa7PAewX7WsaU2jbCKowF5it56yStr6Zgf8aDtx',
48+
mainnet: '5mXPGZRC2Caynh4NyVrTK72DAGB9dfcKmLsnxYWHQ9nd',
49+
matic: 'DPpU1WMxk2Z4H2TAqgwGbVBGpabjbC1972Mynak5jSuR',
50+
moonbeam: '4Jo3DwA25zyVLeDhyi7cks52dNrkVCWWhQJzm1hKnCfj',
51+
sepolia: '6e8Dcwt3cvsgNU3JYBtRQQ9Sj4P9VVVnXaPjJ3jUpYpY',
52+
sonic: 'CQbtmuANYsChysuXTk9jWP3BD4ArncARVVw1b8JpHiTk',
53+
near: '9yEg3h46CZiv4VuSqo1erMMBx5sHxRuW5Ai2V8goSpQL',
54+
['near-testnet']: 'AusVyfndonsMVFrVzckuENLqx8t6kcXuxn6C6VbSGd7M',
55+
optimism: '525fra79nG3Z1w8aPZh3nHsH5zCVetrVmceB1hKcTrTX',
56+
xdai: '2UAW7B94eeeqaL5qUM5FDzTWJcmgA6ta1RcWMo3XuLmU',
57+
zksyncera: 'HJNZW9vRSGXrcCVyQMdNKxxuLKeZcV6yMjTCyY6T2oon',
58+
};
59+
2460
// NB: the GraphQL client is automatically generated based on files present in ./queries,
2561
// using graphql-codegen.
2662
// To generate types, run `yarn codegen`, then open the generated files so that the code editor picks up the changes.
@@ -44,6 +80,8 @@ export type TheGraphQueryOptions = {
4480
export type TheGraphClientOptions = RequestConfig & {
4581
/** constraint to select indexers that have at least parsed this block */
4682
minIndexedBlock?: number | undefined;
83+
/** API key for accessing subgraphs hosted on TheGraph Explorer */
84+
theGraphExplorerApiKey?: string;
4785
};
4886

4987
/** Splits the input options into "client options" to pass to the SDK, and "query options" to use in queries */
@@ -55,7 +93,13 @@ const extractClientOptions = (
5593

5694
// build query options
5795
const queryOptions: TheGraphQueryOptions = {};
58-
const { minIndexedBlock, ...clientOptions } = optionsObject;
96+
const {
97+
minIndexedBlock,
98+
// ignore theGraphExplorerApiKey, it should not be part of clientOptions
99+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
100+
theGraphExplorerApiKey: _theGraphExplorerApiKey,
101+
...clientOptions
102+
} = optionsObject;
59103
if (minIndexedBlock) {
60104
queryOptions.blockFilter = { number_gte: minIndexedBlock };
61105
} else if (url.match(/^https:\/\/gateway-\w+\.network\.thegraph\.com\//)) {
@@ -90,33 +134,49 @@ export const getTheGraphNearClient = (url: string, options?: TheGraphClientOptio
90134
return sdk;
91135
};
92136

137+
export const defaultGetTheGraphClientUrl = (
138+
network: CurrencyTypes.ChainName,
139+
options?: TheGraphClientOptions,
140+
) => {
141+
const chain = network.replace('aurora', 'near') as CurrencyTypes.ChainName;
142+
const theGraphExplorerSubgraphId = THE_GRAPH_EXPLORER_SUBGRAPH_ID[chain];
143+
const { theGraphExplorerApiKey } = options || {};
144+
145+
// build URLs
146+
const theGraphStudioUrl = THE_GRAPH_STUDIO_URL.replace('$NETWORK', chain);
147+
const theGraphExplorerUrl = THE_GRAPH_EXPLORER_URL.replace(
148+
'$API_KEY',
149+
theGraphExplorerApiKey || '',
150+
).replace('$SUBGRAPH_ID', theGraphExplorerSubgraphId || '');
151+
const theGraphAlchemyUrl = THE_GRAPH_ALCHEMY_URL.replace('$NETWORK', chain);
152+
153+
const shouldUseTheGraphExplorer = !!theGraphExplorerApiKey && !!theGraphExplorerSubgraphId;
154+
const shouldUseAlchemy = THE_GRAPH_ALCHEMY_CHAINS.includes(chain);
155+
156+
switch (true) {
157+
case chain === 'private':
158+
return;
159+
case chain === 'mantle':
160+
return THE_GRAPH_URL_MANTLE;
161+
case chain === 'mantle-testnet':
162+
return THE_GRAPH_URL_MANTLE_TESTNET;
163+
case chain === 'core':
164+
return THE_GRAPH_URL_CORE;
165+
default:
166+
return shouldUseTheGraphExplorer
167+
? theGraphExplorerUrl
168+
: shouldUseAlchemy
169+
? theGraphAlchemyUrl
170+
: theGraphStudioUrl;
171+
}
172+
};
173+
93174
export const defaultGetTheGraphClient = (
94175
network: CurrencyTypes.ChainName,
95176
options?: TheGraphClientOptions,
96177
) => {
97-
return network === 'private'
98-
? undefined
99-
: NearChains.isChainSupported(network)
100-
? getTheGraphNearClient(
101-
`${THE_GRAPH_STUDIO_URL.replace('$NETWORK', network.replace('aurora', 'near'))}`,
102-
options,
103-
)
104-
: network === 'mantle'
105-
? getTheGraphEvmClient(THE_GRAPH_URL_MANTLE, options)
106-
: network === 'mantle-testnet'
107-
? getTheGraphEvmClient(THE_GRAPH_URL_MANTLE_TESTNET, options)
108-
: network === 'core'
109-
? getTheGraphEvmClient(THE_GRAPH_URL_CORE, options)
110-
: network === 'mainnet' ||
111-
network === 'sepolia' ||
112-
network === 'matic' ||
113-
network === 'bsc' ||
114-
network === 'optimism' ||
115-
network === 'arbitrum-one' ||
116-
network === 'base' ||
117-
network === 'zksyncera' ||
118-
network === 'avalanche' ||
119-
network === 'fantom'
120-
? getTheGraphEvmClient(`${THE_GRAPH_ALCHEMY_URL.replace('$NETWORK', network)}`, options)
121-
: getTheGraphEvmClient(`${THE_GRAPH_STUDIO_URL.replace('$NETWORK', network)}`, options);
178+
const url = defaultGetTheGraphClientUrl(network, options);
179+
if (!url) return;
180+
if (NearChains.isChainSupported(network)) return getTheGraphNearClient(url, options);
181+
return getTheGraphEvmClient(url, options);
122182
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { defaultGetTheGraphClientUrl } from '../../src/thegraph';
2+
3+
describe('defaultGetTheGraphClientUrl', () => {
4+
it('should build the correct URL for network supported by Alchemy', () => {
5+
const url = defaultGetTheGraphClientUrl('base');
6+
expect(url).toBe(
7+
'https://subgraph.satsuma-prod.com/e2e4905ab7c8/request-network--434873/request-payments-base/api',
8+
);
9+
});
10+
it('should build the correct URL when using TheGraph Explorer API key', () => {
11+
const url = defaultGetTheGraphClientUrl('base', { theGraphExplorerApiKey: 'test' });
12+
expect(url).toBe(
13+
'https://gateway.thegraph.com/api/test/subgraphs/id/CcTtKy6BustyyVZ5XvFD4nLnbkgMBT1vcAEJ3sAx6bRe',
14+
);
15+
});
16+
it('should build the correct URL for Mantle', () => {
17+
const url = defaultGetTheGraphClientUrl('mantle');
18+
expect(url).toBe(
19+
'https://subgraph-api.mantle.xyz/api/public/555176e7-c1f4-49f9-9180-f2f03538b039/subgraphs/requestnetwork/request-payments-mantle/v0.1.0/gn',
20+
);
21+
});
22+
it('should build the correct URL for Near', () => {
23+
const urlNear = defaultGetTheGraphClientUrl('near');
24+
expect(urlNear).toBe(
25+
'https://api.studio.thegraph.com/query/67444/request-payments-near/version/latest',
26+
);
27+
const urlNearTestnet = defaultGetTheGraphClientUrl('near-testnet');
28+
expect(urlNearTestnet).toBe(
29+
'https://api.studio.thegraph.com/query/67444/request-payments-near-testnet/version/latest',
30+
);
31+
const urlAurora = defaultGetTheGraphClientUrl('aurora');
32+
expect(urlAurora).toBe(
33+
'https://api.studio.thegraph.com/query/67444/request-payments-near/version/latest',
34+
);
35+
const urlAuroraTestnet = defaultGetTheGraphClientUrl('aurora-testnet');
36+
expect(urlAuroraTestnet).toBe(
37+
'https://api.studio.thegraph.com/query/67444/request-payments-near-testnet/version/latest',
38+
);
39+
});
40+
it('should build the correct URL for Near with TheGraph Explorer API key', () => {
41+
const url = defaultGetTheGraphClientUrl('near', { theGraphExplorerApiKey: 'test' });
42+
expect(url).toBe(
43+
'https://gateway.thegraph.com/api/test/subgraphs/id/9yEg3h46CZiv4VuSqo1erMMBx5sHxRuW5Ai2V8goSpQL',
44+
);
45+
});
46+
});

0 commit comments

Comments
 (0)