Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
29 changes: 15 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@
},
"dependencies": {
"@coral-xyz/anchor": "^0.31.0",
"@helium/account-fetch-cache": "^0.10.11",
"@helium/account-fetch-cache-hooks": "^0.10.11",
"@helium/helium-react-hooks": "^0.10.11",
"@helium/hpl-crons-sdk": "^0.10.11",
"@helium/account-fetch-cache": "^0.10.13",
"@helium/account-fetch-cache-hooks": "^0.10.13",
"@helium/helium-react-hooks": "^0.10.13",
"@helium/hpl-crons-sdk": "^0.10.13",
"@helium/modular-governance-hooks": "^0.1.5",
"@helium/modular-governance-idls": "^0.1.5",
"@helium/no-emit-sdk": "^0.10.11",
"@helium/no-emit-sdk": "^0.10.13",
"@helium/organization-sdk": "^0.1.5",
"@helium/spl-utils": "^0.10.11",
"@helium/spl-utils": "^0.10.13",
"@helium/state-controller-sdk": "^0.1.5",
"@helium/tuktuk-sdk": "^0.0.8",
"@helium/voter-stake-registry-hooks": "^0.10.11",
"@helium/voter-stake-registry-sdk": "^0.10.11",
"@helium/voter-stake-registry-hooks": "^0.10.13",
"@helium/voter-stake-registry-sdk": "^0.10.13",
"@hookform/resolvers": "^3.3.4",
"@metaplex-foundation/mpl-token-metadata": "2.10.0",
"@project-serum/anchor": "^0.26.0",
Expand All @@ -37,6 +37,7 @@
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.2.4",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-toggle-group": "^1.0.4",
"@solana/spl-token": "^0.4.0",
Expand Down Expand Up @@ -77,15 +78,15 @@
"resolutions": {
"@tanstack/react-query": "5.45.1",
"@solana/web3.js": "^1.90.0",
"@helium/account-fetch-cache": "^0.10.11",
"@helium/account-fetch-cache-hooks": "^0.10.11",
"@helium/helium-react-hooks": "^0.10.11",
"@helium/voter-stake-registry-hooks": "^0.10.11",
"@helium/account-fetch-cache": "^0.10.13",
"@helium/account-fetch-cache-hooks": "^0.10.13",
"@helium/helium-react-hooks": "^0.10.13",
"@helium/voter-stake-registry-hooks": "^0.10.13",
"@helium/modular-governance-idls": "^0.1.5",
"@helium/spl-utils": "^0.10.11",
"@helium/spl-utils": "^0.10.13",
"@helium/modular-governance-hooks": "^0.1.5",
"@solana/wallet-adapter-react": "^0.15.35",
"@helium/voter-stake-registry-sdk": "^0.10.11"
"@helium/voter-stake-registry-sdk": "^0.10.13"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.10",
Expand Down
42 changes: 42 additions & 0 deletions src/components/AutomationSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Switch } from "./ui/switch";

export interface AutomationSettingsProps {
automationEnabled: boolean;
setAutomationEnabled: (enabled: boolean) => void;
solFees?: number;
prepaidTxFees?: number;
}

export const AutomationSettings = ({
automationEnabled,
setAutomationEnabled,
solFees = 0,
prepaidTxFees = 0,
}: AutomationSettingsProps) => {
return (
<div className="bg-slate-850 rounded-lg p-4">
<div className="flex flex-row justify-between items-center">
<div className="flex flex-col">
<span className="text-sm">Enable Automation</span>
<span className="text-xs text-muted-foreground">
Enable automatic claiming of rewards
</span>
</div>
<Switch
checked={automationEnabled}
onCheckedChange={setAutomationEnabled}
/>
</div>
<div className="flex flex-row justify-between items-center mt-4 mb-2">
<span className="text-sm text-muted-foreground">Rent Fees</span>
<span className="text-sm">{solFees.toFixed(6)} SOL</span>
</div>
<div className="flex flex-row justify-between items-center">
<span className="text-sm text-muted-foreground">
Prepaid Transaction Fees
</span>
<span className="text-sm">{prepaidTxFees.toFixed(6)} SOL</span>
</div>
</div>
);
};
27 changes: 23 additions & 4 deletions src/components/CreatePositionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import { Button } from "./ui/button";
import { Dialog, DialogContent, DialogTrigger } from "./ui/dialog";
import { PositionPreview } from "./PositionPreview";
import { MOBILE_SUB_DAO_KEY } from "@/lib/constants";
import { DataSplitBars } from "./DataSplitBars";
import { AutomationSettings } from "./AutomationSettings";

export const CreatePositionModal: FC<React.PropsWithChildren<{}>> = ({
children,
Expand All @@ -41,10 +43,13 @@ export const CreatePositionModal: FC<React.PropsWithChildren<{}>> = ({
const [isSubmitting, setIsSubmitting] = useState(false);
const [formValues, setFormValues] = useState<LockTokensFormValues>();
const [selectedSubDaoPk, setSelectedSubDaoPk] = useState<PublicKey>();
const [automationEnabled, setAutomationEnabled] = useState(true);
const { publicKey: wallet } = useWallet();
const { mint, subDaos, registrar, refetch: refetchState } = useGovernance();
const { amount: ownedAmount, decimals } = useOwnedAmount(wallet, mint);
const { error: createPositionError, createPosition } = useCreatePosition();
const { error: createPositionError, createPosition, rentFee, prepaidTxFees, insufficientBalance } = useCreatePosition({
automationEnabled,
});
const steps = useMemo(() => (mint.equals(HNT_MINT) ? 3 : 2), [mint]);

useEffect(() => {
Expand Down Expand Up @@ -193,14 +198,27 @@ export const CreatePositionModal: FC<React.PropsWithChildren<{}>> = ({
<div className="flex flex-col gap-4 p-4 text-sm bg-slate-600 rounded">
Delegating your position to a subnetwork and voting regularly
earns you HNT rewards. Select the subnetwork you believe offers
the greatest potential for growth and impact. This choice does
not affect the rewarded amount.
the greatest potential for future revenue. This choice does not
affect your HNT rewards for this delegation. Delegation
percentages drive the amount of HNT emissions that go towards
each subnetwork&apos;s growth.
</div>

<DataSplitBars />

<SubDaoSelection
hideNoneOption
selectedSubDaoPk={selectedSubDaoPk}
onSelect={setSelectedSubDaoPk}
/>

<AutomationSettings
automationEnabled={automationEnabled}
setAutomationEnabled={setAutomationEnabled}
solFees={rentFee}
prepaidTxFees={prepaidTxFees}
/>

<div className="flex flex-col gap-4 p-4 text-sm bg-slate-600 rounded">
<div>
<span className="font-medium">
Expand Down Expand Up @@ -232,8 +250,9 @@ export const CreatePositionModal: FC<React.PropsWithChildren<{}>> = ({
<Button
className="flex-grow text-foreground gap-2"
onClick={() => setStep(step + 1)}
disabled={!!insufficientBalance}
>
Review
{insufficientBalance ? "Insufficient SOL" : "Review"}
</Button>
</div>
</>
Expand Down
85 changes: 85 additions & 0 deletions src/components/DataSplitBars.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { humanReadable } from "@/lib/utils"
import { useDataBurnSplit, useSubDaoDelegationSplit } from "@helium/voter-stake-registry-hooks"
import { useGovernance } from "@/providers/GovernanceProvider"
import BN from "bn.js"
import { SplitBar } from "./SplitBar"

export const DataSplitBars = () => {
const { voteService } = useGovernance()
const { data: revData, isLoading: revLoading } = useDataBurnSplit({
voteService,
})
const { iot: iotDataUsageRev = 0, mobile: mobileDataUsageRev = 0 } =
(revData || {}) as { iot: number; mobile: number }
const { data: delegationData, isLoading: delegationLoading } =
useSubDaoDelegationSplit({
voteService,
})
const {
iot: iotDelegation = new BN(0),
mobile: mobileDelegation = new BN(0),
} = (delegationData || {}) as { iot: BN; mobile: BN }

const totalDataUsage = Number(mobileDataUsageRev) + Number(iotDataUsageRev)
const totalVetokens =
mobileDelegation && iotDelegation
? new BN(mobileDelegation).add(new BN(iotDelegation))
: new BN(0)

const mobileDelegationPercentage =
mobileDelegation && totalVetokens.gt(new BN(0))
? new BN(mobileDelegation)
.mul(new BN(10000))
.div(totalVetokens)
.toNumber() / 100
: 0

const iotDelegationPercentage =
iotDelegation && totalVetokens.gt(new BN(0))
? new BN(iotDelegation).mul(new BN(10000)).div(totalVetokens).toNumber() /
100
: 0

const mobileDataUsagePercentage =
totalDataUsage > 0
? (Number(mobileDataUsageRev) / totalDataUsage) * 100
: 0

const iotDataUsagePercentage =
totalDataUsage > 0 ? (Number(iotDataUsageRev) / totalDataUsage) * 100 : 0

if (revLoading || delegationLoading) return null

return (
<div className="flex flex-col gap-4 mb-4">
<SplitBar
title="Data Usage Revenue (30 days)"
leftValue={`$${humanReadable(
new BN(mobileDataUsageRev.toFixed(0)),
0
)?.replace(".00", "")}`}
rightValue={`$${humanReadable(
new BN(iotDataUsageRev.toFixed(0)),
0
)?.replace(".00", "")}`}
leftPercentage={mobileDataUsagePercentage}
rightPercentage={iotDataUsagePercentage}
leftColor="bg-blue-500"
rightColor="bg-green-500"
leftLabel="Mobile"
rightLabel="IoT"
/>
<SplitBar
title="HNT Emissions Split from Delegations"
leftValue={`${mobileDelegationPercentage.toFixed(1)}%`}
rightValue={`${iotDelegationPercentage.toFixed(1)}%`}
leftPercentage={mobileDelegationPercentage}
rightPercentage={iotDelegationPercentage}
leftColor="bg-blue-500"
rightColor="bg-green-500"
leftLabel="Mobile"
rightLabel="IoT"
/>
</div>
)
}
44 changes: 44 additions & 0 deletions src/components/DataSplitSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client";

import Link from "next/link";
import { DataSplitBars } from "./DataSplitBars";
import { Button } from "./ui/button";
import { usePathname } from "next/navigation";

export const DataSplitSection = () => {
const path = usePathname();
const basePath = path.split("/").slice(0, 2).join("/");

return (
<div className="flex flex-col py-12">
<h2 className="text-3xl md:text-4xl font-bold mb-10">
Network Delegation Split
</h2>
<div className="flex flex-col md:flex-row gap-12 items-start">
<div className="flex-1">
<div className="space-y-4 max-w-lg">
<p className="text-lg text-slate-400">
Delegating your staked HNT to a subnetwork and voting regularly earns you HNT rewards.
</p>
<p className="text-lg text-slate-400">
Delegation percentages drive the amount of HNT emissions that go towards each subnetwork&apos;s growth.
</p>
</div>
</div>
<div className="flex-1 w-full max-w-xl">
<DataSplitBars />
<div className="flex justify-end mt-6">
<Link href={`${basePath}/positions`}>
<Button
size="lg"
className="bg-[#4066FF] hover:bg-[#4066FF]/90 text-white font-medium px-8 py-6 text-lg rounded-xl transition-colors"
>
Delegate Now
</Button>
</Link>
</div>
</div>
</div>
</div>
);
};
2 changes: 2 additions & 0 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { NetworkTabs } from "./NetworkTabs";
import { SubNav } from "./SubNav";
import { VeTokensCallout } from "./VeTokensCallout";
import { WalletConnectButton } from "./WalletConnectButton";
import { DataSplitSection } from "./DataSplitSection";

export const Header: FC<{
hideHero?: boolean;
Expand Down Expand Up @@ -43,6 +44,7 @@ export const Header: FC<{
</div>
{!hideHero && (
<ContentSection>
{/* <DataSplitSection /> */}
<div className="flex flex-row h-[342px] py-6 justify-between items-start max-md:py-12 max-md:h-auto">
<div className="flex justify-center items-center">
<div>
Expand Down
Loading