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
28 changes: 16 additions & 12 deletions src/app/routes/create-cluster/distribute-offline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,15 @@ export const DistributeOffline: FC = () => {
const health = useOperatorsDKGHealth(operators.data ?? [], {
enabled: isNew,
});

const hasUnhealthyOperators =
isNew &&
health.data?.some(
({ isHealthy, isMismatchId }) => !isHealthy || isMismatchId,
);
const hasOutdatedOperator = health.data?.some(({ isOutdated }) => isOutdated);
const isAllOperatorsAreOutdated =
health.data?.every(({ isOutdated }) => isOutdated) || false;
const hasUnhealthyOperators = health.data?.some(
({ isHealthy, isMismatchId }) => !isHealthy || isMismatchId,
);
const hasIssuedOperator = hasOutdatedOperator
? hasUnhealthyOperators || !isAllOperatorsAreOutdated
: hasUnhealthyOperators;

return (
<Container size="lg" variant="vertical" className="py-6">
Expand All @@ -73,7 +76,7 @@ export const DistributeOffline: FC = () => {
isLoading={health.isLoading}
/>
</div>
{selectedOption === "new" && hasUnhealthyOperators && (
{isNew && hasIssuedOperator && (
<>
<UnhealthyOperatorsList
operators={operators.data ?? []}
Expand All @@ -91,11 +94,12 @@ export const DistributeOffline: FC = () => {
)}
</>
)}
{selectedOption === "new" &&
!hasUnhealthyOperators &&
health.isSuccess && (
<DockerInstructions operators={operators.data ?? []} />
)}
{selectedOption === "new" && !hasIssuedOperator && health.isSuccess && (
<DockerInstructions
isOutdatedOperators={isAllOperatorsAreOutdated}
operators={operators.data ?? []}
/>
)}
{selectedOption === "existing" && (
<SSVKeysInstructions operators={operators.data ?? []} />
)}
Expand Down
4 changes: 2 additions & 2 deletions src/app/routes/protected-cluster-route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ export const ProtectedClusterRoute: FC<ComponentPropsWithoutRef<"div">> = ({
const location = useLocation();
const currentPath = location.pathname;
const [enabled] = useLocalStorage("reshareFlowEnabled", false);

if (isUndefined(clusterHash)) return <Navigate to="/clusters" />;
if (cluster.isLoading) return <Loading />;
if (cluster.isError || !cluster.data) return <Navigate to="/clusters" />;
if (isFrom("/clusters/:clusterHash")) resetState();
if (isFrom("/clusters/:clusterHash") && currentPath.includes("reshare"))
resetState();
if (!enabled && currentPath.includes("reshare")) {
return <Navigate to={`/clusters/${clusterHash}`} />;
}
Expand Down
17 changes: 1 addition & 16 deletions src/app/routes/reshare-dkg/ceremony-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@ import { LuCheck, LuCopy } from "react-icons/lu";
import CeremonySummary from "@/app/routes/create-cluster/ceremony-summary.tsx";
import { useQuery } from "@tanstack/react-query";
import { stringifyBigints } from "@/lib/utils/bigint.ts";
import {
DKG_VERSIONS,
generateSSVKeysDockerCMD,
} from "@/lib/utils/keyshares.ts";
import { generateSSVKeysDockerCMD } from "@/lib/utils/keyshares.ts";
import type { Address } from "viem";
import { useAccount } from "@/hooks/account/use-account.ts";
import { useSSVAccount } from "@/hooks/use-ssv-account.ts";
import { useBulkActionContext } from "@/guard/bulk-action-guard.tsx";
import { useReshareDkg } from "@/hooks/use-reshare-dkg.ts";
import { useCopyToClipboard } from "react-use";
import { CompletedBadge } from "@/components/ui/completed-badge.tsx";
import { useOperatorsDKGHealth } from "@/hooks/operator/use-operator-dkg-health.ts";

const VALIDATOR_COUNT_THRESHOLD = 20;

Expand Down Expand Up @@ -45,16 +41,6 @@ const CeremonySection = ({
const context = useBulkActionContext();
const reshareContext = useReshareDkg();
const [copyState, copy] = useCopyToClipboard();
const health = useOperatorsDKGHealth(
context.dkgReshareState.newOperators.length
? context.dkgReshareState.newOperators
: context.dkgReshareState.operators,
);
const version = health.data?.every(
({ isHealthy, isOutdated }) => isHealthy && isOutdated,
)
? DKG_VERSIONS.OLD
: DKG_VERSIONS.NEW;

const cmd = useQuery({
queryKey: stringifyBigints([
Expand Down Expand Up @@ -85,7 +71,6 @@ const CeremonySection = ({
signatures,
os: context.dkgReshareState.selectedOs,
proofsString,
version,
}),
);
},
Expand Down
7 changes: 2 additions & 5 deletions src/app/routes/reshare-dkg/reshare.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@ const Reshare = () => {
? health.data?.every(
({ isHealthy, isEthClientConnected, isOutdated, isMismatchId }) =>
isHealthy && isEthClientConnected && !isOutdated && !isMismatchId,
) ||
health.data?.every(
({ isHealthy, isOutdated, isMismatchId }) =>
isHealthy && isOutdated && !isMismatchId,
)
: health.data?.every(
({ isHealthy, isMismatchId }) => isHealthy && !isMismatchId,
({ isHealthy, isMismatchId, isOutdated }) =>
isHealthy && !isMismatchId && !isOutdated,
);

if (health.isLoading) {
Expand Down
8 changes: 6 additions & 2 deletions src/components/offline-generation/docker-instructions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { type FC } from "react";
import { Button } from "@/components/ui/button";
import { Text } from "@/components/ui/text";
import { Spinner } from "@/components/ui/spinner";
import { generateSSVKeysDockerCMD } from "@/lib/utils/keyshares";
import { DKG_VERSIONS, generateSSVKeysDockerCMD } from "@/lib/utils/keyshares";
import type { Operator } from "@/types/api";
import { LuCheck, LuCopy } from "react-icons/lu";
import { useRegisterValidatorContext } from "@/guard/register-validator-guard";
Expand All @@ -29,6 +29,7 @@ import { useNavigate } from "react-router";

interface DockerInstructionsProps {
operators: Operator[];
isOutdatedOperators: boolean;
}

const schema = z.object({
Expand All @@ -45,6 +46,7 @@ const schema = z.object({

export const DockerInstructions: FC<DockerInstructionsProps> = ({
operators,
isOutdatedOperators,
}) => {
const navigate = useNavigate();

Expand All @@ -71,14 +73,15 @@ export const DockerInstructions: FC<DockerInstructionsProps> = ({
isAddress(withdrawalAddress) &&
validators > 0 &&
hasConfirmed;

const cliVersion = isOutdatedOperators ? DKG_VERSIONS.OLD : DKG_VERSIONS.NEW;
const cmd = useQuery({
queryKey: stringifyBigints([
"docker-cmd",
ssvAccount.data,
account.address,
validators,
withdrawalAddress,
cliVersion,
dkgCeremonyState.selectedOs,
account.chainId,
]),
Expand All @@ -90,6 +93,7 @@ export const DockerInstructions: FC<DockerInstructionsProps> = ({
account: account.address!,
withdrawalAddress: withdrawalAddress as Address,
chainId: account.chainId,
version: cliVersion,
validatorsCount: validators,
os: dkgCeremonyState.selectedOs,
}),
Expand Down
12 changes: 6 additions & 6 deletions src/components/offline-generation/unhealthy-operators-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ const getBadgeInfo = (
text: "ID/IP Mismatch",
};
}
if (healthData.isOutdated) {
return {
variant: "warning" as BadgeVariants["variant"],
text: "Dkg Outdated",
};
}
if (isReshareFlow) {
if (healthData.isOutdated) {
return {
variant: "warning" as BadgeVariants["variant"],
text: "Dkg Outdated",
};
}
if (!healthData.isEthClientConnected) {
return {
variant: "error" as BadgeVariants["variant"],
Expand Down
19 changes: 12 additions & 7 deletions src/hooks/operator/use-reshare-signature-payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,25 @@ export const useReshareSignaturePayload = ({
const nonce = await getOwnerNonce(ownerAddress);
const chainId = FORKS[getChainId(config)];
const payload = (proofsQuery.data?.validators || []).map(
({ publicKey, proofs }) => ({
messageData: {
({ publicKey, proofs }, index: number) => {
const messageData: MessageData = {
publicKey,
oldOperators: context.dkgReshareState.operators,
chainId,
withdrawalCredentials: withdrawAddress,
ownerAddress,
nonce,
nonce: nonce + index,
amount: DEFAULT_AMOUNT,
} as MessageData,
proofs: proofs,
}),
};
if (context.dkgReshareState.newOperators.length) {
messageData.newOperators = context.dkgReshareState.newOperators;
}
return {
messageData,
proofs,
};
},
);

return sign.signMessageAsync({
message: getSignaturePayload(payload),
});
Expand Down
9 changes: 8 additions & 1 deletion src/hooks/use-validate-proofs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,14 @@ export const useValidateProofs = (files: File[]) => {
);
}
state.dkgReshareState.selectedValidatorsCount = validators.length;

if (
json.every((proof: Proof | Proof[]) => Array.isArray(proof)) &&
json.length > validators.length
) {
throw new Error(
"proofs.json must only contain validators that are registered.",
);
}
return {
proofs: json,
validators,
Expand Down
9 changes: 5 additions & 4 deletions src/lib/utils/dkg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ const serializedResignMessage = (message: {
const serializedReshareMessage = (message: {
messageData: MessageData;
proofs: ProofType[];
}) =>
ReshareMessageType.serialize({
}) => {
return ReshareMessageType.serialize({
Reshare: {
ValidatorPubKey: parseHexToBuffer(message.messageData.publicKey),
OldOperators: message.messageData.oldOperators.map(
Expand All @@ -134,8 +134,8 @@ const serializedReshareMessage = (message: {
PubKey: Buffer.from(op.public_key),
}),
),
OldT: message.messageData.oldOperators.length % 3,
NewT: (message.messageData.newOperators || []).length % 3,
OldT: Number(message.messageData.oldOperators.length % 3),
NewT: Number((message.messageData.newOperators || []).length % 3),
Fork: parseHexToBuffer(message.messageData.chainId).slice(0, 4),
WithdrawalCredentials: parseHexToBuffer(
message.messageData.withdrawalCredentials,
Expand All @@ -154,6 +154,7 @@ const serializedReshareMessage = (message: {
Signature: parseHexToBuffer(proof.signature),
})),
});
};

export const getSignaturePayload = (
data: {
Expand Down
6 changes: 3 additions & 3 deletions src/lib/utils/keyshares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export const generateSSVKeysDockerCMD = ({
chainId = getChainId(config),
validatorsCount = 1,
os = getOSName(),
version = DKG_VERSIONS.OLD,
version = DKG_VERSIONS.NEW,
newOperators,
signatures,
proofsString,
Expand Down Expand Up @@ -166,7 +166,7 @@ export const generateSSVKeysDockerCMD = ({
.map((op) => op.id)
.join(",")}`
: ""
} --withdrawAddress ${withdrawalAddress} --owner ${account} --nonce ${nonce} --network ${chainName} ${proofsString ? `--proofsString ${proofsString}` : "--proofsFilePath /data/proofs.json"} --operatorsInfo ${newOperators ? getOperatorsData([...operators, ...newOperators]) : getOperatorsData(operators)} --signatures ${signatures} --outputPath /output --logLevel info --logFormat json --logLevelFormat capitalColor --logFilePath /data/debug.log --tlsInsecure`;
} --withdrawAddress ${withdrawalAddress} --owner ${account} --nonce ${nonce} --network ${chainName} ${proofsString ? `--proofsString '${proofsString}'` : "--proofsFilePath ./data/proofs.json"} --operatorsInfo ${newOperators ? getOperatorsData([...operators, ...newOperators]) : getOperatorsData(operators)} --signatures ${signatures} --outputPath ./output --logLevel info --logFormat json --logLevelFormat capitalColor --logFilePath ./data/debug.log --tlsInsecure`;
}
return `docker pull bloxstaking/ssv-dkg:v2.1.0 && docker run --rm -v ${dynamicFullPath}:/data -it "bloxstaking/ssv-dkg:v${version}" init --owner ${account} --nonce ${nonce} --withdrawAddress ${withdrawalAddress} --operatorIDs ${operatorIds} --operatorsInfo ${getOperatorsData(sortedOperators)} --network ${chainName} --validators ${validatorsCount} --logFilePath /data/debug.log --outputPath /data`;
return `docker pull bloxstaking/ssv-dkg:v${version} && docker run --rm -v ${dynamicFullPath}:/data -it "bloxstaking/ssv-dkg:v${version}" init --owner ${account} --nonce ${nonce} --withdrawAddress ${withdrawalAddress} --operatorIDs ${operatorIds} --operatorsInfo ${getOperatorsData(sortedOperators)} --network ${chainName} --validators ${validatorsCount} ${version === DKG_VERSIONS.OLD ? "--logFilePath /data/debug.log --outputPath /data" : "--logFilePath ./data/debug.log --outputPath ./data --tlsInsecure"}}`;
};
Loading