Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix open node list #15

Merged
merged 3 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions apps/staking/app/stake/OpenNodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,16 @@
import { OpenNodeCard } from '@/components/OpenNodeCard';
import { URL } from '@/lib/constants';
import { externalLink } from '@/lib/locale-defaults';
import { FEATURE_FLAG, useFeatureFlag } from '@/providers/feature-flag-provider';
import { useSessionStakingQuery } from '@/providers/sent-staking-provider';
import { OpenNode } from '@session/sent-staking-js/client';
import { generateOpenNodes } from '@session/sent-staking-js/test';
import {
ModuleGridContent,
ModuleGridHeader,
ModuleGridInfoContent,
ModuleGridTitle,
} from '@session/ui/components/ModuleGrid';
import { Loading } from '@session/ui/components/loading';
import { useWallet } from '@session/wallet/hooks/wallet-hooks';
import { useTranslations } from 'next-intl';
import { useMemo } from 'react';
import { useEffect, useState } from 'react';

export default function OpenNodesModule() {
const dictionary = useTranslations('modules.openNodes');
Expand All @@ -31,7 +27,9 @@ export default function OpenNodesModule() {
}

function OpenNodes() {
const showMockNodes = useFeatureFlag(FEATURE_FLAG.MOCK_OPEN_NODES);
const [loading, setLoading] = useState<boolean>(true);
const [nodes, setNodes] = useState<Array<OpenNode>>([]);
/* const showMockNodes = useFeatureFlag(FEATURE_FLAG.MOCK_OPEN_NODES);
const showNoNodes = useFeatureFlag(FEATURE_FLAG.MOCK_NO_OPEN_NODES);

if (showMockNodes && showNoNodes) {
Expand All @@ -44,21 +42,31 @@ function OpenNodes() {
args: undefined,
});

console.log(data);
console.log('no', showNoNodes);

const nodes = useMemo(() => {
if (showMockNodes) {
return generateOpenNodes({ userAddress: address });
} else if (showNoNodes) {
return [] as Array<OpenNode>;
}
return data?.nodes as Array<OpenNode>;
}, [data, showMockNodes, showNoNodes]);
}, [data?.nodes, showMockNodes, showNoNodes, address]); */

useEffect(() => {
fetch('/api/sent/nodes/open')
yougotwill marked this conversation as resolved.
Show resolved Hide resolved
.then((res) => res.json())
.then((data) => setNodes(data.nodes))
.then(() => setLoading(false));
}, []);

return (
<ModuleGridContent className="h-full md:overflow-y-auto">
{isLoading ? (
{loading ? (
<Loading />
) : nodes && nodes.length > 0 ? (
nodes.map((node) => <OpenNodeCard key={node.pubKey} node={node} />)
nodes.map((node) => <OpenNodeCard key={node.service_node_pubkey} node={node} />)
) : (
<NoNodes />
)}
Expand Down
51 changes: 30 additions & 21 deletions apps/staking/app/stake/node/[nodeId]/NodeStaking.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
'use client';

import { NodeContributorList, getTotalStakedAmount } from '@/components/NodeCard';
import { NodeContributorList } from '@/components/NodeCard';
import { PubKey } from '@/components/PubKey';
import { formatPercentage } from '@/lib/locale-client';
import { FEATURE_FLAG, useFeatureFlag } from '@/providers/feature-flag-provider';
import { useSessionStakingQuery } from '@/providers/sent-staking-provider';
import { ButtonDataTestId } from '@/testing/data-test-ids';
import { SENT_SYMBOL } from '@session/contracts';
import type { GetOpenNodesResponse, OpenNode } from '@session/sent-staking-js/client';
import { generateOpenNodes } from '@session/sent-staking-js/test';
import { Loading } from '@session/ui/components/loading';
import { Button } from '@session/ui/ui/button';
import { formatNumber } from '@session/util/maths';
import { useWallet } from '@session/wallet/hooks/wallet-hooks';
import { useTranslations } from 'next-intl';
import { useMemo, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { ActionModuleDivider, ActionModuleRow } from '../../ActionModule';

export default function NodeStaking({ nodeId }: { nodeId: string }) {
const showMockNodes = useFeatureFlag(FEATURE_FLAG.MOCK_OPEN_NODES);
const [loading, setLoading] = useState<boolean>(true);
const [nodes, setNodes] = useState<Array<OpenNode>>([]);
/* const showMockNodes = useFeatureFlag(FEATURE_FLAG.MOCK_OPEN_NODES);
const showNoNodes = useFeatureFlag(FEATURE_FLAG.MOCK_NO_OPEN_NODES);

const { address } = useWallet();
Expand All @@ -30,18 +28,25 @@ export default function NodeStaking({ nodeId }: { nodeId: string }) {
const { data, isLoading } = useSessionStakingQuery({
query: 'getOpenNodes',
args: undefined,
});
}); */

const node = useMemo(() => {
if (showMockNodes) {
/* if (showMockNodes) {
return generateOpenNodes({ userAddress: address })[0];
} else if (showNoNodes) {
return {} as OpenNode;
}
return data?.nodes.find((node) => node.pubKey === nodeId);
}, [data, nodeId, showMockNodes, showNoNodes]);
} */
return nodes?.find((node) => node.service_node_pubkey === nodeId);
}, [nodes]);

return isLoading ? (
useEffect(() => {
fetch('/api/sent/nodes/open')
yougotwill marked this conversation as resolved.
Show resolved Hide resolved
.then((res) => res.json())
.then((data) => setNodes(data.nodes))
.then(() => setLoading(false));
}, []);

return loading ? (
<Loading />
) : node ? (
<NodeStakingForm node={node} />
Expand All @@ -51,16 +56,18 @@ export default function NodeStaking({ nodeId }: { nodeId: string }) {
}

export function NodeStakingForm({ node }: { node: GetOpenNodesResponse['nodes'][number] }) {
const [value, setValue] = useState<number>(node.minContribution);
const dictionary = useTranslations('actionModules.node');
const generalDictionary = useTranslations('general');
const sessionNodeDictionary = useTranslations('sessionNodes.general');
const sessionNodeStakingDictionary = useTranslations('sessionNodes.staking');

const formattedTotalStakedAmount = useMemo(() => {
if (!node.contributors || node.contributors.length === 0) return '0';
return formatNumber(getTotalStakedAmount(node.contributors));
}, [node.contributors]);
if (!node.contributions || node.contributions.length === 0) return '0';
const totalStaked =
node.contributions.reduce((acc, contributor) => acc + contributor.amount, 0) /
Math.pow(10, 9);
return formatNumber(totalStaked);
}, [node.contributions]);

return (
<div className="flex flex-col gap-4">
Expand All @@ -69,7 +76,7 @@ export function NodeStakingForm({ node }: { node: GetOpenNodesResponse['nodes'][
tooltip={dictionary('contributorsTooltip')}
>
<span className="flex flex-row flex-wrap items-center gap-2 align-middle">
<NodeContributorList contributors={node.contributors} forceExpand showEmptySlots />
<NodeContributorList contributors={node.contributions} forceExpand showEmptySlots />
</span>
</ActionModuleRow>
<ActionModuleDivider />
Expand All @@ -84,21 +91,23 @@ export function NodeStakingForm({ node }: { node: GetOpenNodesResponse['nodes'][
label={sessionNodeDictionary('publicKeyShort')}
tooltip={sessionNodeDictionary('publicKeyDescription')}
>
<PubKey pubKey={node.pubKey} force="collapse" alwaysShowCopyButton />
<PubKey pubKey={node.service_node_pubkey} force="collapse" alwaysShowCopyButton />
</ActionModuleRow>
<ActionModuleDivider />
<ActionModuleRow
label={sessionNodeDictionary('operatorAddress')}
tooltip={sessionNodeDictionary('operatorAddressTooltip')}
>
<PubKey pubKey={node.operatorAddress} force="collapse" alwaysShowCopyButton />
{node.contributions[0]?.address ? (
<PubKey pubKey={node.contributions[0]?.address} force="collapse" alwaysShowCopyButton />
) : null}
</ActionModuleRow>
<ActionModuleDivider />
<ActionModuleRow
label={sessionNodeDictionary('operatorFee')}
tooltip={sessionNodeDictionary('operatorFeeDescription')}
>
{formatPercentage(node.operatorFee)}
{formatPercentage(node.fee / 10000)}
</ActionModuleRow>
<ActionModuleDivider />
{/* <SessionTokenInput
Expand Down
23 changes: 11 additions & 12 deletions apps/staking/components/OpenNodeCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { formatPercentage } from '@/lib/locale-client';
import { ButtonDataTestId } from '@/testing/data-test-ids';
import { SENT_SYMBOL } from '@session/contracts';
import type { OpenNode } from '@session/sent-staking-js/client';
import { generateMinAndMaxContribution } from '@session/sent-staking-js/test';
import { TextSeparator } from '@session/ui/components/Separator';
import { StatusIndicator } from '@session/ui/components/StatusIndicator';
import { cn } from '@session/ui/lib/utils';
Expand Down Expand Up @@ -40,17 +41,15 @@ const OpenNodeCard = forwardRef<
const stakingNodeDictionary = useTranslations('sessionNodes.staking');
const titleFormat = useTranslations('modules.title');

const { pubKey, operatorFee, minContribution, maxContribution } = node;
const { service_node_pubkey: pubKey, fee } = node;

const formattedMinContributon = useMemo(() => {
if (!minContribution) return '0';
return formatNumber(minContribution, 2);
}, [minContribution]);
const [formattedMinContributon, formattedMaxContribution] = useMemo(() => {
const { minContribution, maxContribution } = generateMinAndMaxContribution({
contributors: node.contributions,
});

const formattedMaxContributon = useMemo(() => {
if (!maxContribution) return '0';
return formatNumber(maxContribution, 2);
}, [maxContribution]);
return [formatNumber(minContribution, 2), formatNumber(maxContribution, 2)];
}, [node.contributions]);

return (
<NodeCard
Expand Down Expand Up @@ -86,19 +85,19 @@ const OpenNodeCard = forwardRef<
<NodeItem className="hidden md:block">
<NodeItemLabel>{titleFormat('format', { title: dictionary('max') })}</NodeItemLabel>
<NodeItemValue>
{formattedMaxContributon} {SENT_SYMBOL}
{formattedMaxContribution} {SENT_SYMBOL}
</NodeItemValue>
</NodeItem>
<NodeItemSeparator />
<NodeItem>
<NodeItemLabel>
{titleFormat('format', { title: generalNodeDictionary('operatorFeeShort') })}
</NodeItemLabel>
<NodeItemValue>{formatPercentage(operatorFee)}</NodeItemValue>
<NodeItemValue>{formatPercentage(fee / 10000)}</NodeItemValue>
</NodeItem>
</NodeCardText>
</div>
<Link href={`/stake/node/${node.pubKey}`} className="w-full sm:w-auto">
<Link href={`/stake/node/${pubKey}`} className="w-full sm:w-auto">
<Button
variant="outline"
size="md"
Expand Down
2 changes: 2 additions & 0 deletions apps/staking/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const getSENTStakingApiUrl = () => {
url += '/';
}

console.log('SENT Staking API URL:', url);

return url;
};

Expand Down
2 changes: 2 additions & 0 deletions apps/staking/providers/sent-staking-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ export function useSessionStakingQuery<Q extends keyof SessionStakingClient>({
queryFn,
});

console.log('qres', rest.data);

const status = useMemo(
() => parseQueryStatus({ isPending, isLoading, isSuccess, isError }),
[isLoading, isPending, isError, isSuccess]
Expand Down
15 changes: 9 additions & 6 deletions packages/sent-staking-js/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,15 @@ export interface ServiceNode {
}

export interface OpenNode {
pubKey: string;
operatorFee: number;
minContribution: number;
maxContribution: number;
contributors: Contributor[];
operatorAddress: string;
bls_pubkey: string;
cancelled: boolean;
contract: string;
contributions: Array<Contributor>;
fee: number;
finalized: boolean;
service_node_pubkey: string;
service_node_signature: string;
total_contributions: number;
}

export interface GetOpenNodesResponse {
Expand Down
32 changes: 16 additions & 16 deletions packages/sent-staking-js/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,26 +305,27 @@ export const generateMockNodeData = ({
return mockNodeData;
};

const generateMinAndMaxContribution = ({
export const generateMinAndMaxContribution = ({
contributors,
}: {
contributors: Array<Contributor>;
}): { minContribution: number; maxContribution: number } => {
const totalStaked = contributors.reduce((acc, contributor) => acc + contributor.amount, 0);
const totalStaked =
contributors.reduce((acc, contributor) => acc + contributor.amount, 0) / Math.pow(10, 9);
const remainingSlots = 10 - contributors.length;

if (remainingSlots === 0) {
return { minContribution: 0, maxContribution: 0 };
}

const remainingStake = 25000 - totalStaked;
const remainingStake = 240 - totalStaked;

return {
minContribution: Math.max(0, remainingStake / remainingSlots),
maxContribution: remainingStake,
};
};

/*
const generateOpenNode = ({
userAddress,
maxContributors,
Expand All @@ -336,18 +337,17 @@ const generateOpenNode = ({
const { minContribution, maxContribution } = generateMinAndMaxContribution({ contributors });

return {
pubKey: generateNodePubKey(),
operatorFee: Math.random(),
minContribution,
maxContribution,
contributors,
service_node_pubkey: generateNodePubKey(),
fee: Math.random(),
contributions,
operatorAddress: generateWalletAddress(),
};
};
}; */

export const generateOpenNodes = ({ userAddress }: { userAddress?: string }): Array<OpenNode> => {
return [
generateOpenNode({ maxContributors: 1 }),
export const generateOpenNodes =
(/* { userAddress }: { userAddress?: string } */): Array<OpenNode> => {
return [
/* generateOpenNode({ maxContributors: 1 }),
generateOpenNode({ maxContributors: 9 }),
generateOpenNode({ userAddress, maxContributors: 5 }),
generateOpenNode({ userAddress, maxContributors: 1 }),
Expand All @@ -359,6 +359,6 @@ export const generateOpenNodes = ({ userAddress }: { userAddress?: string }): Ar
generateOpenNode({ maxContributors: 5 }),
generateOpenNode({ userAddress, maxContributors: 5 }),
generateOpenNode({ userAddress, maxContributors: 10 }),
generateOpenNode({ userAddress, maxContributors: 10 }),
];
};
generateOpenNode({ userAddress, maxContributors: 10 }), */
];
};