Skip to content

Commit a2e765d

Browse files
committed
prepare for borrow rewards
1 parent aa7bdae commit a2e765d

File tree

9 files changed

+142
-92
lines changed

9 files changed

+142
-92
lines changed

frontend/src/components/dashboard/AprWithRewardsBreakdown.tsx

+12-10
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ const formatAprPercent = (
7979
showChange: boolean,
8080
) =>
8181
showChange && !newValue.eq(value)
82-
? `${formatPercent(value)}${isAprModifierInvalid ? "N/A" : formatPercent(newValue)}`
83-
: formatPercent(value);
82+
? `${formatPercent(value, { useAccountingSign: true })}${isAprModifierInvalid ? "N/A" : formatPercent(newValue, { useAccountingSign: true })}`
83+
: formatPercent(value, { useAccountingSign: true });
8484

8585
interface AprWithRewardsBreakdownProps {
8686
side: Side;
@@ -159,13 +159,11 @@ export default function AprWithRewardsBreakdown({
159159
}));
160160

161161
// Total APR
162-
const totalAprPercent = getTotalAprPercent(aprPercent, filteredRewards);
163-
const newTotalAprPercent = newAprRewards.reduce(
164-
(acc, reward) =>
165-
side === Side.DEPOSIT
166-
? acc.plus(reward.stats.aprPercent)
167-
: acc.minus(reward.stats.aprPercent),
162+
const totalAprPercent = getTotalAprPercent(side, aprPercent, filteredRewards);
163+
const newTotalAprPercent = getTotalAprPercent(
164+
side,
168165
newAprPercent,
166+
newAprRewards,
169167
);
170168

171169
if (filteredRewards.length === 0)
@@ -263,8 +261,12 @@ export default function AprWithRewardsBreakdown({
263261
key={index}
264262
isLast={index === aprRewards.length - 1}
265263
value={formatAprPercent(
266-
reward.stats.aprPercent,
267-
newAprRewards[index].stats.aprPercent,
264+
reward.stats.aprPercent.times(
265+
side === Side.DEPOSIT ? 1 : -1,
266+
),
267+
newAprRewards[index].stats.aprPercent.times(
268+
side === Side.DEPOSIT ? 1 : -1,
269+
),
268270
isAprModifierInvalid,
269271
showChange,
270272
)}

frontend/src/components/dashboard/MarketTable.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,13 @@ export default function MarketTable() {
143143
const borrowedAmountUsd = reserve.borrowedAmountUsd;
144144
const depositAprPercent = reserve.depositAprPercent;
145145
const totalDepositAprPercent = getTotalAprPercent(
146+
Side.DEPOSIT,
146147
reserve.depositAprPercent,
147148
getFilteredRewards(data.rewardMap[coinType].deposit),
148149
);
149150
const borrowAprPercent = reserve.borrowAprPercent;
150151
const totalBorrowAprPercent = getTotalAprPercent(
152+
Side.BORROW,
151153
reserve.borrowAprPercent,
152154
getFilteredRewards(data.rewardMap[coinType].borrow),
153155
);

frontend/src/components/dashboard/account/AccountPositionCard.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import BigNumber from "bignumber.js";
44
import { AlertTriangle, FileClock, TrendingUp } from "lucide-react";
55

66
import { ParsedObligation } from "@suilend/sdk/parsers/obligation";
7+
import { Side } from "@suilend/sdk/types";
78

89
import AccountBreakdown from "@/components/dashboard/account/AccountBreakdown";
910
import BorrowLimitTitle from "@/components/dashboard/account/BorrowLimitTitle";
@@ -46,6 +47,7 @@ function AccountPositionCardContent() {
4647
// APR
4748
const aprWeightedDepositsUsd = obligation.deposits.reduce((acc, deposit) => {
4849
const totalAprPercent = getTotalAprPercent(
50+
Side.DEPOSIT,
4951
deposit.reserve.depositAprPercent,
5052
getFilteredRewards(data.rewardMap[deposit.reserve.coinType].deposit),
5153
);
@@ -55,6 +57,7 @@ function AccountPositionCardContent() {
5557

5658
const aprWeightedBorrowsUsd = obligation.borrows.reduce((acc, borrow) => {
5759
const totalAprPercent = getTotalAprPercent(
60+
Side.BORROW,
5861
borrow.reserve.borrowAprPercent,
5962
getFilteredRewards(data.rewardMap[borrow.reserve.coinType].borrow),
6063
);

frontend/src/components/dashboard/actions-modal/HistoricalAprLineChart.tsx

+27-13
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import {
3333
DAY_S,
3434
Days,
3535
RESERVE_EVENT_SAMPLE_INTERVAL_S_MAP,
36-
calculateRewardDepositAprPercent,
36+
calculateRewardAprPercent,
3737
} from "@/lib/events";
3838
import { formatPercent } from "@/lib/format";
3939
import {
@@ -68,6 +68,19 @@ function TooltipContent({ side, fields, d, viewBox, x }: TooltipContentProps) {
6868

6969
if (fields.every((field) => d[field] === undefined)) return null;
7070
if (viewBox === undefined || x === undefined) return null;
71+
72+
const interestField = `${side}InterestAprPercent`;
73+
const rewardFields = fields.filter((field) => field !== interestField);
74+
75+
const aprPercent = new BigNumber(d[interestField] as number);
76+
const totalAprPercent = rewardFields.reduce(
77+
(acc, field) =>
78+
acc.plus(
79+
new BigNumber(d[field] as number).times(side === Side.DEPOSIT ? 1 : -1),
80+
),
81+
new BigNumber(aprPercent),
82+
);
83+
7184
return (
7285
// Subset of TooltipContent className
7386
<div
@@ -82,14 +95,7 @@ function TooltipContent({ side, fields, d, viewBox, x }: TooltipContentProps) {
8295
<div className="flex w-full flex-row items-center justify-between gap-4">
8396
<TBodySans>{capitalize(side)} APR</TBodySans>
8497
<TBody>
85-
{formatPercent(
86-
new BigNumber(
87-
fields.reduce(
88-
(acc: number, field) => acc + (d[field] as number),
89-
0,
90-
),
91-
),
92-
)}
98+
{formatPercent(totalAprPercent, { useAccountingSign: true })}
9399
</TBody>
94100
</div>
95101

@@ -103,7 +109,14 @@ function TooltipContent({ side, fields, d, viewBox, x }: TooltipContentProps) {
103109
isLast={index === fields.length - 1}
104110
value={
105111
<span style={{ color }}>
106-
{formatPercent(new BigNumber(d[field] as number))}
112+
{formatPercent(
113+
!coinType
114+
? aprPercent
115+
: new BigNumber(d[field] as number).times(
116+
side === Side.DEPOSIT ? 1 : -1,
117+
),
118+
{ useAccountingSign: true },
119+
)}
107120
</span>
108121
}
109122
>
@@ -401,8 +414,9 @@ export default function HistoricalAprLineChart({
401414
const d = aprRewardReserves.reduce(
402415
(acc, rewardReserve) => ({
403416
...acc,
404-
[`depositInterestAprPercent_${rewardReserve.coinType}`]: event
405-
? calculateRewardDepositAprPercent(
417+
[`${side}InterestAprPercent_${rewardReserve.coinType}`]: event
418+
? calculateRewardAprPercent(
419+
side,
406420
event,
407421
reserveAssetDataEventsMap?.[rewardReserve.id]?.[
408422
days
@@ -423,7 +437,7 @@ export default function HistoricalAprLineChart({
423437
});
424438

425439
return result as ChartData[];
426-
}, [reserveAssetDataEventsMap, reserve, days, aprRewardReserves]);
440+
}, [reserveAssetDataEventsMap, reserve, days, aprRewardReserves, side]);
427441
const isLoading = chartData === undefined;
428442

429443
return (

frontend/src/lib/events.ts

+79-65
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import BigNumber from "bignumber.js";
22

33
import { ParsedDownsampledApiReserveAssetDataEvent } from "@suilend/sdk/parsers/apiReserveAssetDataEvent";
44
import { ParsedReserve } from "@suilend/sdk/parsers/reserve";
5+
import { Side } from "@suilend/sdk/types";
56

67
import {
78
NORMALIZED_SUI_COINTYPE,
@@ -72,7 +73,8 @@ type ReducedPoolReward = {
7273
endTimeMs: number;
7374
};
7475

75-
export const calculateRewardDepositAprPercent = (
76+
export const calculateRewardAprPercent = (
77+
side: Side,
7678
event: ParsedDownsampledApiReserveAssetDataEvent,
7779
rewardEvents: ParsedDownsampledApiReserveAssetDataEvent[],
7880
reserve: ParsedReserve,
@@ -86,73 +88,81 @@ export const calculateRewardDepositAprPercent = (
8688

8789
const rewardCoinType = rewardEvent.coinType;
8890

89-
const historicalRewardsMap: Record<string, ReducedPoolReward[]> = {
90-
[NORMALIZED_SUI_COINTYPE]: [
91-
{
92-
coinType: NORMALIZED_SUI_COINTYPE,
93-
totalRewards: new BigNumber(93613.13),
94-
startTimeMs: 1713225600000,
95-
endTimeMs: 1713830400000,
96-
},
97-
{
98-
coinType: NORMALIZED_SUI_COINTYPE,
99-
totalRewards: new BigNumber(177579),
100-
startTimeMs: 1713830400000, // 2024-04-23 08:00:00
101-
endTimeMs: 1715040000000, // 2024-05-07 08:00:00
102-
},
103-
{
104-
coinType: NORMALIZED_SUI_COINTYPE,
105-
totalRewards: new BigNumber(162386.57),
106-
startTimeMs: 1715040000000, // 2024-05-07 08:00:00
107-
endTimeMs: 1716249600000, //2024-05-21 08:00:00
108-
},
109-
],
110-
[NORMALIZED_USDC_COINTYPE]: [
111-
{
112-
coinType: NORMALIZED_SUI_COINTYPE,
113-
totalRewards: new BigNumber(75915.32),
114-
startTimeMs: 1713225600000,
115-
endTimeMs: 1713830400000,
116-
},
117-
{
118-
coinType: NORMALIZED_SUI_COINTYPE,
119-
totalRewards: new BigNumber(168534),
120-
startTimeMs: 1713830400000, // 2024-04-23 08:00:00
121-
endTimeMs: 1715040000000, // 2024-05-07 08:00:00
122-
},
123-
{
124-
coinType: NORMALIZED_SUI_COINTYPE,
125-
totalRewards: new BigNumber(176679.79),
126-
startTimeMs: 1715040000000, // 2024-05-07 08:00:00
127-
endTimeMs: 1716249600000, //2024-05-21 08:00:00
128-
},
129-
],
130-
[NORMALIZED_USDT_COINTYPE]: [
131-
{
132-
coinType: NORMALIZED_SUI_COINTYPE,
133-
totalRewards: new BigNumber(64602.32),
134-
startTimeMs: 1713225600000,
135-
endTimeMs: 1713830400000,
136-
},
137-
{
138-
coinType: NORMALIZED_SUI_COINTYPE,
139-
totalRewards: new BigNumber(128939),
140-
startTimeMs: 1713830400000, // 2024-04-23 08:00:00
141-
endTimeMs: 1715040000000, // 2024-05-07 08:00:00
142-
},
143-
{
144-
coinType: NORMALIZED_SUI_COINTYPE,
145-
totalRewards: new BigNumber(116534.73),
146-
startTimeMs: 1715040000000, // 2024-05-07 08:00:00
147-
endTimeMs: 1716249600000, //2024-05-21 08:00:00
148-
},
149-
],
91+
const historicalRewardsMap: Record<
92+
Side,
93+
Record<string, ReducedPoolReward[]>
94+
> = {
95+
[Side.DEPOSIT]: {
96+
[NORMALIZED_SUI_COINTYPE]: [
97+
{
98+
coinType: NORMALIZED_SUI_COINTYPE,
99+
totalRewards: new BigNumber(93613.13),
100+
startTimeMs: 1713225600000,
101+
endTimeMs: 1713830400000,
102+
},
103+
{
104+
coinType: NORMALIZED_SUI_COINTYPE,
105+
totalRewards: new BigNumber(177579),
106+
startTimeMs: 1713830400000, // 2024-04-23 08:00:00
107+
endTimeMs: 1715040000000, // 2024-05-07 08:00:00
108+
},
109+
{
110+
coinType: NORMALIZED_SUI_COINTYPE,
111+
totalRewards: new BigNumber(162386.57),
112+
startTimeMs: 1715040000000, // 2024-05-07 08:00:00
113+
endTimeMs: 1716249600000, //2024-05-21 08:00:00
114+
},
115+
],
116+
[NORMALIZED_USDC_COINTYPE]: [
117+
{
118+
coinType: NORMALIZED_SUI_COINTYPE,
119+
totalRewards: new BigNumber(75915.32),
120+
startTimeMs: 1713225600000,
121+
endTimeMs: 1713830400000,
122+
},
123+
{
124+
coinType: NORMALIZED_SUI_COINTYPE,
125+
totalRewards: new BigNumber(168534),
126+
startTimeMs: 1713830400000, // 2024-04-23 08:00:00
127+
endTimeMs: 1715040000000, // 2024-05-07 08:00:00
128+
},
129+
{
130+
coinType: NORMALIZED_SUI_COINTYPE,
131+
totalRewards: new BigNumber(176679.79),
132+
startTimeMs: 1715040000000, // 2024-05-07 08:00:00
133+
endTimeMs: 1716249600000, //2024-05-21 08:00:00
134+
},
135+
],
136+
[NORMALIZED_USDT_COINTYPE]: [
137+
{
138+
coinType: NORMALIZED_SUI_COINTYPE,
139+
totalRewards: new BigNumber(64602.32),
140+
startTimeMs: 1713225600000,
141+
endTimeMs: 1713830400000,
142+
},
143+
{
144+
coinType: NORMALIZED_SUI_COINTYPE,
145+
totalRewards: new BigNumber(128939),
146+
startTimeMs: 1713830400000, // 2024-04-23 08:00:00
147+
endTimeMs: 1715040000000, // 2024-05-07 08:00:00
148+
},
149+
{
150+
coinType: NORMALIZED_SUI_COINTYPE,
151+
totalRewards: new BigNumber(116534.73),
152+
startTimeMs: 1715040000000, // 2024-05-07 08:00:00
153+
endTimeMs: 1716249600000, //2024-05-21 08:00:00
154+
},
155+
],
156+
},
157+
[Side.BORROW]: {},
150158
};
151159

152160
const allPoolRewards: ReducedPoolReward[] = [
153-
...reserve.depositsPoolRewardManager.poolRewards,
161+
...(side === Side.DEPOSIT
162+
? reserve.depositsPoolRewardManager.poolRewards
163+
: reserve.borrowsPoolRewardManager.poolRewards),
154164
];
155-
(historicalRewardsMap[event.coinType] ?? []).forEach((hr) => {
165+
(historicalRewardsMap[side][event.coinType] ?? []).forEach((hr) => {
156166
if (
157167
allPoolRewards.find(
158168
(pr) =>
@@ -185,7 +195,11 @@ export const calculateRewardDepositAprPercent = (
185195
pr.totalRewards
186196
.times(rewardEvent.price)
187197
.times(new BigNumber(msPerYear).div(pr.endTimeMs - pr.startTimeMs))
188-
.div(event.depositedAmountUsd)
198+
.div(
199+
side === Side.DEPOSIT
200+
? event.depositedAmountUsd
201+
: event.borrowedAmountUsd,
202+
)
189203
.times(100),
190204
),
191205
new BigNumber(0),

frontend/src/lib/format.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,22 @@ export const formatPoints = (value: BigNumber, options?: { dp?: number }) => {
154154
});
155155
};
156156

157-
export const formatPercent = (value: BigNumber, options?: { dp?: number }) => {
157+
export const formatPercent = (
158+
value: BigNumber,
159+
options?: { dp?: number; useAccountingSign?: boolean },
160+
) => {
158161
const dp = options?.dp ?? 2;
162+
const useAccountingSign = options?.useAccountingSign ?? false;
159163

160-
return Intl.NumberFormat(undefined, {
164+
const formattedValue = Intl.NumberFormat(undefined, {
161165
style: "percent",
162166
minimumFractionDigits: dp,
163167
maximumFractionDigits: dp,
164-
}).format(value.div(100).toNumber());
168+
}).format(value.abs().div(100).toNumber());
169+
170+
return !useAccountingSign || value.gte(0)
171+
? formattedValue
172+
: `(${formattedValue})`;
165173
};
166174

167175
export const formatDuration = (seconds: BigNumber) => {

frontend/src/lib/liquidityMining.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,12 @@ export const getDedupedPerDayRewards = (
222222
};
223223

224224
export const getTotalAprPercent = (
225+
side: Side,
225226
aprPercent: BigNumber,
226227
filteredRewards: RewardSummary[],
227228
) =>
228229
getDedupedAprRewards(filteredRewards).reduce(
229-
(acc, reward) => acc.plus(reward.stats.aprPercent),
230+
(acc, reward) =>
231+
acc.plus(reward.stats.aprPercent.times(side === Side.DEPOSIT ? 1 : -1)),
230232
aprPercent,
231233
);

frontend/src/pages/index.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import NextLink from "next/link";
33

44
import { Droplet, Server } from "lucide-react";
55

6+
import { Side } from "@suilend/sdk/types";
7+
68
import DiscordIcon from "@/components/assets/DiscordIcon";
79
import XIcon from "@/components/assets/XIcon";
810
import HeaderBase from "@/components/layout/HeaderBase";
@@ -162,6 +164,7 @@ export default function Home() {
162164
)
163165
.map((reserve) => {
164166
const totalDepositAprPercent = getTotalAprPercent(
167+
Side.DEPOSIT,
165168
reserve.depositAprPercent,
166169
getFilteredRewards(
167170
data.rewardMap[reserve.coinType].deposit,

0 commit comments

Comments
 (0)