Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
06e75ce
fix: hide SSV balance display for migrated operators with zero yearly…
axelrod-blox Feb 16, 2026
c22c95a
fix: align migration flow liquidation collateral calculation with sta…
axelrod-blox Feb 16, 2026
5cfeaf4
fix: remove incorrect /32 division from migration funding fee display
liorrutenberg Feb 16, 2026
c65de10
Merge pull request #1735 from ssvlabs/fix/migration-liquidation-colla…
IlyaVi Feb 16, 2026
8e27075
fix: change of labels for liquidation during migration
Chris-ssvlabs Feb 17, 2026
b2c4c05
Merge pull request #1737 from ssvlabs/fix/liquidation-tooltips
Chris-ssvlabs Feb 17, 2026
24962fb
fix: change of statuses used to determine deposited and not deposited…
Chris-ssvlabs Feb 17, 2026
337f687
Merge pull request #1738 from ssvlabs/fix/validator-breakdown-migration
Chris-ssvlabs Feb 17, 2026
5ebd1aa
fix: change the sizes of private operator icon to be responsive
Chris-ssvlabs Feb 17, 2026
c93f5f0
Merge pull request #1739 from ssvlabs/fix/private-op-lock-icon
Chris-ssvlabs Feb 17, 2026
24e5864
ci: changed contract addresses
sumbat-ssvlabs Feb 17, 2026
d1b22d9
Merge pull request #1740 from ssvlabs/feature/new-contracts
IlyaVi Feb 17, 2026
6d8c120
fix: use effective balance in ETH for migration liquidation collateral
Chris-ssvlabs Feb 17, 2026
b5d26af
fix: prefix (#1742)
sumbat-ssvlabs Feb 17, 2026
9723c79
Merge pull request #1741 from ssvlabs/fix/liq-col
Chris-ssvlabs Feb 17, 2026
6227525
fix: align liquidation collateral math with shared funding logic
Chris-ssvlabs Feb 18, 2026
44f6afc
Merge pull request #1743 from ssvlabs/fix/liq-col
Chris-ssvlabs Feb 18, 2026
9a29ba4
fix: funding calculation (#1744)
sumbat-ssvlabs Feb 18, 2026
f88d7db
Fex/merge hoodi stage (#1747)
sumbat-ssvlabs Feb 18, 2026
2003af5
fix: operator fee 11294034432 (#1745)
sumbat-ssvlabs Feb 18, 2026
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
16 changes: 9 additions & 7 deletions .github/workflows/build_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ jobs:
\"insufficientBalanceUrl\": \"https://faucet.stage.ssv.network\",
\"googleTagSecret\": \"${{ secrets.STAGE_GOOGLE_TAG_SECRET }}\",
\"tokenAddress\": \"0x746c33ccc28b1363c35c09badaf41b2ffa7e6d56\",
\"setterContractAddress\": \"0x0aaace4e8affc47c6834171c88d342a4abd8f105\",
\"getterContractAddress\": \"0x9143b8c25efa53f28de4cbefd0b6dfd66d43fea6\"
\"setterContractAddress\": \"0x384AC2c8AF4Df1faD7E20F15064B2C2917fAa7a3\",
\"getterContractAddress\": \"0x92c71f0A9823789f72BAEBB2BFE39e897bDd26bd\"
}
]
PROD_SSV_NETWORKS: >
Expand Down Expand Up @@ -87,14 +87,17 @@ jobs:
- name: Run lint
run: pnpm lint

- name: Run tests
run: pnpm run test:run

- name: Run semantic-release
if: github.event_name == 'push' && (github.ref == 'refs/heads/stage' || github.ref == 'refs/heads/main')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release

- name: Configure AWS credentials
if: github.ref == 'refs/heads/pre-stage' || github.ref == 'refs/heads/stage' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/bapps-prod'
if: github.ref == 'refs/heads/pre-stage' || github.ref == 'refs/heads/stage' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/bapps-prod' || github.ref == 'refs/heads/temporary-hoodi-deploy'
uses: aws-actions/configure-aws-credentials@50ac8dd1e1b10d09dac7b8727528b91bed831ac0 # v3
with:
role-to-assume: ${{ secrets.SSV_WEB_AWS_IAM_ROLE }}
Expand All @@ -121,10 +124,9 @@ jobs:
run: |
aws s3 cp ./build s3://${{ secrets.SSV_WEB_STAGE_AWS_S3_BUCKET }} --recursive
# </app.stage.ssv.network>

# <app.ssv.network>
- name: Run prod webapp build
if: github.ref == 'refs/heads/main'
if: github.ref == 'refs/heads/temporary-hoodi-deploy'
run: >
GAS_PRICE="${{ env.GAS_PRICE }}"
GAS_LIMIT="${{ env.GAS_LIMIT }}"
Expand All @@ -141,7 +143,7 @@ jobs:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}

- name: Upload files to S3
if: github.ref == 'refs/heads/main'
if: github.ref == 'refs/heads/temporary-hoodi-deploy'
run: |
aws s3 cp ./build s3://${{ secrets.SSV_WEB_PROD_HOODI_AWS_S3_BUCKET }} --recursive
# </app.ssv.network>
# </app.ssv.network>
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

pnpm run test:run
pnpm run lint-staged
10 changes: 8 additions & 2 deletions scripts/generate-hook-exports.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,14 @@ function generate() {
const outputPath = path.join(HOOKS_DIR, `${name}.ts`);
const content = generateExportFile(name, hookNames);

fs.writeFileSync(outputPath, content, "utf-8");
console.log(` Generated: ${outputPath}`);
const existing = fs.existsSync(outputPath) ? fs.readFileSync(outputPath, "utf-8") : "";
const normalize = (s) => s.replace(/\s/g, "");
if (normalize(existing) === normalize(content)) {
console.log(` Unchanged: ${outputPath}`);
} else {
fs.writeFileSync(outputPath, content, "utf-8");
console.log(` Generated: ${outputPath}`);
}
}

console.log("Done!");
Expand Down
5 changes: 3 additions & 2 deletions src/app/layouts/dashboard/navbar-dvt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { HiOutlineExternalLink, HiOutlineGlobeAlt } from "react-icons/hi";
import { TbDots } from "react-icons/tb";

import { ConnectWalletBtn } from "@/components/connect-wallet/connect-wallet-btn";
import { NetworkSwitchBtn } from "@/components/connect-wallet/network-switch-btn";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
Expand All @@ -23,6 +22,7 @@ import { ThemeSwitcher } from "@/components/ui/theme-switcher";
import { Link } from "react-router-dom";
import { useLinks } from "@/hooks/use-links";
import { useAccountState } from "@/hooks/account/use-account-state";
import { NetworkSwitcher } from "@/components/connect-wallet/network-switcher-hotfix";

export type NavbarProps = {
// TODO: Add props or remove this type
Expand Down Expand Up @@ -130,7 +130,8 @@ export const NavbarDVT: FCProps = ({ className, ...props }) => {

<Spacer />
<div className="flex items-center gap-3">
<NetworkSwitchBtn />
{/* <NetworkSwitchBtn /> */}
<NetworkSwitcher />
<ConnectWalletBtn />
<ThemeSwitcher />
</div>
Expand Down
14 changes: 14 additions & 0 deletions src/app/layouts/dashboard/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,20 @@ export const Navbar: FCProps = ({ className, ...props }) => {
</DropdownMenu>
<div className="flex items-center gap-3">
<NetworkSwitchBtn />
<Button
as="a"
href="https://app.ssv.network/"
target="_blank"
size="wallet"
variant="secondary"
colorScheme="wallet"
className={textVariants({
variant: "body-3-medium",
className: "flex items-center h-12 px-4 rounded-xl",
})}
>
Mainnet App
</Button>
<ConnectWalletBtn />
</div>
<ThemeSwitcher className="ml-3" />
Expand Down
7 changes: 4 additions & 3 deletions src/app/routes/create-cluster/additional-funding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export const AdditionalFunding: FC = () => {
});

const context = useRegisterValidatorContext();
const deltaValidators = BigInt(context.shares.length);

const deltaEffectiveBalance = context.effectiveBalance;

const form = useForm({
defaultValues: { depositAmount: context.depositAmount, topUp: true },
Expand All @@ -53,7 +54,7 @@ export const AdditionalFunding: FC = () => {

const { data: clusterRunway } = useClusterRunway(params.clusterHash!, {
deltaBalance: topUp ? depositAmount : 0n,
deltaValidators,
deltaEffectiveBalance,
});

const submit = form.handleSubmit((data) => {
Expand All @@ -80,7 +81,7 @@ export const AdditionalFunding: FC = () => {
<Divider />
<EstimatedOperationalRunway
withAlerts={false}
deltaValidators={deltaValidators}
deltaEffectiveBalance={deltaEffectiveBalance}
deltaBalance={topUp ? depositAmount : 0n}
/>
</Card>
Expand Down
8 changes: 4 additions & 4 deletions src/app/routes/create-cluster/initial-funding.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
useComputeFundingCost,
useFundingCost,
useFundingCostETH,
} from "@/hooks/use-compute-funding-cost";
import type { ComponentPropsWithoutRef, FC } from "react";
import { Alert, AlertDescription } from "@/components/ui/alert";
Expand Down Expand Up @@ -88,19 +88,19 @@ export const InitialFunding: FCProps = ({ ...props }) => {
days && days < globals.CLUSTER_VALIDITY_PERIOD_MINIMUM,
);

const customFundingCost = useFundingCost({
const customFundingCost = useFundingCostETH({
fundingDays: values.custom,
operators: operators.data ?? [],
effectiveBalance,
});

const yearFundingCost = useFundingCost({
const yearFundingCost = useFundingCostETH({
fundingDays: periods.year,
operators: operators.data ?? [],
effectiveBalance,
});

const halfYearFundingCost = useFundingCost({
const halfYearFundingCost = useFundingCostETH({
fundingDays: periods["half-year"],
operators: operators.data ?? [],
effectiveBalance,
Expand Down
4 changes: 1 addition & 3 deletions src/app/routes/create-cluster/preparation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ export const Preparation: FCProps = ({ className, ...props }) => {
</div>
<div className="flex items-center gap-2">
<BiCheck className="size-5 text-green-500" />
<Text variant="body-2-medium">
SSV tokens to cover operational fees
</Text>
<Text variant="body-2-medium">ETH to cover operational fees</Text>
</div>
</div>
<div className="flex flex-col w-full gap-3">
Expand Down
8 changes: 4 additions & 4 deletions src/app/routes/create-cluster/reactivate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { useClusterPageParams } from "@/hooks/cluster/use-cluster-page-params";
import { useOperators } from "@/hooks/operator/use-operators";
import {
useComputeFundingCost,
useFundingCost,
useFundingCostETH,
} from "@/hooks/use-compute-funding-cost";
import { withTransactionModal } from "@/lib/contract-interactions/utils/useWaitForTransactionReceipt";
import { useReactivate } from "@/lib/contract-interactions/write/use-reactivate";
Expand Down Expand Up @@ -104,19 +104,19 @@ export const ReactivateCluster: FCProps = ({ ...props }) => {
days && days < globals.CLUSTER_VALIDITY_PERIOD_MINIMUM,
);

const customFundingCost = useFundingCost({
const customFundingCost = useFundingCostETH({
fundingDays: values.custom,
operators: operators.data ?? [],
effectiveBalance,
});

const yearFundingCost = useFundingCost({
const yearFundingCost = useFundingCostETH({
fundingDays: periods.year,
operators: operators.data ?? [],
effectiveBalance,
});

const halfYearFundingCost = useFundingCost({
const halfYearFundingCost = useFundingCostETH({
fundingDays: periods["half-year"],
operators: operators.data ?? [],
effectiveBalance,
Expand Down
1 change: 1 addition & 0 deletions src/app/routes/dashboard/clusters/cluster/cluster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export const Cluster: FC = () => {
<div className="grid grid-cols-4 gap-6 w-full">
{cluster.data?.operators.map((operatorId) => (
<OperatorStatCard
isClusterMigrated={isMigrated}
key={operatorId}
className="w-full"
operatorId={operatorId}
Expand Down
3 changes: 1 addition & 2 deletions src/app/routes/dashboard/operators/operator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export const Operator: FC<ComponentPropsWithoutRef<"div">> = ({ ...props }) => {
const params = useOperatorPageParams();
const operatorId = BigInt(params.operatorId!);
const operator = useOperator(operatorId!);

const { feeEth, yearlyFeeEth, yearlyFeeSSV, balanceEth, balanceSSV } =
useOperatorEarningsAndFees(operatorId);

Expand Down Expand Up @@ -104,7 +103,7 @@ export const Operator: FC<ComponentPropsWithoutRef<"div">> = ({ ...props }) => {
</Text>
<div className="flex flex-col gap-4">
<BalanceDisplay amount={balanceEth} token="ETH" />
<BalanceDisplay amount={balanceSSV} token="SSV" />
{yearlyFeeSSV !== 0n && !operator.data.migrated && <BalanceDisplay amount={balanceSSV} token="SSV" />}
</div>
<Tooltip
asChild
Expand Down
39 changes: 28 additions & 11 deletions src/app/routes/join/operator/set-operator-fee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,42 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { Text } from "@/components/ui/text";
import { BigNumberInput } from "@/components/ui/number-input";
import { formatUnits, parseEther } from "viem";
import { globals } from "@/config";
import { Button } from "@/components/ui/button";
import { useNavigate } from "react-router-dom";
import { NavigateBackBtn } from "@/components/ui/navigate-back-btn";
import { useFocus } from "@/hooks/use-focus";
import { useRegisterOperatorContext } from "@/guard/register-operator-guards";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { useRates } from "@/hooks/use-rates";
import { currencyFormatter } from "@/lib/utils/number";
import { currencyFormatter, ms } from "@/lib/utils/number";
import { Tooltip } from "@/components/ui/tooltip";
import { FaCircleInfo } from "react-icons/fa6";

const minimumFee =
globals.BLOCKS_PER_YEAR * globals.MINIMUM_OPERATOR_FEE_PER_BLOCK;
import {
useGetMaximumOperatorFee,
useGetMinimumOperatorEthFee,
} from "@/lib/contract-interactions/hooks/getter";
import { getYearlyFee } from "@/lib/utils/operator";

export const SetOperatorFee: FC<ComponentPropsWithoutRef<"div">> = () => {
const navigate = useNavigate();
const { isPrivate } = useRegisterOperatorContext();

const navigate = useNavigate();
const rates = useRates();

const { data: minFee = 0n } = useGetMinimumOperatorEthFee({
staleTime: ms(1, "weeks"),
});
const { data: maxFee = 13900000000n /* value from the contract */ } =
useGetMaximumOperatorFee({
staleTime: ms(1, "weeks"),
});

const minYearlyFee = getYearlyFee(minFee);
const minYearlyFeeFormatted = getYearlyFee(minFee, { format: true });

const maxYearlyFee = getYearlyFee(maxFee);
const maxYearlyFeeFormatted = getYearlyFee(maxFee, { format: true });

const ethRate = rates.data?.eth ?? 0;

const form = useForm({
Expand All @@ -43,10 +60,10 @@ export const SetOperatorFee: FC<ComponentPropsWithoutRef<"div">> = () => {
resolver: zodResolver(
z.object({
yearlyFee: z.bigint().superRefine((value, ctx) => {
if (value > parseEther("200")) {
if (value > maxYearlyFee) {
return ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Fee must be lower than 200 ETH",
message: `Fee must be lower than ${maxYearlyFeeFormatted}`,
});
}
if (isPrivate && value === parseEther("0")) return;
Expand All @@ -57,10 +74,10 @@ export const SetOperatorFee: FC<ComponentPropsWithoutRef<"div">> = () => {
message: `Fee cannot be set to 0 while operator status is set to public. To set the fee to 0, switch the operator status to private in the previous step.`,
});

if (value >= parseEther("0") && value < minimumFee)
if (value >= parseEther("0") && value < minYearlyFee)
return ctx.addIssue({
code: z.ZodIssueCode.custom,
message: `Fee must be greater than ${formatUnits(minimumFee, 18)} ETH`,
message: `Fee must be greater than ${minYearlyFeeFormatted}`,
});
}),
}),
Expand Down Expand Up @@ -137,7 +154,7 @@ export const SetOperatorFee: FC<ComponentPropsWithoutRef<"div">> = () => {
id="register-operator-fee"
value={field.value}
onChange={field.onChange}
max={parseEther("200")}
max={maxYearlyFee}
rightSlot={
<div className="flex items-center gap-1 px-3">
<img
Expand Down
4 changes: 2 additions & 2 deletions src/components/cluster/cluster-funding-summary.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { FC, ComponentPropsWithoutRef } from "react";
import { cn } from "@/lib/utils/tw";
import type { UseFundingCostArgs } from "@/hooks/use-compute-funding-cost";
import { useFundingCost } from "@/hooks/use-compute-funding-cost";
import { useFundingCostETH } from "@/hooks/use-compute-funding-cost";
import { Text } from "@/components/ui/text";
import { formatSSV } from "@/lib/utils/number";
import { Divider } from "@/components/ui/divider";
Expand All @@ -23,7 +23,7 @@ export const ClusterFundingSummary: ClusterFundingSummaryFC = ({
...props
}) => {
// const isBulk = validatorsAmount > 1;
const cost = useFundingCost({
const cost = useFundingCostETH({
operators,
fundingDays,
effectiveBalance,
Expand Down
14 changes: 8 additions & 6 deletions src/components/cluster/estimated-operational-runway.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { FC, ComponentPropsWithoutRef } from "react";
import type { ComponentPropsWithoutRef, FC } from "react";
import { cn } from "@/lib/utils/tw";
import { Span, Text } from "@/components/ui/text";
import { FaCircleInfo } from "react-icons/fa6";
Expand All @@ -13,7 +13,7 @@ import { humanizeFundingDuration } from "@/lib/utils/date";
export type EstimatedOperationalRunwayProps = {
clusterHash?: string;
deltaBalance?: bigint;
deltaValidators?: bigint;
deltaEffectiveBalance?: bigint;
withAlerts?: boolean;
};

Expand All @@ -25,7 +25,7 @@ type EstimatedOperationalRunwayFC = FC<
export const EstimatedOperationalRunway: EstimatedOperationalRunwayFC = ({
className,
clusterHash,
deltaValidators = 0n,
deltaEffectiveBalance = 0n,
deltaBalance = 0n,
withAlerts = true,
...props
Expand All @@ -37,7 +37,7 @@ export const EstimatedOperationalRunway: EstimatedOperationalRunwayFC = ({

const { data: clusterRunway } = useClusterRunway(hash!, {
deltaBalance,
deltaValidators,
deltaEffectiveBalance,
watch: true,
});

Expand Down Expand Up @@ -81,10 +81,12 @@ export const EstimatedOperationalRunway: EstimatedOperationalRunwayFC = ({
{withAlerts && (
<EstimatedOperationalRunwayAlert
isLiquidated={isLiquidated.data ?? false}
hasDeltaValidators={deltaValidators !== 0n}
hasDeltaValidators={deltaEffectiveBalance !== 0n}
isAtRisk={clusterRunway?.isAtRisk ?? false}
runway={clusterRunway?.runway ?? 0n}
isWithdrawing={clusterRunway?.isDecreasing && !deltaValidators}
isWithdrawing={
clusterRunway?.isDecreasing && deltaEffectiveBalance === 0n
}
/>
)}
</div>
Expand Down
Loading