Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
8702a49
[TOOL-4689] Dashboard: Integrate ERC20Asset contract in token creatio…
MananTank Jun 16, 2025
991051d
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 1, 2025
2702e39
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 1, 2025
4f457e9
add POST v1/tokens after coin creation
MananTank Jul 3, 2025
b6563b8
Fix createTokenOnUniversalBridge
MananTank Jul 3, 2025
5277e18
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 7, 2025
7f7d97a
Fix lint
MananTank Jul 7, 2025
1aebfc8
set initialTick
MananTank Jul 9, 2025
1e8ca5a
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 10, 2025
1d31fd0
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 10, 2025
8a2e39c
update
MananTank Jul 10, 2025
f29a2c2
update tick calc
MananTank Jul 10, 2025
f61d0e0
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 10, 2025
3e45e9d
remove unused stuff
MananTank Jul 10, 2025
ee8e2be
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 15, 2025
3c745cc
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 15, 2025
df8e5a4
add claim rewards page
MananTank Jul 15, 2025
6bfce15
load amounts
MananTank Jul 16, 2025
db396a7
update
MananTank Jul 16, 2025
e8e69ae
update UI
MananTank Jul 16, 2025
e946458
copy changes
MananTank Jul 16, 2025
e222e3d
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 16, 2025
aabe00e
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 17, 2025
2951738
update recent transfers table
MananTank Jul 17, 2025
1366058
update creation UI
MananTank Jul 17, 2025
9170c8f
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
jakeloo Jul 18, 2025
3117a3b
updates
MananTank Jul 18, 2025
23a9a62
add pricing strategy selector
MananTank Jul 18, 2025
f07f9b4
distribute page ui updates
MananTank Jul 18, 2025
bc6691c
ui tweaks
MananTank Jul 18, 2025
6f59b86
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 22, 2025
9842f23
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 23, 2025
67bc000
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 23, 2025
db4a397
update imports
MananTank Jul 23, 2025
500a68c
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 23, 2025
893e05d
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 23, 2025
7a1767e
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Jul 23, 2025
0d7728e
show 2 steps for airdrop
MananTank Jul 23, 2025
07a879d
update chain selectors
MananTank Jul 24, 2025
3245a3e
padding fix
MananTank Jul 24, 2025
54d4b45
UI tweaks
MananTank Jul 24, 2025
178f72d
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
jakeloo Jul 26, 2025
0ebf6cb
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
jakeloo Jul 26, 2025
b99542b
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
jakeloo Jul 26, 2025
e09257e
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
jakeloo Jul 26, 2025
5b7a730
Update tokens SDK
jakeloo Jul 26, 2025
5f8c503
Update referrer -> developer
jakeloo Aug 12, 2025
3ab336a
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Aug 12, 2025
a37c296
fix import
MananTank Aug 12, 2025
bf70bb7
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Aug 13, 2025
3048bd4
fix lint warning
MananTank Aug 13, 2025
0d961d9
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Aug 13, 2025
cad1074
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Aug 13, 2025
e93b4e9
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Aug 13, 2025
87a89ec
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Aug 14, 2025
a07fada
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Aug 14, 2025
484113b
update
MananTank Aug 14, 2025
49103bf
debug crash
MananTank Aug 14, 2025
f6ab2fd
test
MananTank Aug 14, 2025
61edd0e
fix
MananTank Aug 14, 2025
ee0dee1
Merge branch 'yash/ocr-contracts-integration' into 06-16-_tool-4689_d…
MananTank Aug 15, 2025
63940eb
Add tokendrop as fallback
MananTank Aug 15, 2025
f5c875a
reset token on chain change
MananTank Aug 15, 2025
2247a73
changes
MananTank Aug 15, 2025
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
21 changes: 15 additions & 6 deletions apps/dashboard/src/@/analytics/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,11 @@ export function reportChainConfigurationAdded(properties: {
// ASSETS
// ----------------------------

type AssetContractType = "DropERC20" | "DropERC1155" | "DropERC721";
type AssetContractType =
| "DropERC20"
| "DropERC1155"
| "DropERC721"
| "ERC20Asset";

/**
* ### Why do we need to report this event?
Expand Down Expand Up @@ -334,6 +338,15 @@ export function reportAssetCreationSuccessful(properties: {
});
}

type CoinCreationStep =
| "erc20-asset:deploy-contract"
| "erc20-asset:airdrop-tokens"
| "erc20-asset:approve-airdrop-tokens"
| "drop-erc20:deploy-contract"
| "drop-erc20:set-claim-conditions"
| "drop-erc20:mint-tokens"
| "drop-erc20:airdrop-tokens";

/**
* ### Why do we need to report this event?
* - To track number of failed asset creations
Expand All @@ -355,11 +368,7 @@ export function reportAssetCreationFailed(
}
| {
assetType: "coin";
step:
| "deploy-contract"
| "set-claim-conditions"
| "mint-tokens"
| "airdrop-tokens";
step: CoinCreationStep;
}
),
) {
Expand Down
50 changes: 41 additions & 9 deletions apps/dashboard/src/@/components/blocks/NetworkSelectors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,18 @@ export function MultiNetworkSelector(props: {
client: ThirdwebClient;
chainIds?: number[];
}) {
let { allChains, idToChain } = useAllChainsData();

if (props.chainIds && props.chainIds.length > 0) {
allChains = allChains.filter((chain) =>
props.chainIds?.includes(chain.chainId),
);
}
const { allChains, idToChain } = useAllChainsData();

const options = useMemo(() => {
let sortedChains = allChains;
let chains = allChains.filter((chain) => chain.status !== "deprecated");

if (props.chainIds && props.chainIds.length > 0) {
chains = allChains.filter((chain) =>
props.chainIds?.includes(chain.chainId),
);
}

let sortedChains = chains;

if (props.priorityChains) {
const priorityChainsSet = new Set();
Expand Down Expand Up @@ -69,7 +71,13 @@ export function MultiNetworkSelector(props: {
value: String(chain.chainId),
};
});
}, [allChains, props.priorityChains, idToChain, props.hideTestnets]);
}, [
allChains,
props.priorityChains,
idToChain,
props.hideTestnets,
props.chainIds,
]);

const searchFn = useCallback(
(option: Option, searchValue: string) => {
Expand Down Expand Up @@ -155,16 +163,38 @@ export function SingleNetworkSelector(props: {
disableDeprecated?: boolean;
placeholder?: string;
client: ThirdwebClient;
priorityChains?: number[];
}) {
const { allChains, idToChain } = useAllChainsData();

const chainsToShow = useMemo(() => {
let chains = allChains;

chains = chains.filter((chain) => chain.status !== "deprecated");

if (props.disableTestnets) {
chains = chains.filter((chain) => !chain.testnet);
}

if (props.priorityChains) {
const priorityChainsSet = new Set();
for (const chainId of props.priorityChains || []) {
priorityChainsSet.add(chainId);
}

const priorityChains = (props.priorityChains || [])
.map((chainId) => {
return idToChain.get(chainId);
})
.filter((v) => !!v);

const otherChains = allChains.filter(
(chain) => !priorityChainsSet.has(chain.chainId),
);

chains = [...priorityChains, ...otherChains];
}

if (props.chainIds) {
const chainIdSet = new Set(props.chainIds);
chains = chains.filter((chain) => chainIdSet.has(chain.chainId));
Expand All @@ -180,6 +210,8 @@ export function SingleNetworkSelector(props: {
props.chainIds,
props.disableTestnets,
props.disableDeprecated,
props.priorityChains,
idToChain,
]);

const options = useMemo(() => {
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/src/@/components/blocks/TokenSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ export function TokenSelector(props: {
searchPlaceholder="Search by name or symbol"
showCheck={props.showCheck}
side={props.side}
value={selectedValue}
value={tokensQuery.isPending ? undefined : selectedValue}
/>
);
}
43 changes: 29 additions & 14 deletions apps/dashboard/src/@/components/blocks/distribution-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -21,24 +24,36 @@ export function DistributionBarChart(props: DistributionBarChartProps) {

return (
<div>
<div className="mb-2 flex items-center justify-between">
<h3 className="font-medium text-sm">{props.title}</h3>
<div
className={cn(
"font-medium text-muted-foreground text-sm",
invalidTotalPercentage && "text-red-500",
)}
>
Total: {totalPercentage}%
{props.title && (
<div className="mb-2 flex items-center justify-between">
<h3 className={cn("font-medium text-sm", props.titleClassName)}>
{props.title}
</h3>
<div
className={cn(
"font-medium text-muted-foreground text-sm",
invalidTotalPercentage && "text-red-500",
)}
>
Total: {totalPercentage}%
</div>
</div>
</div>
)}

{/* Bar */}
<div className="flex h-3 overflow-hidden rounded-lg">
<div
className={cn(
"flex h-3 overflow-hidden rounded-lg",
props.barClassName,
)}
>
{props.segments.map((segment) => {
return (
<div
className="flex h-full items-center justify-center transition-all duration-200"
className={cn(
"flex h-full items-center justify-center transition-all duration-200",
segment.percent > 0 && "border-r-2 border-background",
)}
key={segment.label}
style={{
backgroundColor: segment.color,
Expand Down Expand Up @@ -67,7 +82,7 @@ export function DistributionBarChart(props: DistributionBarChartProps) {
"text-destructive-text",
)}
>
{segment.label}: {segment.percent}%
{segment.label}: {segment.value}
</p>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function MultiStepStatus<T extends string>(props: {
}) {
return (
<DynamicHeight>
<div className="space-y-4">
<div className="space-y-4 overflow-hidden">
{props.steps.map((step) => (
<div className="flex items-start space-x-3 " key={step.label}>
{step.status.type === "completed" ? (
Expand All @@ -46,7 +46,7 @@ export function MultiStepStatus<T extends string>(props: {
) : (
<CircleIcon className="mt-0.5 size-5 flex-shrink-0 text-muted-foreground/70" />
)}
<div className="flex-1">
<div className="grow">
<p
className={`font-medium ${
step.status.type === "pending"
Expand All @@ -73,7 +73,7 @@ export function MultiStepStatus<T extends string>(props: {
{step.status.type === "error"
? props.renderError?.(step, step.status.message) || (
<div className="mt-1 space-y-2">
<p className="mb-1 text-red-500 text-sm">
<p className="mb-1 text-red-500 text-sm whitespace-pre-wrap break-all">
{step.status.message}
</p>
<Button
Expand Down
20 changes: 16 additions & 4 deletions apps/dashboard/src/@/components/blocks/wallet-address.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";
import { CheckIcon, CopyIcon, XIcon } from "lucide-react";
import { CheckIcon, CircleSlashIcon, CopyIcon, XIcon } from "lucide-react";
import { useMemo } from "react";
import { isAddress, type ThirdwebClient, ZERO_ADDRESS } from "thirdweb";
import { Blobbie, type SocialProfile, useSocialProfiles } from "thirdweb/react";
Expand All @@ -23,6 +23,7 @@ export function WalletAddress(props: {
className?: string;
iconClassName?: string;
client: ThirdwebClient;
fallbackIcon?: React.ReactNode;
}) {
// default back to zero address if no address provided
const address = useMemo(() => props.address || ZERO_ADDRESS, [props.address]);
Expand Down Expand Up @@ -59,9 +60,16 @@ export function WalletAddress(props: {
// special case for zero address
if (address === ZERO_ADDRESS) {
return (
<span className={cn("cursor-pointer font-mono", props.className)}>
{shortenedAddress}
</span>
<div className="flex items-center gap-2 py-2">
<CircleSlashIcon
className={cn("size-6 text-muted-foreground/70", props.iconClassName)}
/>
<span
className={cn("cursor-pointer font-mono text-sm", props.className)}
>
{shortenedAddress}
</span>
</div>
);
}

Expand All @@ -82,6 +90,7 @@ export function WalletAddress(props: {
iconClassName={props.iconClassName}
profiles={profiles.data || []}
thirdwebClient={props.client}
fallbackIcon={props.fallbackIcon}
/>
)}
<span className="cursor-pointer font-mono">
Expand Down Expand Up @@ -173,6 +182,7 @@ function WalletAvatar(props: {
profiles: SocialProfile[];
thirdwebClient: ThirdwebClient;
iconClassName?: string;
fallbackIcon?: React.ReactNode;
}) {
const avatar = useMemo(() => {
return props.profiles.find(
Expand All @@ -199,6 +209,8 @@ function WalletAvatar(props: {
className={cn("size-5 object-cover", props.iconClassName)}
src={resolvedAvatarSrc}
/>
) : props.fallbackIcon ? (
props.fallbackIcon
) : (
<Blobbie
address={props.address}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ const contractTypeToAssetTypeRecord: Record<string, string | undefined> = {
DropERC20: "Coin",
DropERC721: "NFT Collection",
DropERC1155: "NFT Collection",
ERC20Asset: "Coin",
};

const NetworkFilterCell = React.memo(function NetworkFilterCell({
Expand Down
1 change: 1 addition & 0 deletions apps/dashboard/src/@/components/ui/CopyAddressButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export function CopyAddressButton(props: {
copyIconPosition={props.copyIconPosition}
textToCopy={props.address}
textToShow={shortenedAddress}
iconClassName={props.iconClassName}
tooltip={props.tooltip || "Copy Address"}
variant={props.variant}
/>
Expand Down
8 changes: 7 additions & 1 deletion apps/dashboard/src/@/components/ui/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export function TabButtons(props: {
shadowColor?: string;
tabIconClassName?: string;
hideBottomLine?: boolean;
bottomLineClassName?: string;
}) {
const { containerRef, lineRef, activeTabRef } =
useUnderline<HTMLButtonElement>();
Expand All @@ -106,7 +107,12 @@ export function TabButtons(props: {
<div className={cn("relative", props.containerClassName)}>
{/* Bottom line */}
{!props.hideBottomLine && (
<div className="absolute right-0 bottom-0 left-0 h-[1px] bg-border" />
<div
className={cn(
"absolute right-0 bottom-0 left-0 h-[1px] bg-border",
props.bottomLineClassName,
)}
/>
)}

<ScrollShadow
Expand Down
1 change: 0 additions & 1 deletion apps/dashboard/src/@/contexts/error-handler.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"use client";

import { CircleAlertIcon, InfoIcon } from "lucide-react";
import Link from "next/link";
import { createContext, useCallback, useContext, useState } from "react";
Expand Down
7 changes: 6 additions & 1 deletion apps/dashboard/src/@/hooks/project-contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ export function useAddContractToProject() {
contractAddress: string;
chainId: string;
deploymentType: "asset" | undefined;
contractType: "DropERC20" | "DropERC721" | "DropERC1155" | undefined;
contractType:
| "ERC20Asset"
| "DropERC721"
| "DropERC1155"
| "DropERC20"
| undefined;
}) => {
const res = await apiServerProxy({
body: JSON.stringify({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type ContractPageMetadata = {
isAccount: boolean;
isAccountPermissionsSupported: boolean;
functionSelectors: string[];
showClaimRewards: boolean;
};

export async function getContractPageMetadata(contract: ThirdwebContract) {
Expand Down
Loading
Loading