Skip to content

Commit 83cd946

Browse files
committed
feat: aggregate total supply
1 parent 2069a17 commit 83cd946

File tree

3 files changed

+131
-16
lines changed

3 files changed

+131
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import {
2+
SuckerPair,
3+
readJbControllerTotalTokenSupplyWithReservedTokensOf,
4+
readJbDirectoryControllerOf
5+
} from "juice-sdk-core";
6+
import { useJBChainId, useJBContractContext, useSuckers } from "juice-sdk-react";
7+
8+
import { useConfig } from "wagmi";
9+
import { useQuery } from "wagmi/query";
10+
import { wagmiConfig } from "../wagmiConfig";
11+
12+
export function useSuckersTotalSupply() {
13+
const config = useConfig();
14+
15+
const chainId = useJBChainId();
16+
17+
const { projectId } = useJBContractContext();
18+
19+
const suckersQuery = useSuckers();
20+
const pairs: SuckerPair[] = suckersQuery.data ?? [];
21+
22+
const totalSupplyQuery = useQuery({
23+
queryKey: [
24+
"suckersTotalSupply",
25+
projectId?.toString() || "0",
26+
chainId?.toString() || "0",
27+
pairs?.map(p => p.peerChainId).join(",") || "noPairs",
28+
],
29+
queryFn: async () => {
30+
if (!chainId) return null;
31+
if (!pairs || pairs.length === 0) return [];
32+
33+
return await Promise.all(
34+
pairs.map(async pair => {
35+
const { peerChainId, projectId: peerProjectId } = pair;
36+
37+
const controllerAddress = await readJbDirectoryControllerOf(wagmiConfig, {
38+
chainId,
39+
args: [BigInt(projectId)],
40+
})
41+
42+
const totalSupply = await readJbControllerTotalTokenSupplyWithReservedTokensOf(config, {
43+
chainId: Number(peerChainId),
44+
address: controllerAddress,
45+
args: [peerProjectId],
46+
});
47+
48+
return {
49+
chainId: peerChainId,
50+
projectId: peerProjectId,
51+
totalSupply,
52+
};
53+
})
54+
);
55+
},
56+
});
57+
58+
return {
59+
isLoading: totalSupplyQuery.isLoading || suckersQuery.isLoading,
60+
isError: totalSupplyQuery.isError || suckersQuery.isError,
61+
data: totalSupplyQuery.data as
62+
| {
63+
chainId: number;
64+
projectId: bigint;
65+
totalSupply: bigint;
66+
}[]
67+
| undefined,
68+
};
69+
}

src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4TokensPanel.tsx

+12-15
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
import { SettingOutlined } from '@ant-design/icons'
2-
import { t, Trans } from '@lingui/macro'
1+
import { Trans, t } from '@lingui/macro'
32
import { Button, Tooltip } from 'antd'
4-
import { AddTokenToMetamaskButton } from 'components/buttons/AddTokenToMetamaskButton'
5-
import EthereumAddress from 'components/EthereumAddress'
6-
import { TitleDescriptionDisplayCard } from 'components/Project/ProjectTabs/TitleDescriptionDisplayCard'
7-
import { ISSUE_ERC20_EXPLANATION } from 'components/strings'
8-
import { NETWORKS } from 'constants/networks'
9-
import { formatUnits, JB_TOKEN_DECIMALS, JBChainId } from 'juice-sdk-core'
3+
import { JBChainId, JB_TOKEN_DECIMALS, formatUnits } from 'juice-sdk-core'
104
import {
115
useJBChainId,
126
useJBContractContext,
137
useSuckersUserTokenBalance
148
} from 'juice-sdk-react'
9+
import { useCallback, useMemo, useState } from 'react'
10+
11+
import { SettingOutlined } from '@ant-design/icons'
12+
import { AddTokenToMetamaskButton } from 'components/buttons/AddTokenToMetamaskButton'
13+
import EthereumAddress from 'components/EthereumAddress'
14+
import { TitleDescriptionDisplayCard } from 'components/Project/ProjectTabs/TitleDescriptionDisplayCard'
15+
import { ISSUE_ERC20_EXPLANATION } from 'components/strings'
16+
import { NETWORKS } from 'constants/networks'
1517
import { ChainLogo } from 'packages/v4/components/ChainLogo'
1618
import { V4TokenHoldersModal } from 'packages/v4/components/modals/V4TokenHoldersModal/V4TokenHoldersModal'
1719
import { useProjectHasErc20Token } from 'packages/v4/hooks/useProjectHasErc20Token'
1820
import { v4ProjectRoute } from 'packages/v4/utils/routes'
19-
import { useCallback, useMemo, useState } from 'react'
2021
import { reloadWindow } from 'utils/windowUtils'
2122
import { useV4BalanceMenuItemsUserFlags } from './hooks/useV4BalanceMenuItemsUserFlags'
2223
import { useV4TokensPanel } from './hooks/useV4TokensPanel'
@@ -27,7 +28,7 @@ import { V4ReservedTokensSubPanel } from './V4ReservedTokensSubPanel'
2728
import { V4TokenRedemptionCallout } from './V4TokenRedemptionCallout'
2829

2930
export const V4TokensPanel = () => {
30-
const { userTokenBalanceLoading, projectToken, totalSupply } =
31+
const { userTokenBalanceLoading, projectToken, totalTokenSupplyElement } =
3132
useV4TokensPanel()
3233
const projectHasErc20Token = useProjectHasErc20Token()
3334
const { data: suckersBalance } = useSuckersUserTokenBalance()
@@ -149,11 +150,7 @@ export const V4TokensPanel = () => {
149150
<TitleDescriptionDisplayCard
150151
className="w-full"
151152
title={t`Total supply`}
152-
description={
153-
<span>
154-
{totalSupply.format(8)} {projectToken}
155-
</span>
156-
}
153+
description={totalTokenSupplyElement}
157154
/>
158155
</div>
159156
<a

src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4TokensPanel.ts src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4TokensPanel.tsx

+50-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
import { JBProjectToken } from 'juice-sdk-core'
1+
import { JBChainId, JBProjectToken } from 'juice-sdk-core'
2+
3+
import { Tooltip } from 'antd'
4+
import { NETWORKS } from 'constants/networks'
25
import { useJBTokenContext } from 'juice-sdk-react'
6+
import { ChainLogo } from 'packages/v4/components/ChainLogo'
37
import { useV4UserTotalTokensBalance } from 'packages/v4/contexts/V4UserTotalTokensBalanceProvider'
48
import { useProjectHasErc20Token } from 'packages/v4/hooks/useProjectHasErc20Token'
9+
import { useSuckersTotalSupply } from 'packages/v4/hooks/useSuckersTotalSupply'
510
import { useV4TotalTokenSupply } from 'packages/v4/hooks/useV4TotalTokenSupply'
611
import { useV4WalletHasPermission } from 'packages/v4/hooks/useV4WalletHasPermission'
712
import { V4OperatorPermission } from 'packages/v4/models/v4Permissions'
@@ -35,6 +40,49 @@ export const useV4TokensPanel = () => {
3540
// const { totalLegacyTokenBalance, v1ClaimedBalance } =
3641
// useTotalLegacyTokenBalance({ projectId })
3742

43+
const { data: suckersTotalSupply } = useSuckersTotalSupply()
44+
const aggregatedTotalSupply =
45+
suckersTotalSupply?.reduce(
46+
(acc, curr) => acc + curr.totalSupply,
47+
0n,
48+
) ?? 0n
49+
50+
const _aggregatedTotalSupply = new JBProjectToken(aggregatedTotalSupply)
51+
52+
const totalTokenSupplyElement = (
53+
<Tooltip
54+
title={
55+
suckersTotalSupply?.length &&
56+
suckersTotalSupply.length > 0 ? (
57+
<div className="flex flex-col gap-2">
58+
{suckersTotalSupply.map(({ chainId, totalSupply }) => {
59+
const _totalSupply = new JBProjectToken(totalSupply)
60+
return (
61+
<div
62+
className="flex items-center justify-between gap-4"
63+
key={chainId}
64+
>
65+
<div className="flex items-center gap-2">
66+
<ChainLogo chainId={chainId as JBChainId} />
67+
<span>{NETWORKS[chainId].label}</span>
68+
</div>
69+
<span className="whitespace-nowrap font-medium">
70+
{_totalSupply.format(8)}{' '}
71+
{projectToken}
72+
</span>
73+
</div>
74+
)
75+
})}
76+
</div>
77+
) : undefined
78+
}
79+
>
80+
<span>
81+
{_aggregatedTotalSupply.format(8)}
82+
</span>
83+
</Tooltip>
84+
)
85+
3886
const totalTokenSupply = new JBProjectToken(_totalTokenSupply ?? 0n)
3987

4088
const canCreateErc20Token = !projectHasErc20Token && hasDeployErc20Permission
@@ -48,6 +96,7 @@ export const useV4TokensPanel = () => {
4896
projectToken,
4997
projectTokenAddress: tokenAddress,
5098
totalSupply: totalTokenSupply,
99+
totalTokenSupplyElement,
51100
projectHasErc20Token,
52101
canCreateErc20Token,
53102
}

0 commit comments

Comments
 (0)