Skip to content

Commit dc23ea2

Browse files
authored
chore: march bonkness (#43)
* march bonkness * touch ups
1 parent 965c89a commit dc23ea2

6 files changed

Lines changed: 170 additions & 35 deletions

File tree

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.379",
58+
"@dydxprotocol/v4-localization": "1.1.393",
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/hooks/rewards/util.ts

Lines changed: 98 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { STRING_KEYS } from '@/constants/localization';
2+
13
export function pointsToEstimatedDydxRewards(
24
points?: number,
35
totalPoints?: number,
@@ -23,15 +25,104 @@ export function feesToEstimatedDollarRewards(totalFees?: number): number {
2325
return totalFees * CURRENT_SURGE_REWARDS_DETAILS.rebateFraction;
2426
}
2527

28+
type BonkRewardTier = {
29+
positionRange: number[];
30+
reward: number;
31+
};
32+
33+
type BonkRewardsDetails = {
34+
rewards: BonkRewardTier[];
35+
rewardAmount: string;
36+
rewardAmountUsd: number;
37+
topPrizeAmount: string;
38+
startTime: string;
39+
endTime: string;
40+
titleStringKey: string;
41+
leaderboardSize: number;
42+
};
43+
44+
// returns string derived from current time or timestamp in format: Mar | March | March 1
45+
export const simpleDateString = (
46+
timestamp?: string,
47+
options?: {
48+
month?: 'long' | 'short' | undefined;
49+
day?: 'numeric' | undefined;
50+
}
51+
) => {
52+
const date = timestamp ? new Date(timestamp) : new Date();
53+
return date.toLocaleString('en-US', {
54+
...options,
55+
month: options?.month ?? 'long',
56+
timeZone: 'UTC',
57+
});
58+
};
59+
60+
const februaryBonkRewards = [
61+
{ positionRange: [1, 1], reward: 25000 },
62+
{ positionRange: [2, 2], reward: 15000 },
63+
{ positionRange: [3, 3], reward: 10000 },
64+
{ positionRange: [4, 5], reward: 5000 },
65+
{ positionRange: [6, 10], reward: 4000 },
66+
{ positionRange: [11, 20], reward: 2000 },
67+
];
68+
69+
const marchBonkRewards = [
70+
{ positionRange: [1, 1], reward: 15000 },
71+
{ positionRange: [2, 2], reward: 7500 },
72+
{ positionRange: [3, 3], reward: 5000 },
73+
{ positionRange: [4, 5], reward: 2500 },
74+
{ positionRange: [6, 10], reward: 2000 },
75+
{ positionRange: [11, 15], reward: 1500 },
76+
];
77+
78+
const BONK_REWARDS_MAP = {
79+
February: {
80+
rewards: februaryBonkRewards,
81+
rewardAmount: '$100K',
82+
rewardAmountUsd: 100_000,
83+
topPrizeAmount: '$25,000',
84+
leaderboardSize: 20,
85+
startTime: '2026-02-01T00:00:00.000Z',
86+
endTime: '2026-02-28T23:59:59.000Z',
87+
titleStringKey: STRING_KEYS.BONK_PNL_COMPETITION_NAME_FEBRUARY,
88+
},
89+
March: {
90+
rewards: marchBonkRewards,
91+
rewardAmount: '$50k',
92+
rewardAmountUsd: 50_000,
93+
topPrizeAmount: '$15,000',
94+
leaderboardSize: 15,
95+
startTime: '2026-03-01T00:00:00.000Z',
96+
endTime: '2026-03-31T23:59:59.000Z',
97+
titleStringKey: STRING_KEYS.BONK_PNL_COMPETITION_NAME_MARCH,
98+
},
99+
};
100+
101+
const bonkRewardsMonths = Object.keys(BONK_REWARDS_MAP) as (keyof typeof BONK_REWARDS_MAP)[];
102+
const lastBonkRewardsMonth = bonkRewardsMonths[
103+
bonkRewardsMonths.length - 1
104+
] as keyof typeof BONK_REWARDS_MAP;
105+
106+
export const CURRENT_BONK_REWARDS_DETAILS: BonkRewardsDetails =
107+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
108+
BONK_REWARDS_MAP[simpleDateString() as keyof typeof BONK_REWARDS_MAP] ??
109+
BONK_REWARDS_MAP[lastBonkRewardsMonth];
110+
26111
export function positionToBonkRewards(position: number | undefined) {
27112
if (!position) return 0;
28-
if (position === 1) return 25000;
29-
if (position === 2) return 15000;
30-
if (position === 3) return 10000;
31-
if (position === 4 || position === 5) return 5000;
32-
if (position >= 6 && position <= 10) return 4000;
33-
if (position >= 11 && position <= 20) return 2000;
34-
return 0;
113+
114+
const activeBonkRewards = CURRENT_BONK_REWARDS_DETAILS.rewards;
115+
116+
if (!activeBonkRewards.length) return 0;
117+
118+
const activeBonkReward = activeBonkRewards.find(
119+
(reward) =>
120+
!!reward.positionRange[0] &&
121+
!!reward.positionRange[1] &&
122+
position >= reward.positionRange[0] &&
123+
position <= reward.positionRange[1]
124+
);
125+
return activeBonkReward?.reward ?? 0;
35126
}
36127

37128
export const CURRENT_SURGE_REWARDS_DETAILS = {
@@ -49,11 +140,6 @@ export const LIQUIDATION_REBATES_DETAILS = {
49140
rebateAmountUsd: 1_000_000,
50141
};
51142

52-
export const CURRENT_BONK_REWARDS_DETAILS = {
53-
startTime: '2026-02-01T00:00:00.000Z', // start of february 2026
54-
endTime: '2026-02-28T23:59:59.000Z', // end of february 2026
55-
};
56-
57143
export const DEC_2025_COMPETITION_DETAILS = {
58144
rewardAmount: '$1M',
59145
rewardAmountUsd: 1_000_000,
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import { isDev } from '@/constants/networks';
22
import { StatsigFlags } from '@/constants/statsig';
33

4-
import { CURRENT_BONK_REWARDS_DETAILS } from './rewards/util';
54
import { useStatsigGateValue } from './useStatsig';
65

76
export const useEnableBonkPnlLeaderboard = () => {
87
const bonkPnlLeaderboardFF = useStatsigGateValue(StatsigFlags.ffBonkPnlLeaderboard);
9-
const isLive = new Date() >= new Date(CURRENT_BONK_REWARDS_DETAILS.startTime);
10-
return isDev || bonkPnlLeaderboardFF || isLive;
8+
return isDev || bonkPnlLeaderboardFF;
119
};

src/pages/token/BonkIncentivesPanel.tsx

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ import {
1212
useBonkPnlDistribution,
1313
useFeeLeaderboard,
1414
} from '@/hooks/rewards/hooks';
15-
import { CURRENT_BONK_REWARDS_DETAILS, positionToBonkRewards } from '@/hooks/rewards/util';
15+
import {
16+
CURRENT_BONK_REWARDS_DETAILS,
17+
positionToBonkRewards,
18+
simpleDateString,
19+
} from '@/hooks/rewards/util';
1620
import { useAccounts } from '@/hooks/useAccounts';
1721
import { useNow } from '@/hooks/useNow';
1822
import { useStringGetter } from '@/hooks/useStringGetter';
@@ -22,7 +26,7 @@ import { layoutMixins } from '@/styles/layoutMixins';
2226
import { Icon, IconName } from '@/components/Icon';
2327
import { Output, OutputType } from '@/components/Output';
2428
import { Panel } from '@/components/Panel';
25-
import { SuccessTag, TagSize } from '@/components/Tag';
29+
import { PrivateTag, SuccessTag, TagSize } from '@/components/Tag';
2630
import { WithTooltip } from '@/components/WithTooltip';
2731

2832
import { useAppDispatch, useAppSelector } from '@/state/appTypes';
@@ -41,45 +45,90 @@ export const BonkIncentivesPanel = () => {
4145
const BonkIncentivesRewardsPanel = () => {
4246
const stringGetter = useStringGetter();
4347

48+
const { rewardAmount, topPrizeAmount, startTime, endTime, titleStringKey, leaderboardSize } =
49+
CURRENT_BONK_REWARDS_DETAILS;
50+
51+
const isActive = new Date(startTime) <= new Date() && new Date(endTime) >= new Date();
52+
4453
return (
4554
<$Panel>
4655
<div tw="flex gap-3 pb-0.25 pt-0.5">
4756
<div tw="flex flex-1 flex-col gap-1.5">
4857
<div tw="flex flex-col gap-0.5">
49-
<div tw="flex items-center gap-0.5">
58+
<div tw="flex flex-wrap items-center gap-0.5 gap-y-0.25">
5059
<div tw="font-medium-bold">
5160
<span tw="font-bold">
52-
{stringGetter({ key: STRING_KEYS.BONK_REWARDS_HEADLINE })}
61+
{stringGetter({
62+
key: STRING_KEYS.BONK_PNL_REWARDS_HEADLINE,
63+
params: {
64+
COMPETITION_NAME: stringGetter({ key: titleStringKey }),
65+
},
66+
})}
5367
</span>
5468
</div>
55-
<SuccessTag size={TagSize.Medium}>
56-
{stringGetter({ key: STRING_KEYS.ACTIVE })}
57-
</SuccessTag>
69+
{isActive ? (
70+
<SuccessTag size={TagSize.Medium}>
71+
{stringGetter({ key: STRING_KEYS.ACTIVE })}
72+
</SuccessTag>
73+
) : (
74+
<PrivateTag size={TagSize.Medium}>
75+
{stringGetter({ key: STRING_KEYS.INACTIVE })}
76+
</PrivateTag>
77+
)}
5878
</div>
5979
<span>
6080
<span tw="text-color-text-0">
61-
{stringGetter({ key: STRING_KEYS.BONK_REWARDS_BODY })}
81+
{stringGetter({
82+
key: STRING_KEYS.BONK_PNL_REWARDS_BODY,
83+
params: {
84+
REWARD_AMOUNT: rewardAmount,
85+
MONTH: simpleDateString(startTime, { month: 'long' }),
86+
},
87+
})}
6288
</span>
6389
</span>
6490

6591
<div>
66-
<p tw="font-semibold">{stringGetter({ key: STRING_KEYS.BONK_REWARDS_RULES })}</p>
92+
<p tw="font-semibold">{stringGetter({ key: STRING_KEYS.BONK_PNL_REWARDS_RULES })}</p>
6793
<ul tw="list-outside list-disc pl-1.5 text-color-text-0">
68-
<li>{stringGetter({ key: STRING_KEYS.BONK_REWARDS_RULE_1 })}</li>
69-
<li>{stringGetter({ key: STRING_KEYS.BONK_REWARDS_RULE_2 })}</li>
70-
<li>{stringGetter({ key: STRING_KEYS.BONK_REWARDS_RULE_3 })}</li>
94+
<li>
95+
{stringGetter({
96+
key: STRING_KEYS.BONK_PNL_REWARDS_RULE_1,
97+
params: {
98+
MONTH: simpleDateString(startTime, { month: 'long' }),
99+
},
100+
})}
101+
</li>
102+
<li>
103+
{stringGetter({
104+
key: STRING_KEYS.BONK_PNL_REWARDS_RULE_2,
105+
params: {
106+
MONTH_FIRST: `${simpleDateString(startTime, { month: 'short', day: 'numeric' })}`,
107+
MONTH_LAST: `${simpleDateString(endTime, { month: 'short', day: 'numeric' })}`,
108+
},
109+
})}
110+
</li>
111+
<li>
112+
{stringGetter({
113+
key: STRING_KEYS.BONK_PNL_REWARDS_RULE_3,
114+
params: {
115+
LEADERBOARD_SIZE: leaderboardSize,
116+
TOP_PRIZE_AMOUNT: topPrizeAmount,
117+
},
118+
})}
119+
</li>
71120
</ul>
72121
</div>
73122

74123
<span tw="text-color-text-0">
75-
{stringGetter({ key: STRING_KEYS.BONK_REWARDS_BODY_2 })}
124+
{stringGetter({ key: STRING_KEYS.BONK_PNL_REWARDS_BODY_2 })}
76125
</span>
77126
</div>
78127

79128
<div tw="flex items-center gap-0.25 self-start rounded-3 bg-color-layer-1 px-0.875 py-0.5">
80129
<Icon iconName={IconName.Clock} size="1.25rem" tw="text-color-accent" />
81130
<div tw="flex gap-0.375 px-0.375 leading-none">
82-
<MinutesCountdown endTime={CURRENT_BONK_REWARDS_DETAILS.endTime} />
131+
<MinutesCountdown endTime={endTime} />
83132
</div>
84133
</div>
85134
</div>

src/pages/token/RewardsPage.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { STRING_KEYS } from '@/constants/localization';
1111
import { EMPTY_ARR } from '@/constants/objects';
1212
import { AppRoute } from '@/constants/routes';
1313

14+
import { CURRENT_BONK_REWARDS_DETAILS } from '@/hooks/rewards/util';
1415
import { useBreakpoints } from '@/hooks/useBreakpoints';
1516
import { useComplianceState } from '@/hooks/useComplianceState';
1617
import { useEnableBonkPnlLeaderboard } from '@/hooks/useEnableBonkPnlLeaderboard';
@@ -49,6 +50,7 @@ enum Tab {
4950
}
5051

5152
const RewardsPage = () => {
53+
const { titleStringKey } = CURRENT_BONK_REWARDS_DETAILS;
5254
const stringGetter = useStringGetter();
5355
const navigate = useNavigate();
5456
const enableBonkPnlLeaderboard = useEnableBonkPnlLeaderboard();
@@ -99,7 +101,7 @@ const RewardsPage = () => {
99101
<BonkPnlPanel />
100102
</div>
101103
),
102-
label: 'BONKuary',
104+
label: stringGetter({ key: titleStringKey }),
103105
value: Tab.BonkPnl,
104106
},
105107
]

0 commit comments

Comments
 (0)