Skip to content

Commit 31fbde3

Browse files
committed
[TOOL-4651] Dashboard: Show error on invalid token distribution in ERC20 asset creation form
1 parent 6cce31d commit 31fbde3

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

apps/dashboard/src/@/components/blocks/distribution-chart.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type DistributionBarChartProps = {
1010
segments: Segment[];
1111
title: string;
1212
};
13+
1314
export function DistributionBarChart(props: DistributionBarChartProps) {
1415
const totalPercentage = props.segments.reduce(
1516
(sum, segment) => sum + segment.percent,
@@ -59,7 +60,13 @@ export function DistributionBarChart(props: DistributionBarChartProps) {
5960
backgroundColor: segment.color,
6061
}}
6162
/>
62-
<p className="text-sm">
63+
<p
64+
className={cn(
65+
"text-sm",
66+
(segment.percent > 100 || segment.percent < 0) &&
67+
"text-destructive-text",
68+
)}
69+
>
6370
{segment.label}: {segment.percent}%
6471
</p>
6572
</div>

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/create-token-card.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export function StepCard(props: {
1515
| undefined
1616
| {
1717
type: "submit";
18+
disabled?: boolean;
1819
}
1920
| {
2021
type: "custom";
@@ -56,6 +57,7 @@ export function StepCard(props: {
5657
variant="default"
5758
className="gap-2"
5859
type="submit"
60+
disabled={props.nextButton.disabled}
5961
onClick={() => {
6062
trackEvent(
6163
getStepCardTrackingData({

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/distribution/token-distribution.tsx

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export function TokenDistributionFieldset(props: {
2525
client: ThirdwebClient;
2626
}) {
2727
const { form } = props;
28+
const distributionError = getDistributionError(form);
2829

2930
return (
3031
<Form {...form}>
@@ -37,6 +38,7 @@ export function TokenDistributionFieldset(props: {
3738
}}
3839
nextButton={{
3940
type: "submit",
41+
disabled: !!distributionError,
4042
}}
4143
>
4244
<div>
@@ -55,9 +57,17 @@ export function TokenDistributionFieldset(props: {
5557
</div>
5658
</FormFieldSetup>
5759

58-
<TokenDistributionBarChart
59-
distributionFormValues={form.watch()}
60-
/>
60+
<div className="flex flex-col gap-3">
61+
<TokenDistributionBarChart
62+
distributionFormValues={form.watch()}
63+
/>
64+
65+
{distributionError && (
66+
<div className="text-destructive-text text-sm">
67+
{distributionError}
68+
</div>
69+
)}
70+
</div>
6171
</div>
6272

6373
<TokenAirdropSection form={form} client={props.client} />
@@ -73,6 +83,36 @@ export function TokenDistributionFieldset(props: {
7383
);
7484
}
7585

86+
function getDistributionError(form: TokenDistributionForm) {
87+
const supply = Number(form.watch("supply"));
88+
const totalAirdrop = form.watch("airdropAddresses").reduce((sum, addr) => {
89+
return sum + SafeNumber(addr.quantity);
90+
}, 0);
91+
92+
if (totalAirdrop > supply) {
93+
return "Total airdrop quantity exceeds total supply";
94+
}
95+
96+
const saleSupplyPercentage = SafeNumber(
97+
form.watch("saleAllocationPercentage"),
98+
);
99+
100+
const saleSupply = (saleSupplyPercentage / 100) * supply;
101+
const ownerSupply = Math.max(supply - totalAirdrop - saleSupply, 0);
102+
const totalSumOfSupply = totalAirdrop + saleSupply + ownerSupply;
103+
104+
if (totalSumOfSupply > supply) {
105+
return "Token distribution exceeds total supply";
106+
}
107+
108+
return undefined;
109+
}
110+
111+
function SafeNumber(value: string) {
112+
const num = Number(value);
113+
return Number.isNaN(num) ? 0 : num;
114+
}
115+
76116
export function TokenDistributionBarChart(props: {
77117
distributionFormValues: TokenDistributionFormValues;
78118
}) {
@@ -86,7 +126,8 @@ export function TokenDistributionBarChart(props: {
86126
const salePercentage = Number(
87127
props.distributionFormValues.saleAllocationPercentage,
88128
);
89-
const ownerPercentage = 100 - airdropPercentage - salePercentage;
129+
130+
const ownerPercentage = Math.max(100 - airdropPercentage - salePercentage, 0);
90131

91132
const tokenAllocations: Segment[] = [
92133
{

0 commit comments

Comments
 (0)