Skip to content

Commit

Permalink
Merge pull request #53 from oxen-io/staking_card_backend_generation
Browse files Browse the repository at this point in the history
Staking card backend generation & Fixes
  • Loading branch information
Aerilym authored Sep 26, 2024
2 parents 71de6a6 + 80ffe35 commit 301cb32
Show file tree
Hide file tree
Showing 41 changed files with 7,253 additions and 918 deletions.
6 changes: 6 additions & 0 deletions apps/staking/app/address/[address]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import ScreenContainer from '@/components/ScreenContainer';
import type { ReactNode } from 'react';

export default async function Layout({ children }: { children: ReactNode }) {
return <ScreenContainer>{children}</ScreenContainer>;
}
22 changes: 22 additions & 0 deletions apps/staking/app/address/[address]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { StakedNodesWithAddress } from '@/app/mystakes/modules/StakedNodesModule';
import { isAddress } from 'viem';
import { notFound } from 'next/navigation';
import { ModuleGrid } from '@session/ui/components/ModuleGrid';
import BalanceModule from '@/app/mystakes/modules/BalanceModule';
import TotalRewardsModule from '@/app/mystakes/modules/TotalRewardsModule';
import UnclaimedTokensModule from '@/app/mystakes/modules/UnclaimedTokensModule';

export default function Page({ params: { address } }: { params: { address: string } }) {
return isAddress(address) ? (
<div className="flex flex-col gap-4">
<ModuleGrid>
<BalanceModule addressOverride={address} />
<TotalRewardsModule addressOverride={address} />
<UnclaimedTokensModule addressOverride={address} />
</ModuleGrid>
<StakedNodesWithAddress address={address} />
</div>
) : (
notFound()
);
}
50 changes: 23 additions & 27 deletions apps/staking/app/mystakes/modules/BalanceModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,41 @@ import {
getVariableFontSizeForLargeModule,
ModuleDynamicQueryText,
} from '@/components/ModuleDynamic';
import { getTotalStakedAmountForAddressBigInt } from '@/components/NodeCard';
import type { ServiceNode } from '@session/sent-staking-js/client';
import type { Stake } from '@session/sent-staking-js/client';
import { Module, ModuleTitle } from '@session/ui/components/Module';
import { useWallet } from '@session/wallet/hooks/wallet-hooks';
import { useTranslations } from 'next-intl';
import { useMemo } from 'react';
import type { Address } from 'viem';
import { useStakingBackendQueryWithParams } from '@/lib/sent-staking-backend-client';
import { getStakedNodes } from '@/lib/queries/getStakedNodes';
import { generateMockNodeData } from '@session/sent-staking-js/test';
import type { QUERY_STATUS } from '@/lib/query';
import { formatSENTBigInt } from '@session/contracts/hooks/SENT';
import { FEATURE_FLAG } from '@/lib/feature-flags';
import { useFeatureFlag } from '@/lib/feature-flags-client';
import { generateMockNodeData } from '@session/sent-staking-js/test';

const getTotalStakedAmount = ({
nodes,
address,
}: {
nodes: Array<ServiceNode>;
address: Address;
}) => {
return formatSENTBigInt(
nodes.reduce(
(acc, node) => acc + getTotalStakedAmountForAddressBigInt(node.contributors, address),
BigInt(0)
)
const getTotalStakedAmount = ({ stakes }: { stakes: Array<Stake> }) =>
formatSENTBigInt(
stakes.reduce((acc, stake) => {
const stakedBalance = stake.staked_balance ?? BigInt(0);
return typeof stakedBalance !== 'bigint' ? acc + BigInt(stakedBalance) : acc + stakedBalance;
}, BigInt(0))
);
};

function useTotalStakedAmount() {
function useTotalStakedAmount(params?: { addressOverride?: Address }) {
const showMockNodes = useFeatureFlag(FEATURE_FLAG.MOCK_STAKED_NODES);
const showNoNodes = useFeatureFlag(FEATURE_FLAG.MOCK_NO_STAKED_NODES);

if (showMockNodes && showNoNodes) {
console.error('Cannot show mock nodes and no nodes at the same time');
}

const { address } = useWallet();
const { address: connectedAddress } = useWallet();
const address = useMemo(
() => params?.addressOverride ?? connectedAddress,
[params?.addressOverride, connectedAddress]
);

const { data, refetch, status } = useStakingBackendQueryWithParams(
getStakedNodes,
Expand All @@ -52,25 +48,25 @@ function useTotalStakedAmount() {
{ enabled: !!address }
);

const nodes = useMemo(() => {
const stakes = useMemo(() => {
if (!address || showNoNodes) {
return [];
} else if (showMockNodes) {
return generateMockNodeData({ userAddress: address }).nodes;
return generateMockNodeData({ userAddress: address }).stakes;
}
return data?.nodes ?? [];
return data?.stakes ?? [];
}, [data, showMockNodes, showNoNodes]);

const totalStakedAmount = useMemo(() => {
if (!address || !nodes.length) return null;
return getTotalStakedAmount({ nodes, address });
}, [nodes.length, address]);
const totalStakedAmount = useMemo(
() => (stakes ? getTotalStakedAmount({ stakes }) : null),
[stakes]
);

return { totalStakedAmount, status, refetch };
}

export default function BalanceModule() {
const { totalStakedAmount, status, refetch } = useTotalStakedAmount();
export default function BalanceModule({ addressOverride }: { addressOverride?: Address }) {
const { totalStakedAmount, status, refetch } = useTotalStakedAmount({ addressOverride });
const dictionary = useTranslations('modules.balance');
const toastDictionary = useTranslations('modules.toast');
const titleFormat = useTranslations('modules.title');
Expand Down
2 changes: 1 addition & 1 deletion apps/staking/app/mystakes/modules/ClaimTokensModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function ClaimTokensModule() {

const [rewards, blsSignature, excludedSigners] = useMemo(() => {
if (!rewardsClaimData) return [null, null, null];
const { amount, signature, non_signer_indices } = rewardsClaimData.bls_rewards_response;
const { amount, signature, non_signer_indices } = rewardsClaimData.result;

return [BigInt(amount), signature, non_signer_indices.map(BigInt)];
}, [rewardsClaimData]);
Expand Down
5 changes: 3 additions & 2 deletions apps/staking/app/mystakes/modules/DailyNodeReward.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { externalLink } from '@/lib/locale-defaults';
import { Module, ModuleTitle, ModuleTooltip } from '@session/ui/components/Module';
import { useTranslations } from 'next-intl';
import { useMemo } from 'react';
import { formatSENTNumber } from '@session/contracts/hooks/SENT';
import { formatSENTBigInt } from '@session/contracts/hooks/SENT';

export default function DailyNodeReward() {
const { dailyNodeReward, status, refetch } = useDailyNodeReward();
Expand All @@ -21,7 +21,8 @@ export default function DailyNodeReward() {
const title = dictionary('title');

const formattedDailyNodeRewardAmount = useMemo(
() => `~ ${formatSENTNumber(dailyNodeReward ?? 0, DYNAMIC_MODULE.SENT_ROUNDED_DECIMALS)}`,
() =>
`~ ${formatSENTBigInt(dailyNodeReward ?? BigInt(0), DYNAMIC_MODULE.SENT_ROUNDED_DECIMALS)}`,
[dailyNodeReward]
);

Expand Down
91 changes: 33 additions & 58 deletions apps/staking/app/mystakes/modules/StakedNodesModule.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
'use client';

import Loading from '@/app/loading';
import { GenericStakedNode, StakedNode, StakedNodeCard } from '@/components/StakedNodeCard';
import { generateStakeId, StakedNodeCard } from '@/components/StakedNodeCard';
import { WalletModalButtonWithLocales } from '@/components/WalletModalButtonWithLocales';
import { internalLink } from '@/lib/locale-defaults';
import { ButtonDataTestId } from '@/testing/data-test-ids';
import type { ServiceNode } from '@session/sent-staking-js/client';
import { generateMockNodeData } from '@session/sent-staking-js/test';
import {
ModuleGridContent,
ModuleGridHeader,
Expand All @@ -21,12 +19,12 @@ import Link from 'next/link';
import { useMemo } from 'react';
import { useStakingBackendQueryWithParams } from '@/lib/sent-staking-backend-client';
import { getStakedNodes } from '@/lib/queries/getStakedNodes';
import { getDateFromUnixTimestampSeconds, getUnixTimestampNowSeconds } from '@session/util/date';
import { SESSION_NODE } from '@/lib/constants';
import { EXPERIMENTAL_FEATURE_FLAG, FEATURE_FLAG } from '@/lib/feature-flags';
import { useExperimentalFeatureFlag, useFeatureFlag } from '@/lib/feature-flags-client';
import { Address } from 'viem';
import { generateMockNodeData } from '@session/sent-staking-js/test';

function StakedNodesWithAddress({ address }: { address: string }) {
export function StakedNodesWithAddress({ address }: { address: Address }) {
const showMockNodes = useFeatureFlag(FEATURE_FLAG.MOCK_STAKED_NODES);
const showNoNodes = useFeatureFlag(FEATURE_FLAG.MOCK_NO_STAKED_NODES);

Expand All @@ -38,32 +36,43 @@ function StakedNodesWithAddress({ address }: { address: string }) {
address,
});

const nodes = useMemo(() => {
const [stakes, blockHeight, networkTime] = useMemo(() => {
if (showMockNodes) {
return generateMockNodeData({ userAddress: address }).nodes;
} else if (showNoNodes) {
return [];
const mockResponse = generateMockNodeData({ userAddress: address });
return [
mockResponse.stakes,
mockResponse.network.block_height,
mockResponse.network.block_timestamp,
];
} else if (!data || showNoNodes) {
return [[], null, null];
}
return data?.nodes ?? [];

return [
data.stakes.concat(data.historical_stakes),
data.network.block_height,
data.network.block_timestamp,
];
}, [data, showMockNodes, showNoNodes]);

return (
<ModuleGridContent className="h-full md:overflow-y-auto">
{isLoading ? (
<Loading />
) : nodes.length ? (
nodes.map((node) => (
<StakedNodeCard
key={node.service_node_pubkey}
node={
parseSessionNodeData(
node,
data?.network?.block_height,
data?.network?.block_timestamp
) as StakedNode
}
/>
))
) : stakes?.length && blockHeight && networkTime ? (
stakes.map((node) => {
const key = generateStakeId(node);
return (
<StakedNodeCard
key={key}
uniqueId={key}
node={node}
blockHeight={blockHeight}
networkTime={networkTime}
targetWalletAddress={address}
/>
);
})
) : (
<NoNodes />
)}
Expand Down Expand Up @@ -126,37 +135,3 @@ function NoNodes() {
</ModuleGridInfoContent>
);
}

export const parseSessionNodeData = (
node: ServiceNode,
currentBlock: number = 0,
networkTime: number = getUnixTimestampNowSeconds()
): GenericStakedNode => {
return {
state: node.state,
contributors: node.contributors,
lastRewardHeight: 0,
lastUptime: getDateFromUnixTimestampSeconds(node.last_uptime_proof),
pubKey: node.service_node_pubkey,
balance: node.total_contributed,
operatorFee: node.operator_fee,
operator_address: node.operator_address,
contract_id: node.contract_id,
...(node.awaiting_liquidation ? { awaitingLiquidation: true } : {}),
...(node.decomm_blocks_remaining
? {
deregistrationDate: new Date(
networkTime * 1000 + node.decomm_blocks_remaining * SESSION_NODE.MS_PER_BLOCK
),
}
: {}),
...(node.requested_unlock_height
? {
unlockDate: new Date(
networkTime * 1000 +
(node.requested_unlock_height - currentBlock) * SESSION_NODE.MS_PER_BLOCK
),
}
: {}),
};
};
9 changes: 7 additions & 2 deletions apps/staking/app/mystakes/modules/TotalRewardsModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@ import {
import type { QUERY_STATUS } from '@/lib/query';
import { useMemo } from 'react';
import { formatSENTBigInt } from '@session/contracts/hooks/SENT';
import { Address } from 'viem';

export default function TotalRewardsModule() {
export default function TotalRewardsModule(params?: { addressOverride?: Address }) {
const dictionary = useTranslations('modules.totalRewards');
const toastDictionary = useTranslations('modules.toast');
const titleFormat = useTranslations('modules.title');
const title = dictionary('title');

const { address } = useWallet();
const { address: connectedAddress } = useWallet();
const address = useMemo(
() => params?.addressOverride ?? connectedAddress,
[params?.addressOverride, connectedAddress]
);

const { data, status, refetch } = useStakingBackendQueryWithParams(
getStakedNodes,
Expand Down
15 changes: 11 additions & 4 deletions apps/staking/app/mystakes/modules/UnclaimedTokensModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ import {
ModuleDynamicQueryText,
} from '@/components/ModuleDynamic';
import { formatSENTBigInt } from '@session/contracts/hooks/SENT';
import { Address } from 'viem';

export const useUnclaimedTokens = () => {
const { address } = useWallet();
export const useUnclaimedTokens = (params?: { addressOverride?: Address }) => {
const { address: connectedAddress } = useWallet();
const address = useMemo(
() => params?.addressOverride ?? connectedAddress,
[params?.addressOverride, connectedAddress]
);

const { data, status, refetch } = useStakingBackendQueryWithParams(
getStakedNodes,
Expand Down Expand Up @@ -47,13 +52,15 @@ export const useUnclaimedTokens = () => {
return { status, refetch, unclaimedRewards, formattedUnclaimedRewardsAmount, canClaim };
};

export default function UnclaimedTokensModule() {
export default function UnclaimedTokensModule({ addressOverride }: { addressOverride?: Address }) {
const dictionary = useTranslations('modules.unclaimedTokens');
const toastDictionary = useTranslations('modules.toast');
const titleFormat = useTranslations('modules.title');
const title = dictionary('title');

const { formattedUnclaimedRewardsAmount, status, refetch } = useUnclaimedTokens();
const { formattedUnclaimedRewardsAmount, status, refetch } = useUnclaimedTokens({
addressOverride,
});

return (
<Module>
Expand Down
Loading

0 comments on commit 301cb32

Please sign in to comment.