Skip to content

Commit 3681e0f

Browse files
committed
sync upstream
2 parents 2981db0 + c7d77ad commit 3681e0f

File tree

18 files changed

+405
-129
lines changed

18 files changed

+405
-129
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"@cosmjs/tendermint-rpc": "^0.32.1",
5656
"@datadog/browser-logs": "^5.23.3",
5757
"@dydxprotocol/v4-client-js": "3.4.0",
58-
"@dydxprotocol/v4-localization": "1.1.367",
58+
"@dydxprotocol/v4-localization": "1.1.371",
5959
"@dydxprotocol/v4-proto": "^7.0.0-dev.0",
6060
"@emotion/is-prop-valid": "^1.3.0",
6161
"@hugocxl/react-to-image": "^0.0.9",

pnpm-lock.yaml

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bonsai/calculators/fills.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ import { weakMapMemoize } from 'reselect';
33

44
import { NUM_PARENT_SUBACCOUNTS } from '@/constants/account';
55
import { EMPTY_ARR } from '@/constants/objects';
6-
import { IndexerFillType } from '@/types/indexer/indexerApiGen';
6+
import {
7+
IndexerFillType,
8+
IndexerOrderSide,
9+
IndexerPositionSide,
10+
} from '@/types/indexer/indexerApiGen';
711
import { IndexerCompositeFillObject } from '@/types/indexer/indexerManual';
812

913
import { assertNever } from '@/lib/assertNever';
10-
import { MustBigNumber } from '@/lib/numbers';
14+
import { MustBigNumber, MustNumber } from '@/lib/numbers';
1115

1216
import { mergeObjects } from '../lib/mergeObjects';
1317
import { SubaccountFill, SubaccountFillType } from '../types/summaryTypes';
@@ -30,6 +34,7 @@ const calculateFill = weakMapMemoize(
3034
...base,
3135
marginMode: (base.subaccountNumber ?? 0) >= NUM_PARENT_SUBACCOUNTS ? 'ISOLATED' : 'CROSS',
3236
type: getFillType(base),
37+
closedPnl: calculateClosedPnl(base),
3338
})
3439
);
3540

@@ -53,3 +58,48 @@ function getFillType({
5358
assertNever(type);
5459
return SubaccountFillType.LIMIT;
5560
}
61+
62+
const calculateClosedPnl = (fill: IndexerCompositeFillObject) => {
63+
const fee = MustNumber(fill.fee ?? '0');
64+
65+
// Old fills are not supported so we show -- instead of 0
66+
if (
67+
fill.positionSideBefore == null ||
68+
fill.positionSizeBefore == null ||
69+
fill.entryPriceBefore == null
70+
) {
71+
return undefined;
72+
}
73+
74+
const positionSizeBefore = parseFloat(fill.positionSizeBefore);
75+
const entryPriceBefore = parseFloat(fill.entryPriceBefore);
76+
77+
// No position before = opening trade, only fees realize
78+
if (positionSizeBefore === 0) {
79+
return -fee;
80+
}
81+
82+
// Check if position is reducing (opposite side)
83+
const isReducing =
84+
(fill.positionSideBefore === IndexerPositionSide.LONG && fill.side === IndexerOrderSide.SELL) ||
85+
(fill.positionSideBefore === IndexerPositionSide.SHORT && fill.side === IndexerOrderSide.BUY);
86+
87+
if (!isReducing) {
88+
// Position increasing (same side), only fees realize
89+
return -fee;
90+
}
91+
92+
const size = MustNumber(fill.size ?? '0');
93+
const price = MustNumber(fill.price ?? '0');
94+
95+
// Position reducing - cap closing amount to actual position size
96+
const closingAmount = Math.min(size, positionSizeBefore);
97+
98+
// Calculate P&L only on the closing portion
99+
const closingPnl =
100+
fill.positionSideBefore === IndexerPositionSide.LONG
101+
? (price - entryPriceBefore) * closingAmount
102+
: (entryPriceBefore - price) * closingAmount;
103+
104+
return closingPnl - fee;
105+
};

src/bonsai/lifecycles/usdcRebalanceLifecycle.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { createSemaphore, SupersededError } from '../lib/semaphore';
1616
import { logBonsaiError, logBonsaiInfo } from '../logs';
1717
import { createValidatorStoreEffect } from '../rest/lib/indexerQueryStoreEffect';
1818
import {
19-
selectTxAuthorizedAccount,
19+
selectTxAuthorizedCloseOnlyAccount,
2020
selectUserHasUsdcGasForTransaction,
2121
} from '../selectors/accountTransaction';
2222

@@ -30,7 +30,7 @@ const INVALIDATION_SLEEP_TIME = timeUnits.second * 10;
3030
export function setUpUsdcRebalanceLifecycle(store: RootStore) {
3131
const balanceAndTransfersSelector = createAppSelector(
3232
[
33-
selectTxAuthorizedAccount,
33+
selectTxAuthorizedCloseOnlyAccount,
3434
selectUserHasUsdcGasForTransaction,
3535
selectShouldAccountRebalanceUsdc,
3636
],

src/bonsai/rest/historicalPnl.ts

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,18 @@ export function useParentSubaccountHistoricalPnls() {
5555
for (let request = 0; request < MAX_REQUESTS; request += 1) {
5656
const thisResult =
5757
// eslint-disable-next-line no-await-in-loop
58-
await indexerClient.account.getParentSubaccountNumberHistoricalPNLsV2(
59-
address,
60-
subaccount,
61-
true,
62-
undefined,
63-
// one second before oldest current result
64-
mapIfPresent(allResults.at(-1), (r) =>
65-
new Date(new Date(r.createdAt).getTime() - timeUnits.second).toISOString()
66-
) ?? undefined
67-
);
58+
await indexerClient.account
59+
.getParentSubaccountNumberHistoricalPNLsV2(
60+
address,
61+
subaccount,
62+
true,
63+
undefined,
64+
// one second before oldest current result
65+
mapIfPresent(allResults.at(-1), (r) =>
66+
new Date(new Date(r.createdAt).getTime() - timeUnits.second).toISOString()
67+
) ?? undefined
68+
)
69+
.catch(() => ({ pnl: [] }));
6870
const typedResult = isIndexerHistoricalPnlResponse(thisResult);
6971

7072
// we discard the final item because the indexer incorrectly computes this datapoint on nearly every request
@@ -93,12 +95,9 @@ export function useParentSubaccountHistoricalPnls() {
9395
const hourlyResults = runFn(async () => {
9496
const result =
9597
// eslint-disable-next-line no-await-in-loop
96-
await indexerClient.account.getParentSubaccountNumberHistoricalPNLsV2(
97-
address,
98-
subaccount,
99-
false,
100-
undefined
101-
);
98+
await indexerClient.account
99+
.getParentSubaccountNumberHistoricalPNLsV2(address, subaccount, false, undefined)
100+
.catch(() => ({ pnl: [] }));
102101
const typedResult = isIndexerHistoricalPnlResponse(result);
103102

104103
// we discard the final item because the indexer incorrectly computes this datapoint on nearly every request

src/bonsai/types/summaryTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ export enum SubaccountFillType {
197197
export type SubaccountFill = Omit<IndexerCompositeFillObject, 'type'> & {
198198
marginMode: MarginMode;
199199
type: SubaccountFillType | undefined;
200+
closedPnl?: number;
200201
};
201202

202203
export type LiveTrade = IndexerWsTradeResponseObject;

src/constants/hiddenMarkets.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
export const HIDDEN_MARKETS = new Set([
2+
'PIPPIN',
3+
'BABYDOGE',
4+
'ID',
5+
'AERGO',
6+
'XYO',
7+
'MOODENG',
8+
'PRIME',
9+
'HOLO',
10+
'TREE',
11+
'PROMPT',
12+
'ES',
13+
'KERNEL',
14+
'TAIKO',
15+
'SIGN',
16+
'LINEA',
17+
'SAFE',
18+
'GOAT',
19+
'ACX',
20+
'ORCA',
21+
'IOTA',
22+
'COOKIE',
23+
'ERA',
24+
'MOG',
25+
'MEW',
26+
'MAGIC',
27+
'ME',
28+
'PROVE',
29+
'LA',
30+
'LPT',
31+
'IOTX',
32+
'NEWT',
33+
'GALA',
34+
'SYRUP',
35+
'IO',
36+
'GMX',
37+
'CETUS',
38+
'MORPHO',
39+
'NOT',
40+
'YFI',
41+
'CORE',
42+
'S',
43+
'GRASS',
44+
'GAS',
45+
'THETA',
46+
'OSMO',
47+
'XAI',
48+
'SKL',
49+
'LAYER',
50+
'WCT',
51+
'B3',
52+
'EGLD',
53+
'API3',
54+
'CVX',
55+
'BANANA',
56+
'KAS',
57+
'PI',
58+
'QNT',
59+
'ASTR',
60+
'JASMY',
61+
'IP',
62+
'SKY',
63+
'CAKE',
64+
'SUSHI',
65+
'AKT',
66+
'NIL',
67+
'MOVE',
68+
]);

src/hooks/rewards/util.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,108 @@ export const DEC_2025_COMPETITION_DETAILS = {
3838
rewardAmount: '$1M',
3939
rewardAmountUsd: 1_000_000,
4040
endTime: '2025-12-31T23:59:59.000Z', // end of month
41+
claimStartTime: '2025-12-19T23:59:00.000Z', // proposal passes + a few hours for any changes to claim page
42+
claimEndtime: '2026-01-31T23:59:59.000Z', // end of jan
43+
estimatedWalletRewards: {
44+
dydx18scsz5rdh242lnlnsgwxu5f5pmtf8cqw0pl58c: '5775.42',
45+
dydx17vt04dtfau0hvm0v6ahx708lflpgg4gedfqsyh: '5132.79',
46+
dydx10hpl83hamwz0pxvjlanh5rcas3mdgf8xk7g7ra: '4963.81',
47+
dydx17tch34sk5gzmn92zc5srwjngqgfqxcfex9339j: '4478.60',
48+
dydx1hyfm837du0zzn2pw0r328q7nl07c0um7u207ge: '4156.27',
49+
dydx1jxe3l4h2ychf66q5f37qxfpx2jh6l3zjum39rz: '2849.81',
50+
dydx13aeza8l3mrcr8d34g9z8tcunncl74gprf7t98g: '2797.10',
51+
dydx1a3ggqr30aduu4nhf92xxv8zqceczqdsg078lk4: '2667.30',
52+
dydx10yeumv4mdfre68g3tcf03nlr9y4rlsn4uss4uf: '2271.06',
53+
dydx1c4snkv9kac768m7dcxygjh6vqysmhyycj5f9t4: '2016.15',
54+
dydx1ufs97x7psym2735x7sfksdrsux63wzjfzfvpwd: '1901.04',
55+
dydx1hsest59cpjhzlpslwdsjmvwapjyd0cfthmn3ja: '1893.51',
56+
dydx1qmx0way5kd9umj9vgsyeg4e2sh9m3s293mpgq9: '1853.91',
57+
dydx179gwlz4fx20dntagmyzgu2uem5f95ej05qzpse: '1794.80',
58+
dydx1t9hd44tz6rh5ah7ljcyp99053rpymwm5fw4f53: '1715.40',
59+
dydx1zug353eq708ycmx5m8wp2ldj5nwfusl3kz2svk: '1646.83',
60+
dydx146keskm02u7hkqc6v6nvq3f8slavrytwpks6zz: '1625.57',
61+
dydx1n76jumjapfqkpnyqgvvqcv8762m06k4yl6cr5y: '1491.74',
62+
dydx1za0zs4stp65vll2nmh26qualq0uj6thh7ryyxc: '1429.89',
63+
dydx1kh9rhnyjmh6h4dpzpxqfcsc3dhmzwpz9myu7ev: '1314.07',
64+
dydx1qnulemnmyrm2rv2u3y6nfq379kldjza8qxgcga: '1279.73',
65+
dydx1afr2uvufcw4qwr4k9le2g8yxughnztncm3j5v9: '1168.91',
66+
dydx1axv8uda4c8ryz9e5gyx7hc3vz4ptmr6gmn67jw: '1161.17',
67+
dydx1y92j8l9nmnx8htjx3f9jec4eg4xzlepreg5xa5: '1156.29',
68+
dydx1uj5cywf4jyenrelkdtd7zwunzpumdu9j3tysqf: '1132.76',
69+
dydx10gtrjmf0qsutgrlsc32qwv6dq4v8xwqdcameyl: '1121.41',
70+
dydx1wyhxdz7aej4ze80f3szmdveufz56zanhv6ej7t: '1077.78',
71+
dydx1h0xansqzvhs2th9m7cdn5r6e52tkwvxrxp9yuf: '1063.53',
72+
dydx1f3l724ezg3m9eykkyem6xamguqyf434ptzpkda: '975.78',
73+
dydx19vs0ys95hauyu6yejdkt59rvungn9z8zj6l8kt: '962.23',
74+
dydx10wv0ur56cq3wyk5v58cjnux4745xc85fe7uurj: '935.56',
75+
dydx1xg9c2jj7z07krwsfz3njc5gnwcmwfqxcjwl6tw: '928.88',
76+
dydx14mlqzx6v5ajmerfqwmeu2asr32a0qs2dfc5970: '915.44',
77+
dydx19v3y45yas9k0k9qzv3pqmwdzusgrlxev6t45fj: '867.28',
78+
dydx16y908xy4pg2q07a8ydfzxwcryy8uzwt044uvu0: '853.66',
79+
dydx18023tv2kw8c03us8nl77ma00466zqqzgzh7l6y: '828.14',
80+
dydx1878e4s67ura0l5mp4zesz6ghkcr4u232zhfcy4: '811.61',
81+
dydx1qlnpjgqhdfca54gjrute88estqwz7mchffyawk: '806.79',
82+
dydx1lh75k0str8nxgwgrd2xwx440l38ds9ur0ek67e: '801.82',
83+
dydx176txwnwps6shutxl0jwlv9p4vhdasmp3fm6s4e: '795.8',
84+
dydx1klkt566wcz4hel793gah0t43lqlpqwg04h8uhf: '767',
85+
dydx1m4mc4dsvdf3q7jpa5kgpz2w86wykfqergfmc5v: '728.8',
86+
dydx15uh9tkcht0nvx0n8rqnqd2ky05xkrnmd7un972: '700.21',
87+
dydx1jfl3c74shcqpq7kvaa6ac7g3pmg2warlrfa2mk: '676.2',
88+
dydx19hzvjn9nsmafz2ua63hr6r0v609unvyxf4tu96: '665.19',
89+
dydx1vstyyprk2xtrfe8ealw3wrqt9rgfs9rx9ztfvp: '660.93',
90+
dydx1qgx5mhzxmtpvadmcgdq5ytmll5hq6truy9rfq6: '651.18',
91+
dydx1keelhggvqu9qley30qx9s8evu4f9jznxugh5pn: '635.65',
92+
dydx142v4mv2ng6ejxd8anx7a93p5tx8md5mqgz6nqj: '607.89',
93+
dydx12g8fjey35weu7ef8q2lnakmpqkw5avpxszxuy4: '594.54',
94+
dydx1rng56c8lg2ggdpav004as9mh5aft9v9fnw73j5: '593.91',
95+
dydx14jk68rhpjrlquupvdystfzw2snf7v43qscanqt: '580.64',
96+
dydx12p4z697emcxra05tu0t27ayj33y5tcpx2zq68n: '579.98',
97+
dydx1mefa0n6j58zvxpva0c4na8rgm5rf6sj9wr6xdl: '573.68',
98+
dydx1cdh7lg5awsxdgc2gvm26k8ut8f5nflrw55dzcg: '570.6',
99+
dydx1fq359sn2y7waawamk28t0k3wgkucz25njzm3tc: '567.4',
100+
dydx163s0g5a0f4x8264w5nx2qear06ffe3w45dcv5u: '550.08',
101+
dydx1s4fquxtzlvfumqfhvjlln23gzvxunasdcamuat: '527.11',
102+
dydx1yrne3cadvch3hju8at5k4tn9xp98z4hgkzyhj5: '519.42',
103+
dydx1x89rwrgsd287j8nyrk084c2rqwxv9zxypv7nht: '496.3',
104+
dydx1u98rum2e3plmvwugegcnge6st4pvxpu2ccsvwe: '489.22',
105+
dydx1wdm2vfjzqjn2k37n86aqz7ccf5qpdpwj5serjr: '487.1',
106+
dydx1xa8vpn0e9gjfhaqhnl06rjhjngg54mywk0aax8: '470.22',
107+
dydx1m4v5r5s9t2m3ukm35shcn84rrkzrv4u8k7dnq7: '465.87',
108+
dydx1zqgese9vvr338c2c63f27gwcg9h8npsstnvsda: '452.12',
109+
dydx1jfueucq6qg4avnjev0vd2nvtg0rdcl4lvgsr5g: '449.09',
110+
dydx14g8gtj52dgtpv5x4k03u7qlnmw2guyy6j3rwgf: '447.53',
111+
dydx13rysc2grgj8kt8yys6ylm03n9chpwktvx9rcsd: '443.57',
112+
dydx14r34ern0duvaerpypl6lh0lyeesa5454hr5ctr: '441.64',
113+
dydx1qcslanrp92v7r37w9qx867l5lghk5r5yfc5ajy: '430',
114+
dydx1vgl5r7shzlx4s026jvsyyld4v5lz98alwe5xtd: '427.12',
115+
dydx1fs456vxznh5ajpqwa59x4etzv0tq6eg6asq0ls: '410.4',
116+
dydx1ra8x3ktlynukrtwcy3wvmpsujk98nyz5e4nheu: '394.26',
117+
dydx1jqqp3pc6se96g2kecxgkaz0j7umx5j0y08ypgh: '393.09',
118+
dydx1lhhmnthgd4shjkkxepzgjv3n9fpcjw7cjn2xgy: '388.89',
119+
dydx19gvq2407chnwy0qz7ra83cktfymnwy0nn08puz: '378.6',
120+
dydx1sdx3cdcvkvygkq24tcsa9z2z4lkszfu44q0lgs: '372.29',
121+
dydx1rr2q3dm02dpagddyj2fklgn78094sdpt9hldh4: '366.25',
122+
dydx1clczqvzdcvdhh4qn4vl4n5wwnnnyru8mq5egwm: '350.11',
123+
dydx12tpalgc2hm8k8xg2j3nvuf3q5qkmrj7sus2xzf: '343.63',
124+
dydx1kupl5q5kjfkxdlgz27afshqe6anmkgtjdnw5va: '334.28',
125+
dydx1vk0h00qqzfvw9kdjsywxlatk985a497krmh5hj: '332.01',
126+
dydx10pqape76uwew0na3xrdxwnjam5qwzc04h79l0m: '328.77',
127+
dydx1xd9qtmu35kp6yrhqkktq84hvq88lmn65mp75pj: '326.59',
128+
dydx16ca2dg7y477zyrw0demqsse3stesud7val6dk9: '323.42',
129+
dydx1vd27pygl6y4qndpmd4hc86fqvdj7tj4hhf6hee: '322.14',
130+
dydx1gch3w7yu2cp97gsukx4ludfn8stwdk50gcf65d: '319.44',
131+
dydx1270ufzkufkkp4l922zltjf5g9rlufupl748lr2: '317.61',
132+
dydx1u4kprlmrhdxzn663p6gsjf5sq3jsfus9n399u9: '315.2',
133+
dydx1gmmyuv4ttzgduj6zpxtsnemvfa5gr6ca4cmcj2: '298.93',
134+
dydx1ga7aqlv9ll765v0pqtzcspmvg9xgxgj3kjvpss: '294.07',
135+
dydx1k9a76t62p6dv0wrkc4fg8vkrjtkv6ssfjg5l5e: '287.96',
136+
dydx1mf5myafs9vtt0erqpnfrk447g5fd5aa4sqx9t8: '282.46',
137+
dydx1ww3e3s59vvca0lfkw97nnwzt4sed5a59zmg77l: '281.78',
138+
dydx19rpqpy7hf3zs7z0c0urd7es0qk3rq8dlsplptl: '270.88',
139+
dydx177r48xzlzys8r3nz0kyelurul65xhw09p2cmp9: '267.89',
140+
dydx17qvwdpdljavs8ksg89pdjuqf3nmzdu6x92wst9: '262.57',
141+
dydx18zswqnds6ctwhm05vf2nfv3edw0kdkwf8u4fdh: '256.9',
142+
dydx1k36d0u3s9670yuphwcaem9f3k8zkhxa50xhhz8: '256.15',
143+
dydx1w26nye5g2psq8edhj3ch99tc0p4qkv3kvcdnkx: '253.61',
144+
} as Record<string, string>,
41145
};

src/hooks/useMarketsData.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { BonsaiCore } from '@/bonsai/ontology';
44
import { AssetData } from '@/bonsai/types/summaryTypes';
55
import { shallowEqual } from 'react-redux';
66

7+
import { HIDDEN_MARKETS } from '@/constants/hiddenMarkets';
78
import {
89
HiddenMarketFilterTags,
910
MARKET_FILTER_OPTIONS,
@@ -74,7 +75,7 @@ const sortByMarketCap = (a: AssetData, b: AssetData) => {
7475
return (b.marketCap ?? 0) - (a.marketCap ?? 0);
7576
};
7677

77-
const ASSETS_TO_REMOVE = new Set(['USDC', 'USDT', 'PIPPIN']);
78+
const ASSETS_TO_REMOVE = new Set(['USDC', 'USDT', ...HIDDEN_MARKETS]);
7879
export const useMarketsData = ({
7980
filter = MarketFilters.ALL,
8081
searchFilter,
@@ -116,9 +117,10 @@ export const useMarketsData = ({
116117
.filter(isTruthy)
117118
// filter out markets that cannot be traded
118119
.filter((m) => m.status !== 'FINAL_SETTLEMENT')
119-
// temporarily filter out markets with empty/0 oracle price
120+
// temporarily filter out markets with empty/0 oracle price and $0 open interest
120121
.filter((m) => MustBigNumber(m.oraclePrice).gt(0))
121-
.filter((a) => !ASSETS_TO_REMOVE.has(a.assetId))
122+
.filter((m) => MustBigNumber(m.openInterestUSDC).gt(0))
123+
.filter((m) => !HIDDEN_MARKETS.has(m.assetId))
122124
.map(getMarketDataFromPerpetualMarketSummary);
123125

124126
const unlaunchedMarketsData =

0 commit comments

Comments
 (0)