From 8702a49cc7d5b0bde62cdc8b12fad91070ca00ad Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Mon, 16 Jun 2025 20:27:39 +0530 Subject: [PATCH 01/19] [TOOL-4689] Dashboard: Integrate ERC20Asset contract in token creation flow --- .../tables/contract-table.tsx | 1 + apps/dashboard/src/@/components/ui/tabs.tsx | 8 +- .../src/@/hooks/project-contracts.ts | 2 +- .../tokens/create/_common/step-card.tsx | 2 +- .../nft-collection-info-fieldset.tsx | 3 +- .../tokens/create/nft/create-nft-page-ui.tsx | 11 +- .../tokens/create/token/_common/form.ts | 29 +- .../create/token/create-token-page-impl.tsx | 231 +++-------- .../create/token/create-token-page.client.tsx | 31 +- .../token/create-token-page.stories.tsx | 17 +- .../token/distribution/token-airdrop.tsx | 4 +- .../create/token/distribution/token-sale.tsx | 377 ++++++++++++++---- .../create/token/launch/launch-token.tsx | 14 - .../token/token-info/token-info-fieldset.tsx | 3 +- 14 files changed, 418 insertions(+), 315 deletions(-) diff --git a/apps/dashboard/src/@/components/contract-components/tables/contract-table.tsx b/apps/dashboard/src/@/components/contract-components/tables/contract-table.tsx index 27ba135d3fd..e608e879c03 100644 --- a/apps/dashboard/src/@/components/contract-components/tables/contract-table.tsx +++ b/apps/dashboard/src/@/components/contract-components/tables/contract-table.tsx @@ -300,6 +300,7 @@ const contractTypeToAssetTypeRecord: Record = { DropERC20: "Coin", DropERC721: "NFT Collection", DropERC1155: "NFT Collection", + ERC20Asset: "Coin", }; const NetworkFilterCell = React.memo(function NetworkFilterCell({ diff --git a/apps/dashboard/src/@/components/ui/tabs.tsx b/apps/dashboard/src/@/components/ui/tabs.tsx index 47acea12b5d..a2239f181ef 100644 --- a/apps/dashboard/src/@/components/ui/tabs.tsx +++ b/apps/dashboard/src/@/components/ui/tabs.tsx @@ -98,6 +98,7 @@ export function TabButtons(props: { shadowColor?: string; tabIconClassName?: string; hideBottomLine?: boolean; + bottomLineClassName?: string; }) { const { containerRef, lineRef, activeTabRef } = useUnderline(); @@ -106,7 +107,12 @@ export function TabButtons(props: {
{/* Bottom line */} {!props.hideBottomLine && ( -
+
)} { const res = await apiServerProxy({ body: JSON.stringify({ diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/step-card.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/step-card.tsx index fa14752c80f..316ee8b824f 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/step-card.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/_common/step-card.tsx @@ -35,7 +35,7 @@ export function StepCard(props: { {props.children} {(props.prevButton || props.nextButton) && ( -
+
{props.prevButton && ( +
+ ); +} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/page.tsx new file mode 100644 index 00000000000..5cd5d7de07e --- /dev/null +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/page.tsx @@ -0,0 +1,91 @@ +import { notFound, redirect } from "next/navigation"; +import { getContract } from "thirdweb"; +import { + getDeployedEntrypointERC20, + getRewardLocker, + v3PositionManager as getV3PositionManager, +} from "thirdweb/assets"; +import { getProject } from "@/api/projects"; +import { getContractPageParamsInfo } from "../../../../../../../(dashboard)/(chain)/[chain_id]/[contractAddress]/_utils/getContractFromParams"; +import type { ProjectContractPageParams } from "../types"; +import { ClaimRewardsPage } from "./components/claim-rewards-page"; +import { getValidReward } from "./utils/rewards"; + +export default async function Page(props: { + params: Promise; +}) { + const params = await props.params; + const project = await getProject(params.team_slug, params.project_slug); + + if (!project) { + notFound(); + } + + const info = await getContractPageParamsInfo({ + chainIdOrSlug: params.chainIdOrSlug, + contractAddress: params.contractAddress, + teamId: project.teamId, + }); + + if (!info) { + notFound(); + } + + const assetContractClient = info.clientContract; + + const entrypointContractClient = await getDeployedEntrypointERC20({ + chain: assetContractClient.chain, + client: assetContractClient.client, + }); + + const reward = await getValidReward({ + assetContract: assetContractClient, + entrypointContract: entrypointContractClient, + }); + + const rewardLocker = await getRewardLocker({ + contract: entrypointContractClient, + }).catch(() => null); + + if (!reward || !rewardLocker) { + redirect( + `/team/${params.team_slug}/${params.project_slug}/contract/${params.chainIdOrSlug}/${params.contractAddress}`, + ); + } + + const rewardLockerContractClient = getContract({ + address: rewardLocker, + chain: assetContractClient.chain, + client: assetContractClient.client, + }); + + const v3PositionManager = await getV3PositionManager({ + contract: rewardLockerContractClient, + }).catch(() => null); + + // const v4PositionManager = await getV4PositionManager({ + // contract: rewardLockerContractClient, + // }).catch(() => null); + + if (!v3PositionManager || v3PositionManager !== reward.positionManager) { + redirect( + `/team/${params.team_slug}/${params.project_slug}/contract/${params.chainIdOrSlug}/${params.contractAddress}`, + ); + } + + const v3PositionManagerContract = getContract({ + address: reward.positionManager, + chain: assetContractClient.chain, + client: assetContractClient.client, + }); + + return ( + + ); +} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/utils/rewards.ts b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/utils/rewards.ts new file mode 100644 index 00000000000..7c6283d0100 --- /dev/null +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/utils/rewards.ts @@ -0,0 +1,28 @@ +import { type ThirdwebContract, ZERO_ADDRESS } from "thirdweb"; +import { getReward } from "thirdweb/assets"; + +export async function getValidReward(params: { + assetContract: ThirdwebContract; + entrypointContract: ThirdwebContract; +}) { + try { + const reward = await getReward({ + contract: params.entrypointContract, + asset: params.assetContract.address, + }); + + if ( + reward.positionManager === ZERO_ADDRESS || + reward.recipient === ZERO_ADDRESS || + reward.referrer === ZERO_ADDRESS || + reward.referrerBps === 0 || + reward.tokenId === BigInt(0) + ) { + return null; + } + + return reward; + } catch { + return null; + } +} diff --git a/packages/thirdweb/src/exports/assets.ts b/packages/thirdweb/src/exports/assets.ts index a2cbef1ae7a..71967483f99 100644 --- a/packages/thirdweb/src/exports/assets.ts +++ b/packages/thirdweb/src/exports/assets.ts @@ -18,5 +18,10 @@ export type { PoolConfig, TokenParams, } from "../assets/types.js"; -export { getInitBytecodeWithSalt } from "../utils/any-evm/get-init-bytecode-with-salt.js"; export { getReward } from "../extensions/assets/__generated__/ERC20AssetEntrypoint/read/getReward.js"; +export { getRewardLocker } from "../extensions/assets/__generated__/ERC20AssetEntrypoint/read/getRewardLocker.js"; +export { claimReward } from "../extensions/assets/__generated__/ERC20AssetEntrypoint/write/claimReward.js"; +export { positions } from "../extensions/assets/__generated__/RewardLocker/read/positions.js"; +export { v3PositionManager } from "../extensions/assets/__generated__/RewardLocker/read/v3PositionManager.js"; +export { v4PositionManager } from "../extensions/assets/__generated__/RewardLocker/read/v4PositionManager.js"; +export { getInitBytecodeWithSalt } from "../utils/any-evm/get-init-bytecode-with-salt.js"; From 6bfce15daeb3c13d82c83b11b087dbc9a3c12229 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Wed, 16 Jul 2025 20:49:32 +0530 Subject: [PATCH 10/19] load amounts --- .../components/claim-rewards-page.tsx | 85 +++++++++++-------- .../claim-rewards/utils/unclaimed-fees.ts | 63 ++++++++++++++ 2 files changed, 114 insertions(+), 34 deletions(-) create mode 100644 apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/utils/unclaimed-fees.ts diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/components/claim-rewards-page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/components/claim-rewards-page.tsx index 43e7f9984b2..7eb9be51c7e 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/components/claim-rewards-page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/components/claim-rewards-page.tsx @@ -2,15 +2,17 @@ import { useQuery } from "@tanstack/react-query"; import { ArrowRightIcon } from "lucide-react"; -import { readContract, type ThirdwebContract } from "thirdweb"; +import { toast } from "sonner"; +import type { ThirdwebContract } from "thirdweb"; import { claimReward } from "thirdweb/assets"; import { useSendAndConfirmTransaction } from "thirdweb/react"; +import { WalletAddress } from "@/components/blocks/wallet-address"; import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/Spinner/Spinner"; import { parseError } from "@/utils/errorParser"; +import { tryCatch } from "@/utils/try-catch"; import type { getValidReward } from "../utils/rewards"; - -const maxInt128 = 2n ** (128n - 1n) - 1n; +import { getUnclaimedFees } from "../utils/unclaimed-fees"; export function ClaimRewardsPage(props: { assetContractClient: ThirdwebContract; @@ -22,44 +24,47 @@ export function ClaimRewardsPage(props: { const sendAndConfirmTransaction = useSendAndConfirmTransaction(); async function handleClaim() { - const tx = claimReward({ + const claimRewardsTx = claimReward({ asset: props.assetContractClient.address, contract: props.rewardLockerContractClient, }); - await sendAndConfirmTransaction.mutateAsync(tx); + const claimRewardsResult = await tryCatch( + sendAndConfirmTransaction.mutateAsync(claimRewardsTx), + ); + + if (claimRewardsResult.error) { + toast.error("Failed to claim rewards", { + description: parseError(claimRewardsResult.error), + }); + } else { + toast.success("Rewards claimed successfully"); + } } - const collectionQuery = useQuery({ + const unclaimedFeesQuery = useQuery({ queryKey: [ - "unclaimed-fees", + "get-unclaimed-fees", { - ...props, + positionManager: props.v3PositionManagerContractClient.address, reward: { - ...props.reward, - tokenId: props.reward?.tokenId.toString(), + tokenId: props.reward.tokenId.toString(), + recipient: props.reward.recipient, }, }, ], - queryFn: async () => { - const result = await readContract({ - contract: props.v3PositionManagerContractClient, - method: - "function collect((uint256 tokenId,address recipient,uint128 amount0Max,uint128 amount1Max)) returns (uint256,uint256)", - params: [ - { - tokenId: props.reward.tokenId, - recipient: props.reward.recipient, - amount0Max: maxInt128, - amount1Max: maxInt128, - }, - ], - }); - - return result; - }, + queryFn: async () => + getUnclaimedFees({ + positionManager: props.v3PositionManagerContractClient, + reward: { + tokenId: props.reward.tokenId, + recipient: props.reward.recipient, + }, + }), }); + // TODO: add proper UI + return (

@@ -67,24 +72,36 @@ export function ClaimRewardsPage(props: {

- {collectionQuery.isPending && ( + {unclaimedFeesQuery.isPending && (
Loading unclaimed fees
)} - {collectionQuery.error && ( + {unclaimedFeesQuery.error && (
- Failed to load unclaimed fees {parseError(collectionQuery.error)} + Failed to load unclaimed fees {parseError(unclaimedFeesQuery.error)}
)} - {collectionQuery.data && ( -
-

Amount0: {collectionQuery.data[0]}

-

Amount1: {collectionQuery.data[1]}

+ {unclaimedFeesQuery.data && ( +
+

+ Amount0: {unclaimedFeesQuery.data.token0.amount}{" "} + {unclaimedFeesQuery.data.token0.address} +

+

+ Amount1: {unclaimedFeesQuery.data.token1.amount}{" "} + {unclaimedFeesQuery.data.token1.address} +

)} + +

Recipient

+
-
- ); -} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/components/claim-rewards-page.stories.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.stories.tsx similarity index 73% rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/components/claim-rewards-page.stories.tsx rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.stories.tsx index 7e937c9e62a..e324f36bf65 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/components/claim-rewards-page.stories.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.stories.tsx @@ -1,5 +1,6 @@ import type { Meta } from "@storybook/nextjs"; import { toUnits } from "thirdweb"; +import { base } from "thirdweb/chains"; import { ThirdwebProvider } from "thirdweb/react"; import { storybookThirdwebClient } from "@/storybook/utils"; import { ClaimRewardsPageUI } from "./claim-rewards-page"; @@ -10,7 +11,7 @@ const meta = { decorators: [ (Story) => ( -
+
@@ -28,10 +29,12 @@ function unclaimedFeesStub(token0Amount: bigint, token1Amount: bigint) { token0: { address: "0x1234567890123456789012345678901234567890", amount: token0Amount, + symbol: "FOO", }, token1: { address: "0x0987654321098765432109876543210987654321", amount: token1Amount, + symbol: "BAR", }, }; } @@ -41,6 +44,7 @@ export function LargeAmounts() { ); } @@ -50,24 +54,42 @@ export function SmallAmounts() { ); } -export function ZeroAmounts() { +export function ZeroAmount() { + return ( + + ); +} + +export function ZeroAmountNoChainExplorer() { return ( ); } -function Variant(props: { token0Amount: bigint; token1Amount: bigint }) { +function Variant(props: { + token0Amount: bigint; + token1Amount: bigint; + includeChainExplorer?: boolean; +}) { return ( {}} isClaimPending={false} + chain={base} unclaimedFees={unclaimedFeesStub(props.token0Amount, props.token1Amount)} /> ); diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx new file mode 100644 index 00000000000..dafeb0de9ea --- /dev/null +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx @@ -0,0 +1,304 @@ +"use client"; + +import { ArrowRightIcon, ExternalLinkIcon } from "lucide-react"; +import Link from "next/link"; +import { toast } from "sonner"; +import { + type Chain, + type ThirdwebClient, + type ThirdwebContract, + toTokens, +} from "thirdweb"; +import { claimReward } from "thirdweb/assets"; +import { TokenIcon, TokenProvider, useSendTransaction } from "thirdweb/react"; +import { DistributionBarChart } from "@/components/blocks/distribution-chart"; +import { WalletAddress } from "@/components/blocks/wallet-address"; +import { Button } from "@/components/ui/button"; +import { Spinner } from "@/components/ui/Spinner/Spinner"; +import { useDashboardRouter } from "@/lib/DashboardRouter"; +import { parseError } from "@/utils/errorParser"; +import { tryCatch } from "@/utils/try-catch"; +import type { getValidReward } from "../utils/rewards"; + +export function ClaimRewardsPage(props: { + assetContractClient: ThirdwebContract; + entrypointContractClient: ThirdwebContract; + reward: NonNullable>>; + unclaimedFees: { + token0: { + address: string; + amount: bigint; + symbol: string; + }; + token1: { + address: string; + amount: bigint; + symbol: string; + }; + }; + chainSlug: string; +}) { + const sendTx = useSendTransaction(); + const router = useDashboardRouter(); + + async function handleClaim() { + const claimRewardsTx = claimReward({ + asset: props.assetContractClient.address, + contract: props.entrypointContractClient, + }); + + const claimRewardsResult = await tryCatch( + sendTx.mutateAsync(claimRewardsTx), + ); + + if (claimRewardsResult.error) { + toast.error("Failed to claim rewards", { + description: parseError(claimRewardsResult.error), + }); + } else { + toast.success("Rewards claimed successfully"); + router.refresh(); + } + } + + return ( + + ); +} + +function calculateFees(referrerBps: number) { + // 20% of is protocol fees + // remaining is split between referrer and recipient + + const protocolFees = 20; + const remaining = 100 - protocolFees; + + const referrerPercentageFinal = (remaining * referrerBps) / 10000; + + return { + protocolFees, + referrerPercentage: referrerPercentageFinal, + recipientPercentage: 100 - protocolFees - referrerPercentageFinal, + }; +} + +export function ClaimRewardsPageUI(props: { + unclaimedFees: { + token0: { + address: string; + amount: bigint; + symbol: string; + }; + token1: { + address: string; + amount: bigint; + symbol: string; + }; + }; + recipient: string; + referrer: string; + referrerBps: number; + handleClaim: () => void; + isClaimPending: boolean; + client: ThirdwebClient; + chain: Chain; + chainSlug: string; +}) { + const fees = calculateFees(props.referrerBps); + + const recipientColor = `hsl(var(--chart-1))`; + const referrerColor = `hsl(var(--chart-2))`; + const protocolFeesColor = `hsl(var(--chart-10))`; + + const hasUnclaimedRewards = + props.unclaimedFees.token0.amount > 0 || + props.unclaimedFees.token1.amount > 0; + + return ( +
+
+
+

+ Uniswap LP Rewards +

+

+ Earnings received by Liquidity Providers (LPs) in exchange for + depositing tokens into {props.unclaimedFees.token0.symbol} /{" "} + {props.unclaimedFees.token1.symbol} Uniswap liquidity pool +

+
+ +
+
+

Unclaimed Rewards

+
+
+ + +
+
+ +
+ + +
+ +
+
+

Recipient

+ + } + /> +
+ +
+

Referrer

+ + } + /> +
+
+
+ +
+ {hasUnclaimedRewards && ( +

+ Click on "Distribute Rewards" to distribute unclaimed rewards +

+ )} + + {!hasUnclaimedRewards && ( +

+ No unclaimed rewards to distribute +

+ )} + +
+
+
+ ); +} + +function TokenReward(props: { + token: { + address: string; + amount: bigint; + symbol: string; + }; + client: ThirdwebClient; + chain: Chain; + chainSlug: string; +}) { + const fallbackIcon = ( +
+ {props.token.symbol[0]} +
+ ); + + return ( +
+
+ + + +
+
+

+ {toTokens(props.token.amount, 18)} {props.token.symbol} +

+ + + {props.token.address.slice(0, 6)}... + {props.token.address.slice(-4)} + + + +
+
+ ); +} diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/page.tsx similarity index 98% rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/page.tsx rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/page.tsx index 3d53487686f..eecf4a3d445 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/page.tsx @@ -90,6 +90,7 @@ export default async function Page(props: { entrypointContractClient={entrypointContractClient} reward={reward} unclaimedFees={unclaimedFees} + chainSlug={info.chainMetadata.slug} /> ); } diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/utils/rewards.ts b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/utils/rewards.ts similarity index 100% rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/utils/rewards.ts rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/utils/rewards.ts diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/utils/unclaimed-fees.ts b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/utils/unclaimed-fees.ts similarity index 66% rename from apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/utils/unclaimed-fees.ts rename to apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/utils/unclaimed-fees.ts index 2306481692d..16c1284602e 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/claim-rewards/utils/unclaimed-fees.ts +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/utils/unclaimed-fees.ts @@ -1,5 +1,6 @@ import type { ThirdwebContract } from "thirdweb"; -import { readContract } from "thirdweb"; +import { getContract, readContract } from "thirdweb"; +import { symbol } from "thirdweb/extensions/common"; export const maxUint128 = 2n ** 128n - 1n; @@ -36,7 +37,6 @@ export async function getUnclaimedFees(params: { positionsResultPromise, ]); - // positionsResult // 0- nonce // 1- owner // 2- token0 @@ -50,14 +50,39 @@ export async function getUnclaimedFees(params: { // 10 - tokensOwed0 // 11 - tokensOwed1 + const client = params.positionManager.client; + const chain = params.positionManager.chain; + + const token0Address = positionsResult[2]; + const token1Address = positionsResult[3]; + + const [token0Symbol, token1Symbol] = await Promise.all([ + symbol({ + contract: getContract({ + address: token0Address, + chain, + client, + }), + }), + symbol({ + contract: getContract({ + address: token1Address, + chain, + client, + }), + }), + ]); + return { token0: { - address: positionsResult[2], // token0 + address: token0Address, amount: collectResult[0], + symbol: token0Symbol, }, token1: { - address: positionsResult[3], // token1 + address: token1Address, amount: collectResult[1], + symbol: token1Symbol, }, }; } From e946458827e7d309e01e9610ff8034bc62ffb753 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Thu, 17 Jul 2025 00:54:50 +0530 Subject: [PATCH 13/19] copy changes --- .../rewards/components/claim-rewards-page.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx index dafeb0de9ea..708e1638cb3 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx @@ -52,11 +52,11 @@ export function ClaimRewardsPage(props: { ); if (claimRewardsResult.error) { - toast.error("Failed to claim rewards", { + toast.error("Failed to distribute rewards", { description: parseError(claimRewardsResult.error), }); } else { - toast.success("Rewards claimed successfully"); + toast.success("Rewards distributed successfully"); router.refresh(); } } @@ -128,7 +128,7 @@ export function ClaimRewardsPageUI(props: {
-

+

Uniswap LP Rewards

@@ -221,7 +221,7 @@ export function ClaimRewardsPageUI(props: {

-
+
{hasUnclaimedRewards && (

Click on "Distribute Rewards" to distribute unclaimed rewards @@ -230,7 +230,7 @@ export function ClaimRewardsPageUI(props: { {!hasUnclaimedRewards && (

- No unclaimed rewards to distribute + There are no unclaimed rewards available for distribution

)} + + + + +
))} @@ -183,6 +222,34 @@ function RecentTransfersUI(props: { ); } +function timestamp(block_timestamp: string) { + return formatDistanceToNow( + new Date( + block_timestamp.endsWith("Z") ? block_timestamp : `${block_timestamp}Z`, + ), + { + addSuffix: true, + }, + ); +} + +function TokenAmount(props: { + amount: string; + decimals: number; + symbol: string; +}) { + return ( +
+ + {tokenAmountFormatter.format( + Number(toTokens(BigInt(props.amount), props.decimals)), + )} + + {props.symbol} +
+ ); +} + function SkeletonRow() { return ( @@ -199,7 +266,7 @@ function SkeletonRow() { - + ); From 1366058d963195b9ea29be95b0af20b1e8792030 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Fri, 18 Jul 2025 04:08:54 +0530 Subject: [PATCH 15/19] update creation UI --- .../create/token/create-token-page.client.tsx | 10 ++-- .../token/distribution/token-distribution.tsx | 9 +++- .../create/token/distribution/token-sale.tsx | 53 +++++++++++++------ 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page.client.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page.client.tsx index 3187173a3c0..cec518d549b 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page.client.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page.client.tsx @@ -49,7 +49,7 @@ export function CreateTokenAssetPageUI(props: { const tokenInfoForm = useForm({ defaultValues: { - chain: activeChain?.id.toString() || "1", + chain: activeChain?.id.toString() || "8453", description: "", image: undefined, name: "", @@ -75,12 +75,12 @@ export function CreateTokenAssetPageUI(props: { // airdrop airdropEnabled: false, pool: { - startingPricePerToken: "0.01", + startingPricePerToken: "0.000000001", // 1gwei per token }, // sale fieldset - saleAllocationPercentage: "0", - saleMode: "disabled", - supply: "1000000", + saleAllocationPercentage: "100", + saleMode: "pool", + supply: "1000000000", // 1 billion }, mode: "onChange", resolver: zodResolver(tokenDistributionFormSchema), diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-distribution.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-distribution.tsx index b15dba1adb1..0627a5bc5d5 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-distribution.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-distribution.tsx @@ -17,6 +17,11 @@ import type { import { TokenAirdropSection } from "./token-airdrop"; import { TokenSaleSection } from "./token-sale"; +const compactNumberFormatter = new Intl.NumberFormat("en-US", { + maximumFractionDigits: 10, + notation: "compact", +}); + export function TokenDistributionFieldset(props: { accountAddress: string; onNext: () => void; @@ -49,6 +54,7 @@ export function TokenDistributionFieldset(props: { @@ -73,12 +79,13 @@ export function TokenDistributionFieldset(props: {
- + +
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx index d14fbc83822..f72476d643e 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx @@ -2,14 +2,14 @@ import { useQuery } from "@tanstack/react-query"; import { XIcon } from "lucide-react"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import type { ThirdwebClient } from "thirdweb"; import { defineChain } from "thirdweb"; import { isRouterEnabled } from "thirdweb/assets"; import { FormFieldSetup } from "@/components/blocks/FormFieldSetup"; import { DynamicHeight } from "@/components/ui/DynamicHeight"; import { DecimalInput } from "@/components/ui/decimal-input"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Spinner } from "@/components/ui/Spinner/Spinner"; import { Switch } from "@/components/ui/switch"; import { useAllChainsData } from "@/hooks/chains/allChains"; import type { TokenDistributionForm } from "../_common/form"; @@ -22,27 +22,48 @@ export function TokenSaleSection(props: { const saleMode = props.form.watch("saleMode"); const { idToChain } = useAllChainsData(); const chainMeta = idToChain.get(Number(props.chainId)); + const [hasUserUpdatedSaleMode, setHasUserUpdatedSaleMode] = useState(false); const isRouterEnabledQuery = useQuery({ - queryFn: () => - isRouterEnabled({ - // eslint-disable-next-line no-restricted-syntax - chain: defineChain(Number(props.chainId)), - client: props.client, - }), + queryFn: async () => { + try { + return await isRouterEnabled({ + // eslint-disable-next-line no-restricted-syntax + chain: defineChain(Number(props.chainId)), + client: props.client, + }); + } catch { + return false; + } + }, queryKey: ["isRouterEnabled", props.chainId], }); + const isRouterEnabledValue = isRouterEnabledQuery.data === true; + const isSaleEnabled = saleMode !== "disabled"; // eslint-disable-next-line no-restricted-syntax useEffect(() => { - if (isRouterEnabledQuery.data === false && isSaleEnabled) { + if (isRouterEnabledValue === false && isSaleEnabled) { props.form.setValue("saleMode", "disabled", { shouldValidate: true, }); } - }, [isRouterEnabledQuery.data, isSaleEnabled, props.form]); + }, [isRouterEnabledValue, isSaleEnabled, props.form]); + + // eslint-disable-next-line no-restricted-syntax + useEffect(() => { + if ( + isRouterEnabledValue === true && + !hasUserUpdatedSaleMode && + !isSaleEnabled + ) { + props.form.setValue("saleMode", "pool", { + shouldValidate: true, + }); + } + }, [isRouterEnabledValue, props.form, hasUserUpdatedSaleMode, isSaleEnabled]); return ( @@ -52,23 +73,25 @@ export function TokenSaleSection(props: {

Sale

- List and add liquidity for your coin on a decentralized exchange - for purchase at fluctuating market price + List your coin on a decentralized exchange and earn rewards on + every trade

{isRouterEnabledQuery.isPending ? ( - + ) : ( { - if (isRouterEnabledQuery.data !== true) { + if (!isRouterEnabledValue) { return; } + setHasUserUpdatedSaleMode(true); + props.form.setValue( "saleMode", checked ? "pool" : "disabled", From 3117a3bf7cf041ea9712f846e633a30e002594ca Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Sat, 19 Jul 2025 03:57:35 +0530 Subject: [PATCH 16/19] updates --- .../components/blocks/distribution-chart.tsx | 43 +++++++++++------ .../create/token/create-token-page-impl.tsx | 2 +- .../token/distribution/token-airdrop.tsx | 2 +- .../token/distribution/token-distribution.tsx | 3 ++ .../create/token/distribution/token-sale.tsx | 48 ++++++++++++++++++- .../rewards/components/claim-rewards-page.tsx | 22 +++++---- 6 files changed, 94 insertions(+), 26 deletions(-) diff --git a/apps/dashboard/src/@/components/blocks/distribution-chart.tsx b/apps/dashboard/src/@/components/blocks/distribution-chart.tsx index 8abb8373679..b34094aadda 100644 --- a/apps/dashboard/src/@/components/blocks/distribution-chart.tsx +++ b/apps/dashboard/src/@/components/blocks/distribution-chart.tsx @@ -3,12 +3,15 @@ import { cn } from "@/lib/utils"; export type Segment = { label: string; percent: number; + value: string; color: string; }; type DistributionBarChartProps = { segments: Segment[]; - title: string; + title?: string; + titleClassName?: string; + barClassName?: string; }; export function DistributionBarChart(props: DistributionBarChartProps) { @@ -21,24 +24,36 @@ export function DistributionBarChart(props: DistributionBarChartProps) { return (
-
-

{props.title}

-
- Total: {totalPercentage}% + {props.title && ( +
+

+ {props.title} +

+
+ Total: {totalPercentage}% +
-
+ )} {/* Bar */} -
+
{props.segments.map((segment) => { return (
0 && "border-r-2 border-background", + )} key={segment.label} style={{ backgroundColor: segment.color, @@ -67,7 +82,7 @@ export function DistributionBarChart(props: DistributionBarChartProps) { "text-destructive-text", )} > - {segment.label}: {segment.percent}% + {segment.label}: {segment.value}

); diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx index c291f038bb8..8230c955cb0 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx @@ -113,7 +113,7 @@ export function CreateTokenAssetPage(props: { params.values.pool.startingPricePerToken, ), }), - referrerRewardBps: 5000, // 50% + referrerRewardBps: 1250, // 12.5% }, } : undefined, diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-airdrop.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-airdrop.tsx index 133e8bd0295..99631b957d7 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-airdrop.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-airdrop.tsx @@ -67,7 +67,7 @@ export function TokenAirdropSection(props: { return (
-
+

Airdrop

diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-distribution.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-distribution.tsx index 0627a5bc5d5..075eacd6e79 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-distribution.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-distribution.tsx @@ -144,16 +144,19 @@ export function TokenDistributionBarChart(props: { color: "hsl(var(--chart-1))", label: "Owner", percent: ownerPercentage, + value: `${ownerPercentage}%`, }, { color: "hsl(var(--chart-3))", label: "Airdrop", percent: airdropPercentage, + value: `${airdropPercentage}%`, }, { color: "hsl(var(--chart-4))", label: "Sale", percent: salePercentage, + value: `${salePercentage}%`, }, ]; diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx index f72476d643e..22b0c3eb10d 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx @@ -1,11 +1,12 @@ "use client"; import { useQuery } from "@tanstack/react-query"; -import { XIcon } from "lucide-react"; +import { DollarSignIcon, XIcon } from "lucide-react"; import { useEffect, useState } from "react"; import type { ThirdwebClient } from "thirdweb"; import { defineChain } from "thirdweb"; import { isRouterEnabled } from "thirdweb/assets"; +import { DistributionBarChart } from "@/components/blocks/distribution-chart"; import { FormFieldSetup } from "@/components/blocks/FormFieldSetup"; import { DynamicHeight } from "@/components/ui/DynamicHeight"; import { DecimalInput } from "@/components/ui/decimal-input"; @@ -65,6 +66,11 @@ export function TokenSaleSection(props: { } }, [isRouterEnabledValue, props.form, hasUserUpdatedSaleMode, isSaleEnabled]); + const protocolFee = 20; + const leftOverFee = 100 - protocolFee; + const convenienceFee = (12.5 * leftOverFee) / 100; + const deployerFee = leftOverFee - convenienceFee; + return (

@@ -131,6 +137,46 @@ export function TokenSaleSection(props: { client={props.client} form={props.form} /> + +
+
+
+ +
+
+

Sale Rewards

+

+ All trades on the market are subjected to{" "} + 1% {" "} + fee distributed as: +

+ +
+
Total: 1%
+ +
+
)}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx index 708e1638cb3..51da24045f5 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx @@ -128,8 +128,8 @@ export function ClaimRewardsPageUI(props: {
-

- Uniswap LP Rewards +

+ Rewards

Earnings received by Liquidity Providers (LPs) in exchange for @@ -140,7 +140,7 @@ export function ClaimRewardsPageUI(props: {

-

Unclaimed Rewards

+

Unclaimed Rewards

@@ -289,7 +293,7 @@ function TokenReward(props: { From 23a9a62a6a2af9741e8a80b914ee6d1b4bb06ca2 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Sat, 19 Jul 2025 04:30:08 +0530 Subject: [PATCH 17/19] add pricing strategy selector --- .../create/token/distribution/token-sale.tsx | 126 ++++++++++++------ .../rewards/utils/unclaimed-fees.ts | 2 +- 2 files changed, 83 insertions(+), 45 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx index 22b0c3eb10d..61cb85ed3fa 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx @@ -8,9 +8,17 @@ import { defineChain } from "thirdweb"; import { isRouterEnabled } from "thirdweb/assets"; import { DistributionBarChart } from "@/components/blocks/distribution-chart"; import { FormFieldSetup } from "@/components/blocks/FormFieldSetup"; +import { Badge } from "@/components/ui/badge"; import { DynamicHeight } from "@/components/ui/DynamicHeight"; import { DecimalInput } from "@/components/ui/decimal-input"; import { Spinner } from "@/components/ui/Spinner/Spinner"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; import { useAllChainsData } from "@/hooks/chains/allChains"; import type { TokenDistributionForm } from "../_common/form"; @@ -198,55 +206,85 @@ function PoolConfig(props: { ); return ( -
- {/* supply % */} +
+ {/* Pricing Strategy */} -
- { - props.form.setValue("saleAllocationPercentage", value, { - shouldValidate: true, - }); - }} - value={props.form.watch("saleAllocationPercentage")} - /> - - % - -
+
- {/* starting price */} - -
- { - props.form.setValue("pool.startingPricePerToken", value, { - shouldValidate: true, - }); - }} - value={props.form.watch("pool.startingPricePerToken")} - /> - - {chainMeta?.nativeCurrency.symbol || "ETH"} - -
-
+
+ {/* supply % */} + +
+ { + props.form.setValue("saleAllocationPercentage", value, { + shouldValidate: true, + }); + }} + value={props.form.watch("saleAllocationPercentage")} + /> + + % + +
+
+ + {/* starting price */} + +
+ { + props.form.setValue("pool.startingPricePerToken", value, { + shouldValidate: true, + }); + }} + value={props.form.watch("pool.startingPricePerToken")} + /> + + {chainMeta?.nativeCurrency.symbol || "ETH"} + +
+
+
); } diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/utils/unclaimed-fees.ts b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/utils/unclaimed-fees.ts index 16c1284602e..3e0adcb6e9e 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/utils/unclaimed-fees.ts +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/utils/unclaimed-fees.ts @@ -2,7 +2,7 @@ import type { ThirdwebContract } from "thirdweb"; import { getContract, readContract } from "thirdweb"; import { symbol } from "thirdweb/extensions/common"; -export const maxUint128 = 2n ** 128n - 1n; +const maxUint128 = 2n ** 128n - 1n; export async function getUnclaimedFees(params: { positionManager: ThirdwebContract; From f07f9b44a9cec16727c224244d038539d8788b44 Mon Sep 17 00:00:00 2001 From: Manan Tank Date: Sat, 19 Jul 2025 04:59:49 +0530 Subject: [PATCH 18/19] distribute page ui updates --- .../rewards/components/claim-rewards-page.tsx | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx index 51da24045f5..e8856bbe586 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx @@ -1,6 +1,6 @@ "use client"; -import { ArrowRightIcon, ExternalLinkIcon } from "lucide-react"; +import { DollarSignIcon, ExternalLinkIcon, SplitIcon } from "lucide-react"; import Link from "next/link"; import { toast } from "sonner"; import { @@ -118,7 +118,7 @@ export function ClaimRewardsPageUI(props: { const recipientColor = `hsl(var(--chart-1))`; const referrerColor = `hsl(var(--chart-2))`; - const protocolFeesColor = `hsl(var(--chart-10))`; + const protocolFeesColor = `hsl(var(--chart-3))`; const hasUnclaimedRewards = props.unclaimedFees.token0.amount > 0 || @@ -127,8 +127,8 @@ export function ClaimRewardsPageUI(props: { return (
-
-

+
+

Rewards

@@ -138,9 +138,17 @@ export function ClaimRewardsPageUI(props: {

-
-
-

Unclaimed Rewards

+
+
+
+
+ +
+
+

Unclaimed Rewards

+

+ The rewards that are earned but haven't been distributed yet +

-
+
+
+
+ +
+
+ +

Reward Distribution

+

+ The unclaimed rewards will be distributed as: +

+
-
+
{hasUnclaimedRewards && (

Click on "Distribute Rewards" to distribute unclaimed rewards @@ -239,14 +256,14 @@ export function ClaimRewardsPageUI(props: { )}

@@ -272,7 +289,7 @@ function TokenReward(props: { ); return ( -
+
Date: Sat, 19 Jul 2025 05:16:34 +0530 Subject: [PATCH 19/19] ui tweaks --- .../rewards/components/claim-rewards-page.tsx | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx index e8856bbe586..9e476bf9713 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/contract/[chainIdOrSlug]/[contractAddress]/rewards/components/claim-rewards-page.tsx @@ -127,8 +127,14 @@ export function ClaimRewardsPageUI(props: { return (
-
-

+
+
+
+ +
+
+ +

Rewards

@@ -140,11 +146,6 @@ export function ClaimRewardsPageUI(props: {

-
-
- -
-

Unclaimed Rewards

The rewards that are earned but haven't been distributed yet @@ -167,12 +168,6 @@ export function ClaimRewardsPageUI(props: {

-
-
- -
-
-

Reward Distribution

The unclaimed rewards will be distributed as: