Skip to content

Commit a6ad261

Browse files
committed
gmx v2 swap graph, fix
1 parent f72d1d6 commit a6ad261

File tree

1 file changed

+127
-78
lines changed

1 file changed

+127
-78
lines changed

src/adaptors/gmx-v2-perps/index.js

Lines changed: 127 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ const { sub } = require('date-fns');
99

1010
const { default: BigNumber } = require('bignumber.js');
1111

12+
const MARKETS_PAGE_SIZE = 100;
13+
1214
const SUBGRAPH_URL = {
13-
arbitrum:
14-
'https://subgraph.satsuma-prod.com/3b2ced13c8d9/gmx/synthetics-arbitrum-stats/api',
15-
avax: 'https://subgraph.satsuma-prod.com/3b2ced13c8d9/gmx/synthetics-avalanche-stats/api',
15+
arbitrum: 'https://gmx.squids.live/gmx-synthetics-arbitrum:prod/api/graphql',
16+
avax: 'https://gmx.squids.live/gmx-synthetics-avalanche:prod/api/graphql',
1617
};
1718

1819
const CONTRACTS = {
@@ -52,45 +53,43 @@ const MAX_PNL_FACTOR_FOR_DEPOSITS_KEY = hashString(
5253
);
5354

5455
const marketsQuery = gql`
55-
query M {
56-
marketInfos {
56+
query M($limit: Int!, $offset: Int!) {
57+
marketInfos(limit: $limit, offset: $offset) {
5758
id
58-
marketToken
59-
indexToken
60-
longToken
61-
shortToken
59+
marketTokenAddress
60+
indexTokenAddress
61+
longTokenAddress
62+
shortTokenAddress
6263
}
6364
}
6465
`;
6566

6667
const marketFeesQuery = (marketAddress) => {
6768
return `
68-
_${marketAddress}_lte_start_of_period_: collectedMarketFeesInfos(
69-
orderBy:timestampGroup
70-
orderDirection:desc
71-
where: {
72-
marketAddress: "${marketAddress.toLowerCase()}",
73-
period: "1h",
74-
timestampGroup_lte: ${Math.floor(
75-
sub(new Date(), { days: 7 }).valueOf() / 1000
76-
)}
77-
},
78-
first: 1
79-
) {
80-
cumulativeFeeUsdPerPoolValue
81-
}
82-
_${marketAddress}_recent: collectedMarketFeesInfos(
83-
orderBy: timestampGroup
84-
orderDirection: desc
85-
where: {
86-
marketAddress: "${marketAddress.toLowerCase()}",
87-
period: "1h"
88-
},
89-
first: 1
90-
) {
91-
cumulativeFeeUsdPerPoolValue
92-
}
93-
`;
69+
_${marketAddress}_lte_start_of_period_: collectedFeesInfos(
70+
orderBy: timestampGroup_DESC
71+
where: {
72+
address_containsInsensitive: "${marketAddress.toLowerCase()}"
73+
period_eq: "1h"
74+
timestampGroup_lte: ${Math.floor(
75+
sub(new Date(), { days: 7 }).valueOf() / 1000
76+
)}
77+
}
78+
limit: 1
79+
) {
80+
cumulativeFeeUsdPerPoolValue
81+
}
82+
_${marketAddress}_recent: collectedFeesInfos(
83+
orderBy: timestampGroup_DESC
84+
where: {
85+
address_containsInsensitive: "${marketAddress.toLowerCase()}"
86+
period_eq: "1h"
87+
}
88+
limit: 1
89+
) {
90+
cumulativeFeeUsdPerPoolValue
91+
}
92+
`;
9493
};
9594

9695
function bigNumberify(n) {
@@ -107,19 +106,40 @@ function expandDecimals(n, decimals) {
107106
}
108107

109108
const getMarkets = async (chain) => {
110-
const { marketInfos } = await request(SUBGRAPH_URL[chain], marketsQuery);
111-
112-
const queryBody = marketInfos.reduce(
113-
(acc, market) => acc + marketFeesQuery(market.id),
114-
''
115-
);
109+
const marketInfos = [];
110+
let offset = 0;
111+
while (true) {
112+
const { marketInfos: batch } = await request(
113+
SUBGRAPH_URL[chain],
114+
marketsQuery,
115+
{ limit: MARKETS_PAGE_SIZE, offset }
116+
);
117+
if (!batch?.length) break;
118+
marketInfos.push(...batch);
119+
if (batch.length < MARKETS_PAGE_SIZE) break;
120+
offset += MARKETS_PAGE_SIZE;
121+
}
116122

117-
const res = await request(
118-
SUBGRAPH_URL[chain],
119-
gql`query M {
123+
if (!marketInfos.length) return [];
124+
125+
const queryBody = marketInfos.reduce((acc, market) => {
126+
const marketAddress = (
127+
market.marketTokenAddress ||
128+
market.id ||
129+
''
130+
).toLowerCase();
131+
if (!marketAddress) return acc;
132+
return acc + marketFeesQuery(marketAddress);
133+
}, '');
134+
135+
const res = queryBody
136+
? await request(
137+
SUBGRAPH_URL[chain],
138+
gql`query M {
120139
${queryBody}
121140
}`
122-
);
141+
)
142+
: {};
123143

124144
const tickers = (
125145
await fetch(TICKERS_URL[chain]).then((r) => r.json())
@@ -137,16 +157,32 @@ const getMarkets = async (chain) => {
137157

138158
const marketResults = {};
139159

140-
const marketCall = await Promise.all(
160+
await Promise.all(
141161
marketInfos.map(async (market) => {
162+
const {
163+
marketTokenAddress,
164+
longTokenAddress,
165+
shortTokenAddress,
166+
indexTokenAddress,
167+
} = market;
168+
169+
if (!marketTokenAddress || !longTokenAddress || !shortTokenAddress)
170+
return null;
171+
142172
const marketProps = {
143-
marketToken: market.marketToken,
144-
longToken: market.longToken,
145-
shortToken: market.shortToken,
146-
indexToken: market.indexToken,
173+
marketToken: marketTokenAddress,
174+
longToken: longTokenAddress,
175+
shortToken: shortTokenAddress,
176+
indexToken: indexTokenAddress,
147177
};
148178

149-
if (!tickers[market.longToken?.toLowerCase()]) return null;
179+
const indexTicker =
180+
tickers[indexTokenAddress?.toLowerCase()] || tickers[WETH[chain]];
181+
const longTicker = tickers[longTokenAddress?.toLowerCase()];
182+
const shortTicker = tickers[shortTokenAddress?.toLowerCase()];
183+
184+
if (!indexTicker || !longTicker || !shortTicker) return null;
185+
150186
const min = (
151187
await sdk.api.abi.call({
152188
target: CONTRACTS[chain].syntheticsReader, // synthetix,
@@ -155,9 +191,9 @@ const getMarkets = async (chain) => {
155191
params: [
156192
CONTRACTS[chain].dataStore, //datastore
157193
marketProps,
158-
tickers[market.indexToken?.toLowerCase()] || tickers[WETH[chain]],
159-
tickers[market.longToken?.toLowerCase()],
160-
tickers[market.shortToken?.toLowerCase()],
194+
indexTicker,
195+
longTicker,
196+
shortTicker,
161197
MAX_PNL_FACTOR_FOR_DEPOSITS_KEY,
162198
false,
163199
],
@@ -171,23 +207,28 @@ const getMarkets = async (chain) => {
171207
params: [
172208
CONTRACTS[chain].dataStore, //datastore
173209
marketProps,
174-
tickers[market.indexToken?.toLowerCase()] || tickers[WETH[chain]],
175-
tickers[market.longToken?.toLowerCase()],
176-
tickers[market.shortToken?.toLowerCase()],
210+
indexTicker,
211+
longTicker,
212+
shortTicker,
177213
MAX_PNL_FACTOR_FOR_DEPOSITS_KEY,
178214
true,
179215
],
180216
})
181217
).output;
182218

183219
const supply = await sdk.api.erc20.totalSupply({
184-
target: market.marketToken,
220+
target: marketTokenAddress,
185221
chain: chain,
186222
});
187223

188-
const tvl = ((supply.output / 1e18) * min[0]) / 1e30;
224+
const tvl = BigNumber(supply.output || 0)
225+
.div(1e18)
226+
.times(BigNumber(min[0] || 0))
227+
.div(1e30)
228+
.toNumber();
229+
if (!Number.isFinite(tvl)) return null;
189230

190-
marketResults[market.marketToken.toLowerCase()] = {
231+
marketResults[marketTokenAddress.toLowerCase()] = {
191232
totalSupply: supply.output,
192233
minPrice: min[0],
193234
maxPrice: max[0],
@@ -218,19 +259,25 @@ const getMarkets = async (chain) => {
218259
);
219260
}
220261

221-
const marketTokensAPRData = marketInfos.map((market, i) => {
222-
const marketAddress = market.id;
223-
const marketToken = market.marketToken.toLowerCase();
224-
const marketData = marketResults[marketToken];
225-
const lteStartOfPeriodFees = res[`_${marketAddress}_lte_start_of_period_`];
226-
const recentFees = res[`_${marketAddress}_recent`];
262+
const marketTokensAPRData = marketInfos.map((market) => {
263+
const marketToken = market.marketTokenAddress;
264+
const marketAddress = marketToken?.toLowerCase();
265+
if (!marketAddress) return;
266+
267+
const marketData = marketResults[marketAddress];
268+
if (!marketData) return;
269+
270+
const lteStartOfPeriodFees =
271+
res[`_${marketAddress}_lte_start_of_period_`] || [];
272+
const recentFees = res[`_${marketAddress}_recent`] || [];
227273

228274
const poolValue1 =
229-
bigNumberify(lteStartOfPeriodFees[0]?.cumulativeFeeUsdPerPoolValue) ??
230-
BigNumber.from(0);
231-
const poolValue2 = bigNumberify(
232-
recentFees[0]?.cumulativeFeeUsdPerPoolValue
233-
);
275+
bigNumberify(lteStartOfPeriodFees[0]?.cumulativeFeeUsdPerPoolValue) ||
276+
BigNumber(0);
277+
const poolValue2 =
278+
bigNumberify(recentFees[0]?.cumulativeFeeUsdPerPoolValue) || BigNumber(0);
279+
280+
if (poolValue1.isNaN() || poolValue2.isNaN()) return;
234281

235282
if (poolValue2) {
236283
const incomePercentageForPeriod = poolValue2.minus(poolValue1);
@@ -239,16 +286,19 @@ const getMarkets = async (chain) => {
239286
const apr = incomePercentageForPeriod
240287
.times(yearMultiplier)
241288
.div(expandDecimals(1, 26));
289+
const apyBase = apr.div(100).toNumber();
290+
if (!Number.isFinite(apyBase)) return;
242291

243292
const longSymbol =
244-
tickers[market.longToken.toLowerCase()]?.data?.tokenSymbol;
293+
tickers[market.longTokenAddress.toLowerCase()]?.data?.tokenSymbol;
245294
const shortSymbol =
246-
tickers[market.shortToken.toLowerCase()]?.data?.tokenSymbol;
295+
tickers[market.shortTokenAddress.toLowerCase()]?.data?.tokenSymbol;
247296

248-
const tvlUsd = parseFloat(marketData?.tvl);
297+
const tvlUsd = Number(marketData?.tvl);
298+
if (!Number.isFinite(tvlUsd)) return;
249299

250300
let apyReward;
251-
if (rewards) {
301+
if (rewards && tvlUsd > 0) {
252302
const rewardPerYear =
253303
(rewards[marketAddress.toLowerCase()] / 1e18) *
254304
52 *
@@ -263,16 +313,15 @@ const getMarkets = async (chain) => {
263313
project: 'gmx-v2-perps',
264314
symbol: `${longSymbol}-${shortSymbol}`,
265315
tvlUsd,
266-
apyBase: apr.toString() / 100,
316+
apyBase,
267317
apyReward: apyReward ?? null,
268-
underlyingTokens: [market.longToken, market.shortToken],
318+
underlyingTokens: [market.longTokenAddress, market.shortTokenAddress],
269319
rewardTokens: apyReward > 0 ? [ARB] : [],
270320
};
271321
} else {
272322
return;
273323
}
274324
});
275-
276325
return marketTokensAPRData.filter(Boolean).filter((i) => utils.keepFinite(i));
277326
};
278327

0 commit comments

Comments
 (0)