Skip to content
Open
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
18 changes: 14 additions & 4 deletions app/console/history/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,22 @@ export default function ConsoleHistoryPage() {
type: 'address'
});
}
if (toolboxStore.stakingManagerAddress && toolboxStore.stakingManagerAddress !== '') {
if (toolboxStore.nativeStakingManagerAddress && toolboxStore.nativeStakingManagerAddress !== '') {
items.push({
id: 'tb-staking-mgr',
title: 'Staking Manager',
id: 'tb-native-staking-mgr',
title: 'Native Token Staking Manager',
description: 'Deployed Contract',
address: toolboxStore.stakingManagerAddress,
address: toolboxStore.nativeStakingManagerAddress,
chainId,
type: 'address'
});
}
if (toolboxStore.erc20StakingManagerAddress && toolboxStore.erc20StakingManagerAddress !== '') {
items.push({
id: 'tb-erc20-staking-mgr',
title: 'ERC20 Token Staking Manager',
description: 'Deployed Contract',
address: toolboxStore.erc20StakingManagerAddress,
chainId,
type: 'address'
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import DelegateToValidator from '@/components/toolbox/console/permissionless-l1s/delegate/native/Delegate';

export default function DelegateNativeTokenPage() {
return <DelegateToValidator />;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use client";

import StepFlow from "@/components/console/step-flow";
import { steps } from "../steps";

export default function ERC20StakingManagerSetupClientPage({ currentStepKey }: { currentStepKey: string }) {
const basePath = "/console/permissionless-l1s/erc20-staking-manager-setup";
return (
<StepFlow
steps={steps}
basePath={basePath}
currentStepKey={currentStepKey}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import ERC20StakingManagerSetupClientPage from "./client-page";

export default async function Page({ params }: { params: Promise<{ step: string }> }) {
const { step } = await params;
return (
<ERC20StakingManagerSetupClientPage currentStepKey={step} />
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { redirect } from "next/navigation";

export default function Page() {
redirect("/console/permissionless-l1s/erc20-staking-manager-setup/deploy-erc20-staking-manager");
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { type StepDefinition } from "@/components/console/step-flow";
import ReadContract from "@/components/toolbox/console/permissioned-l1s/validator-manager-setup/ReadContract";
import DeployNativeTokenStakingManager from "@/components/toolbox/console/permissionless-l1s/setup/native/DeployNativeStakingManager";
import InitializeNativeTokenStakingManager from "@/components/toolbox/console/permissionless-l1s/setup/native/InitializeNativeStakingManager";
import DeployERC20StakingManager from "@/components/toolbox/console/permissionless-l1s/setup/erc20/DeployERC20StakingManager";
import InitializeERC20StakingManager from "@/components/toolbox/console/permissionless-l1s/setup/erc20/InitializeERC20StakingManager";
import DeployExampleRewardCalculator from "@/components/toolbox/console/permissionless-l1s/setup/DeployExampleRewardCalculator";
import TransferOwnership from "@/components/toolbox/console/permissioned-l1s/multisig-setup/TransferOwnership";
import EnableStakingManagerMinting from "@/components/toolbox/console/permissionless-l1s/setup/native/EnableStakingManagerMinting";

export const steps: StepDefinition[] = [
{
type: "single",
key: "deploy-erc20-staking-manager",
title: "Deploy ERC20 Token Staking Manager",
component: DeployERC20StakingManager,
},
{ type: "single", key: "deploy-example-reward-calculator", title: "Deploy Example Reward Calculator", component: DeployExampleRewardCalculator },
{
type: "single",
key: "initialize-erc20-staking-manager",
title: "Initialize ERC20 Token Staking Manager",
component: InitializeERC20StakingManager,
},
{ type: "single", key: "transfer-ownership", title: "Transfer Ownership", component: TransferOwnership },
{ type: "single", key: "read-contract", title: "Read Contract", component: ReadContract },
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use client";

import StepFlow from "@/components/console/step-flow";
import { steps } from "../steps";

export default function NativeStakingManagerSetupClientPage({ currentStepKey }: { currentStepKey: string }) {
const basePath = "/console/permissionless-l1s/native-staking-manager-setup";
return (
<StepFlow
steps={steps}
basePath={basePath}
currentStepKey={currentStepKey}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import NativeStakingManagerSetupClientPage from "./client-page";

export default async function Page({ params }: { params: Promise<{ step: string }> }) {
const { step } = await params;
return (
<NativeStakingManagerSetupClientPage currentStepKey={step} />
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { redirect } from "next/navigation";

export default function Page() {
redirect("/console/permissionless-l1s/native-staking-manager-setup/deploy-native-token-staking-manager");
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { type StepDefinition } from "@/components/console/step-flow";
import ReadContract from "@/components/toolbox/console/permissioned-l1s/validator-manager-setup/ReadContract";
import DeployNativeTokenStakingManager from "@/components/toolbox/console/permissionless-l1s/setup/native/DeployNativeStakingManager";
import InitializeNativeTokenStakingManager from "@/components/toolbox/console/permissionless-l1s/setup/native/InitializeNativeStakingManager";
import DeployERC20StakingManager from "@/components/toolbox/console/permissionless-l1s/setup/erc20/DeployERC20StakingManager";
import InitializeERC20StakingManager from "@/components/toolbox/console/permissionless-l1s/setup/erc20/InitializeERC20StakingManager";
import DeployExampleRewardCalculator from "@/components/toolbox/console/permissionless-l1s/setup/DeployExampleRewardCalculator";
import TransferOwnershipToStakingManager from "@/components/toolbox/console/permissionless-l1s/setup/TransferOwnershipToStakingManager";
import EnableStakingManagerMinting from "@/components/toolbox/console/permissionless-l1s/setup/native/EnableStakingManagerMinting";

export const steps: StepDefinition[] = [
{
type: "single",
key: "deploy-native-token-staking-manager",
title: "Deploy Staking Manager",
component: DeployNativeTokenStakingManager,
},
{ type: "single", key: "deploy-example-reward-calculator", title: "Deploy Example Reward Calculator", component: DeployExampleRewardCalculator },
{
type: "single",
key: "initialize-native-staking-manager",
title: "Initialize Staking Manager",
component: InitializeNativeTokenStakingManager,
},
{ type: "single", key: "enable-staking-minting", title: "Enable StakingManager in Native Minter", component: EnableStakingManagerMinting },
{ type: "single", key: "transfer-ownership", title: "Transfer Ownership to Staking Manager", component: TransferOwnershipToStakingManager },
{ type: "single", key: "read-contract", title: "Read Contract", component: ReadContract },
];
7 changes: 7 additions & 0 deletions app/console/permissionless-l1s/stake-native-token/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Stake from "@/components/toolbox/console/permissionless-l1s/staking/native/Stake";

export default function Page() {
return (
<Stake />
);
}
20 changes: 14 additions & 6 deletions components/console/console-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,17 +226,25 @@ const data = {
icon: Globe,
items: [
{
title: "Migrate from Permissioned L1",
url: "/console/permissionless-l1s/deploy-reward-manager",
title: "Native Staking Manager Setup",
url: "/console/permissionless-l1s/native-staking-manager-setup",
icon: GitMerge,
},
{
title: "ERC20 Staking Manager Setup",
url: "/console/permissionless-l1s/erc20-staking-manager-setup",
icon: GitMerge,
comingSoon: true,
},
{
title: "Stake & Unstake",
url: "/console/permissionless-l1s/manage-validators",
title: "Stake Native Token",
url: "/console/permissionless-l1s/stake-native-token",
icon: Hexagon,
comingSoon: true,
},
{
title: "Delegate Native Token",
url: "/console/permissionless-l1s/delegate-native-token",
icon: HandCoins,
}
],
},
{
Expand Down
7 changes: 6 additions & 1 deletion components/toolbox/components/AllowListComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@ function SetEnabledComponent({
precompileType = "precompiled contract",
abi = allowListAbi.abi,
onSuccess,
defaultAddress,
}: {
precompileAddress: string;
precompileType?: string;
abi?: any;
onSuccess?: () => void;
defaultAddress?: string;
}) {
const { publicClient, walletEVMAddress, walletChainId } =
useWalletStore();
const { coreWalletClient } = useConnectedWallet();
const viemChain = useViemChainStore();
const [isProcessing, setIsProcessing] = useState(false);
const [enabledAddress, setEnabledAddress] = useState<string>("");
const [enabledAddress, setEnabledAddress] = useState<string>(defaultAddress || "");
const [txHash, setTxHash] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);

Expand Down Expand Up @@ -523,11 +525,13 @@ export function AllowlistComponent({
precompileType = "precompiled contract",
abi = allowListAbi.abi,
onSuccess,
defaultEnabledAddress,
}: {
precompileAddress: string;
precompileType?: string;
abi?: any;
onSuccess?: () => void;
defaultEnabledAddress?: string;
}) {
return (
<div className="space-y-6">
Expand All @@ -538,6 +542,7 @@ export function AllowlistComponent({
precompileType={precompileType}
abi={abi}
onSuccess={onSuccess}
defaultAddress={defaultEnabledAddress}
/>
<SetManagerComponent
precompileAddress={precompileAddress}
Expand Down
21 changes: 16 additions & 5 deletions components/toolbox/components/CheckPrecompile.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { useState, useEffect } from "react";
import { useWalletStore } from "../stores/walletStore";
import { useViemChainStore } from "../stores/toolboxStore";
import { Alert } from "./Alert";
import { getActiveRulesAt } from "../coreViem";
import { createPublicClient, http } from "viem";

type PrecompileConfigKey =
| "warpConfig"
Expand Down Expand Up @@ -33,21 +36,29 @@ export const CheckPrecompile = ({
docsLink,
docsLinkText = "Learn how to activate this precompile"
}: CheckPrecompileProps) => {
const { coreWalletClient, walletChainId } = useWalletStore();
const { walletChainId } = useWalletStore();
const viemChain = useViemChainStore();
const [state, setState] = useState<PrecompileState>({
isActive: false,
isLoading: false,
error: null
});

useEffect(() => {
if (!coreWalletClient) return;
if (!viemChain?.rpcUrls?.default?.http?.[0]) return;

const checkPrecompileStatus = async () => {
setState(prev => ({ ...prev, isLoading: true, error: null }));

try {
const data = await coreWalletClient.getActiveRulesAt();
// Create a dedicated publicClient using the chain's RPC URL
// This is necessary because Core wallet provider doesn't support eth_getActiveRulesAt
const rpcPublicClient = createPublicClient({
transport: http(viemChain.rpcUrls.default.http[0]),
chain: viemChain as any,
});

const data = await getActiveRulesAt(rpcPublicClient);
const isActive = Boolean(data.precompiles?.[configKey]?.timestamp);
setState({ isLoading: false, isActive, error: null });
} catch (err) {
Expand All @@ -61,7 +72,7 @@ export const CheckPrecompile = ({
};

checkPrecompileStatus();
}, [coreWalletClient, configKey, walletChainId]);
}, [viemChain, configKey, walletChainId]);

if (state.isLoading) {
return (
Expand Down Expand Up @@ -103,4 +114,4 @@ export const CheckPrecompile = ({
}

return <>{children}</>;
};
};
3 changes: 3 additions & 0 deletions components/toolbox/components/ValidatorListInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ interface ValidatorListInputProps {
maxValidators?: number;
selectedSubnetId?: string | null;
isTestnet?: boolean;
hideConsensusWeight?: boolean;
}

export function ValidatorListInput({
Expand All @@ -42,6 +43,7 @@ export function ValidatorListInput({
maxValidators,
selectedSubnetId = null,
isTestnet = false,
hideConsensusWeight = false,
}: ValidatorListInputProps) {

const [error, setError] = useState<string | null>(null)
Expand Down Expand Up @@ -85,6 +87,7 @@ export function ValidatorListInput({
onChange={onChange}
l1TotalInitializedWeight={l1TotalInitializedWeight}
userPChainBalanceNavax={userPChainBalanceNavax}
hideConsensusWeight={hideConsensusWeight}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ interface Props {
onUpdate: (index: number, updated: Partial<ConvertToL1Validator>) => void
l1TotalInitializedWeight?: bigint | null
userPChainBalanceNavax?: bigint | null
hideConsensusWeight?: boolean
}

export function ValidatorItem({
Expand All @@ -25,6 +26,7 @@ export function ValidatorItem({
onUpdate,
l1TotalInitializedWeight = null,
userPChainBalanceNavax = null,
hideConsensusWeight = false,
}: Props) {

let insufficientBalanceError: string | null = null
Expand Down Expand Up @@ -89,29 +91,31 @@ export function ValidatorItem({
/>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div className="space-y-2">
<label className="block text-sm font-medium text-zinc-700 dark:text-zinc-300">
Consensus Weight
</label>
<input
type="number"
value={validator.validatorWeight.toString()}
onChange={(e) => onUpdate(index, { validatorWeight: BigInt(e.target.value || 0) })}
className={cn(
"w-full rounded p-2",
"bg-zinc-50 dark:bg-zinc-900",
"border border-zinc-200 dark:border-zinc-700",
"text-zinc-900 dark:text-zinc-100",
"shadow-sm focus:ring focus:ring-primary/30 focus:ring-opacity-50",
<div className={cn("grid gap-3", hideConsensusWeight ? "grid-cols-1" : "grid-cols-1 md:grid-cols-2")}>
{!hideConsensusWeight && (
<div className="space-y-2">
<label className="block text-sm font-medium text-zinc-700 dark:text-zinc-300">
Consensus Weight
</label>
<input
type="number"
value={validator.validatorWeight.toString()}
onChange={(e) => onUpdate(index, { validatorWeight: BigInt(e.target.value || 0) })}
className={cn(
"w-full rounded p-2",
"bg-zinc-50 dark:bg-zinc-900",
"border border-zinc-200 dark:border-zinc-700",
"text-zinc-900 dark:text-zinc-100",
"shadow-sm focus:ring focus:ring-primary/30 focus:ring-opacity-50",
)}
/>
{hasWeightError && (
<p className="text-xs mt-1 text-red-500 dark:text-red-400">
Warning: This validator's weight is 20% or more of the current L1 total stake ({ Number(validator.validatorWeight * 10000n / l1TotalInitializedWeight / 100n).toFixed(2) }%). Recommended to be less than 20%.
</p>
)}
/>
{hasWeightError && (
<p className="text-xs mt-1 text-red-500 dark:text-red-400">
Warning: This validator's weight is 20% or more of the current L1 total stake ({ Number(validator.validatorWeight * 10000n / l1TotalInitializedWeight / 100n).toFixed(2) }%). Recommended to be less than 20%.
</p>
)}
</div>
</div>
)}
<div className="space-y-2">
<label className="block text-sm font-medium text-zinc-700 dark:text-zinc-300">
Validator Balance (P-Chain AVAX)
Expand Down
Loading