Skip to content

Commit

Permalink
feat: show metanodes earning (#304)
Browse files Browse the repository at this point in the history
* feat: show metanodes earning

* feat: add internal api rewards-last-week

* fix: wrong redirect to / (should be /explorer)
  • Loading branch information
ryenguyen7411 authored Sep 6, 2023
1 parent 6985d53 commit 6fd44b7
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 41 deletions.
5 changes: 3 additions & 2 deletions src/components/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React, { useState } from 'react';
import { useIntl } from 'react-intl';

import { StylingConstants } from '../../modules/styles';
import { PATH } from '../../modules/env';

import { SearchIcon, SearchInput } from './styled';

Expand Down Expand Up @@ -51,7 +52,7 @@ export const Search = () => {
var address = await checkUD(search);
if (address)
router.push({
pathname: '/',
pathname: PATH.EXPLORER,
query: {
bridge: chainBridge,
type: address ? 'search' : '',
Expand All @@ -60,7 +61,7 @@ export const Search = () => {
});
else
router.push({
pathname: '/',
pathname: PATH.EXPLORER,
query: {
bridge: chainBridge,
type: search ? 'search' : '',
Expand Down
28 changes: 26 additions & 2 deletions src/modules/hooks/useToggleMetanode/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useEffect, useState } from 'react';
import { stringifyUrl } from 'query-string';

import { Bridge, Mode, Node, useNodesDetailsQuery } from '../../../generated/graphql';
import { ENDPOINT_SKYBRIDGE_EXCHANGE, mode, PATH } from '../../env';
Expand All @@ -11,6 +12,7 @@ import {
ILiquidityRatio,
ILiquidityRatios,
IReward,
IRewardV2,
listHistory,
} from '../../metanodes';
import { useInterval } from '../useInterval';
Expand All @@ -21,6 +23,7 @@ export const useToggleMetanode = (path: PATH) => {

const [metanodes, setMetanodes] = useState<Node[] | null>(null);
const [reward, setReward] = useState<IReward | null>(null);
const [rewardV2, setRewardV2] = useState<IRewardV2 | null>(null);
const [liquidity, setLiquidity] = useState<ILiquidity | null>(null);
const [churnTime, setChurnTime] = useState<IChurn | null>(null);
const [bondHistories, setBondHistories] = useState<IChartDate[] | null>(null);
Expand Down Expand Up @@ -58,6 +61,16 @@ export const useToggleMetanode = (path: PATH) => {
}
}, [bridge, path]);

const getRewardsV2 = useCallback(async () => {
const rewardsUrl = stringifyUrl({
url: `/api/v1/rewards-last-week`,
query: { bridge: 'btc_skypool' },
});

const rewardData = await fetcher<IRewardV2>(rewardsUrl);
setRewardV2(rewardData);
}, []);

const getLiquidity = useCallback(async () => {
if (bridge && path === PATH.METANODES) {
const url = `${ENDPOINT_SKYBRIDGE_EXCHANGE}/${mode}/${bridge}/bond-to-liquidity`;
Expand Down Expand Up @@ -97,7 +110,8 @@ export const useToggleMetanode = (path: PATH) => {
(async () => {
try {
await Promise.all([
getRewards(),
// getRewards(),
getRewardsV2(),
getLiquidity(),
getBondHistory(),
getLiquidityRation(),
Expand All @@ -110,10 +124,19 @@ export const useToggleMetanode = (path: PATH) => {
setIsLoading(false);
}
})();
}, [getBondHistory, getLiquidityRation, getChurnTime, getLiquidity, getRewards, getNodes]);
}, [
getBondHistory,
getLiquidityRation,
getChurnTime,
getLiquidity,
getRewards,
getRewardsV2,
getNodes,
]);

useEffect(() => {
setReward(null);
setRewardV2(null);
setLiquidity(null);
setChurnTime(null);
setBondHistories(null);
Expand All @@ -134,6 +157,7 @@ export const useToggleMetanode = (path: PATH) => {
liquidityRatio,
churnTime,
reward,
rewardV2,
isLoading,
};
};
1 change: 1 addition & 0 deletions src/modules/links/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const URL = {
MigrateErc20: 'https://etherscan.io/token/0x8287c7b963b405b7b8d467db9d79eec40625b13a',
MigrateIn: 'https://bscscan.com/address/0x640534D32D015e4C80318ad5256Ec7962fDB155f',
MigrateOut: 'https://etherscan.io/address/0x640534D32D015e4C80318ad5256Ec7962fDB155f',
SetupNode: 'https://skybridge-docs.swingby.network/technical-details/the-swingby-node',
};

export const Links = [
Expand Down
6 changes: 6 additions & 0 deletions src/modules/metanodes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ export interface IReward {
stakingRewards: string;
}

export interface IRewardV2 {
currency: string;
total: number;
totalSbBtc: number;
}

export interface IBridge {
bridge: SkybridgeBridge;
tabMenu: string;
Expand Down
12 changes: 12 additions & 0 deletions src/modules/scenes/Main/Metanodes/ActionButtonMetanodes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import { Tooltip, Text } from '@swingby-protocol/pulsar';
import React from 'react';
import { FormattedMessage } from 'react-intl';

import { URL } from '../../../../links';

import {
ActionButtonMetanodesContainer,
RowText,
TextAPR,
TextTitle,
TextSwapFee,
InfoIcon,
ButtonSetupNode,
ButtonSetupNodeAnchor,
} from './styled';

export const ActionButtonMetanodes = () => {
Expand Down Expand Up @@ -41,6 +45,14 @@ export const ActionButtonMetanodes = () => {
<InfoIcon />
</Tooltip>
</div>

<div style={{ flex: 1 }}></div>

<ButtonSetupNodeAnchor href={URL.SetupNode} target="_blank">
<ButtonSetupNode variant="primary" size="country">
How to Setup Node
</ButtonSetupNode>
</ButtonSetupNodeAnchor>
</RowText>
</ActionButtonMetanodesContainer>
);
Expand Down
18 changes: 16 additions & 2 deletions src/modules/scenes/Main/Metanodes/ActionButtonMetanodes/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { rem } from 'polished';
import styled from 'styled-components';

import { StylingConstants } from '../../../../styles';
import { IconInfo } from '../../../Common';
import { IconInfo, ButtonScale } from '../../../Common';

const { media } = StylingConstants;

Expand All @@ -26,13 +26,27 @@ export const RowText = styled.div`
@media (min-width: ${rem(media.sm)}) {
align-items: center;
flex-direction: row;
width: auto;
width: 100%;
column-gap: ${({ theme }) => rem(theme.pulsar.size.box)};
}
`;

export const ButtonContainer = styled.div``;

export const ButtonSetupNode = styled(ButtonScale)`
width: 200px;
`;

export const ButtonSetupNodeAnchor = styled.a`
display: flex;
align-items: center;
gap: ${({ theme }) => rem(theme.pulsar.size.room)};
color: ${({ theme }) => theme.pulsar.color.text.normal};
font-size: ${({ theme }) => rem(theme.pulsar.size.closet)};
text-decoration: none;
cursor: pointer;
`;

export const TextTitle = styled(Text)`
font-size: ${({ theme }) => rem(theme.pulsar.size.house)};
`;
Expand Down
40 changes: 5 additions & 35 deletions src/modules/scenes/Main/Metanodes/Earnings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@ import { getFiatAssetFormatter, Text, Tooltip } from '@swingby-protocol/pulsar';
import { FormattedMessage, useIntl } from 'react-intl';

import { Loader } from '../../../../../components/Loader';
import { IReward } from '../../../../metanodes';
import { IRewardV2 } from '../../../../metanodes';
import { IconInfo } from '../../../Common';

import { EarningsContainer, Row } from './styled';

interface Props {
reward: IReward | null;
reward: IRewardV2 | null;
isLoading: boolean;
}

export const Earnings = (props: Props) => {
const { locale } = useIntl();
const { reward, isLoading } = props;
const rewardsTotal = reward ? reward.total : 0;
const rewardsSwingby = reward ? reward.stakingRewards : 0;
// const rewardsSbBtcUsd = reward ? reward.networkRewards : 0;
const rewardsAvgPerNode = reward ? reward.avgPerNode : 0;
const rewardsSbBtc = reward ? reward.totalSbBtc : 0;

const earningTotal = getFiatAssetFormatter({
locale,
Expand All @@ -27,27 +25,6 @@ export const Earnings = (props: Props) => {
maximumFractionDigits: 0,
}).format(Number(rewardsTotal));

const earningSwingbyUsd = getFiatAssetFormatter({
locale,
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(Number(rewardsSwingby));

// const earningSbBtcUsd = getFiatAssetFormatter({
// locale,
// currency: 'USD',
// minimumFractionDigits: 0,
// maximumFractionDigits: 0,
// }).format(Number(rewardsSbBtcUsd));

const earningAvr = getFiatAssetFormatter({
locale,
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(Number(rewardsAvgPerNode));

const loader = <Loader marginTop={0} minHeight={68} />;

return (
Expand All @@ -60,7 +37,7 @@ export const Earnings = (props: Props) => {
content={
<Tooltip.Content>
<Text variant="accent">
<FormattedMessage id="metanodes.swingby" values={{ value: earningSwingbyUsd }} />
<FormattedMessage id="metanodes.swingby" values={{ value: earningTotal }} />
</Text>
<br />
{/* <Text variant="accent">
Expand All @@ -79,14 +56,7 @@ export const Earnings = (props: Props) => {
<Text variant="title-xs">{earningTotal}</Text>
</Row>
<div>
<Text variant="section-title">
<FormattedMessage
id="metanodes.earning-avr"
values={{
earningAvr,
}}
/>
</Text>
<Text variant="section-title">{rewardsSbBtc.toFixed(6)} sbBTC</Text>
</div>
</>
) : (
Expand Down
3 changes: 3 additions & 0 deletions src/modules/scenes/Main/Metanodes/MeatanodeInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useToggleMetanode } from '../../../../hooks';
import { ActionButtonMetanodes } from '../ActionButtonMetanodes';
import { BondToLiquidity } from '../BondToLiquidity';
import { Churning } from '../Churning';
import { Earnings } from '../Earnings';
import { GeneralInfo } from '../GeneralInfo';
import { LiquidityRatio } from '../LiquidityRatio';
import { MetanodeList } from '../MetanodeList';
Expand All @@ -22,6 +23,7 @@ export const MetanodeInfo = () => {
liquidity,
liquidityRatio,
churnTime,
rewardV2,
isLoading,
} = useToggleMetanode(PATH.METANODES);
return (
Expand All @@ -39,6 +41,7 @@ export const MetanodeInfo = () => {
<LiquidityRatio liquidityRatio={liquidityRatio} isLoading={isLoading} />
<Row>
<Churning churnTime={churnTime} isLoading={isLoading} />
<Earnings reward={rewardV2} isLoading={isLoading} />
</Row>
</Right>
</Top>
Expand Down
56 changes: 56 additions & 0 deletions src/pages/api/v1/rewards-last-week.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { SkybridgeBridge } from '@swingby-protocol/sdk';
import { NextApiRequest, NextApiResponse } from 'next';

import { corsMiddleware, getParam } from '../../../modules/api';
import { fetcher } from '../../../modules/fetch';
import { skypoolsEnabled, ENDPOINT_SKYBRIDGE_EXCHANGE, mode } from '../../../modules/env';

const isBridgeEnabled = (bridge: SkybridgeBridge): boolean => {
switch (bridge) {
case 'btc_skypool': {
return skypoolsEnabled;
}
default:
return skypoolsEnabled;
}
};

export default async function handler(
req: NextApiRequest,
res: NextApiResponse<{ currency: string; total: number; totalSbBtc: number; e?: string }>,
) {
await corsMiddleware({ req, res });
const bridge = getParam({ req, name: 'bridge' }) as SkybridgeBridge;
let reward = {
currency: 'USD',
total: 0,
totalSbBtc: 0,
};

if (!isBridgeEnabled(bridge)) {
return res.status(200).json(reward);
}

try {
const sbBtcPriceUrl = `${ENDPOINT_SKYBRIDGE_EXCHANGE}/${mode}/${bridge}/sbBTC/price`;

const results = await Promise.all([
fetcher<{ price: number; usdtPrice: number }>(sbBtcPriceUrl),
fetcher<{ result: { rows: { Amount: number }[] } }>(
`https://api.dune.com/api/v1/query/2364511/results?api_key=${process.env.DUNE_API_KEY}`,
),
]);

const sbBtcUsdtPrice = results[0].usdtPrice;
const currentReward = results[1].result.rows.find((row) => row.Amount > 0);
if (currentReward) {
reward.totalSbBtc = currentReward.Amount;
reward.total = currentReward.Amount * sbBtcUsdtPrice;
}

res.status(200).json(reward);
} catch (e) {
console.log(e);
res.status(500).json({ ...reward, e: e.message });
}
}

1 comment on commit 6fd44b7

@vercel
Copy link

@vercel vercel bot commented on 6fd44b7 Sep 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.