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
151 changes: 18 additions & 133 deletions src/components/Staking/WithdrawalCredentials.tsx
Original file line number Diff line number Diff line change
@@ -1,143 +1,27 @@
"use client"

import { ChangeEvent, FC, type JSX, useMemo, useState } from "react"
import { ChangeEvent, FC, useState } from "react"

import CopyToClipboard from "@/components/CopyToClipboard"
import Emoji from "@/components/Emoji"
import Translation from "@/components/Translation"

import { trackCustomEvent } from "@/lib/utils/matomo"
import { ButtonLink } from "@/components/ui/buttons/Button"

import { CANONICAL_STAKING_TESTNET } from "@/lib/constants"

import { Alert, AlertContent } from "../ui/alert"
import { Button } from "../ui/buttons/Button"
import { Flex } from "../ui/flex"
import Input from "../ui/input"
import { Spinner } from "../ui/spinner"

import { useTranslation } from "@/hooks/useTranslation"

interface Validator {
validatorIndex: number
withdrawalCredentials: string
isUpgraded: boolean
isTestnet?: boolean
}

const WithdrawalCredentials: FC = () => {
const { t } = useTranslation("page-staking")
const [isLoading, setIsLoading] = useState<{
mainnet: boolean
testnet: boolean
}>({ mainnet: false, testnet: false })
const [hasError, setHasError] = useState<boolean>(false)
const [inputValue, setInputValue] = useState<string>("")
const [validator, setValidator] = useState<Validator | null>(null)

const checkWithdrawalCredentials = async (isTestnet: boolean = false) => {
const network = isTestnet ? CANONICAL_STAKING_TESTNET : "Mainnet"
const networkLowercase = network.toLowerCase()
trackCustomEvent({
eventCategory: `Validator index`,
eventAction: `Verify on ${network}`,
eventName: `click`,
})
setHasError(false)
setIsLoading((prev) =>
isTestnet ? { ...prev, testnet: true } : { ...prev, mainnet: true }
)
const endpoint = `https://${networkLowercase}.beaconcha.in/api/v1/validator/${inputValue}`
try {
const response = await fetch(endpoint)
const { data } = await response.json()
const withdrawalCredentials = data.length
? data[0].withdrawalcredentials
: data.withdrawalcredentials
setValidator({
validatorIndex: parseInt(inputValue),
withdrawalCredentials,
isUpgraded: withdrawalCredentials.startsWith("0x01"),
isTestnet,
})
} catch (error) {
console.error(error)
setHasError(true)
} finally {
setIsLoading((prev) =>
isTestnet ? { ...prev, testnet: false } : { ...prev, mainnet: false }
)
}
}

const handleChange = (e: ChangeEvent<HTMLInputElement>) =>
setInputValue(e.target.value.replace(/\D/g, ""))

const longAddress = useMemo<string>(
() => (validator ? `0x${validator.withdrawalCredentials.slice(-40)}` : ""),
[validator]
)
const shortAddress = useMemo<string>(
() =>
longAddress ? `${longAddress.slice(0, 6)}…${longAddress.slice(-4)}` : "",
[longAddress]
)
const resultText = useMemo<string | JSX.Element>(() => {
if (hasError)
return (
<Alert variant="error">
<AlertContent className="inline">
{t("comp-withdrawal-credentials-error")}
</AlertContent>
</Alert>
)
if (!validator) return " "
if (validator.isUpgraded)
return (
<Alert variant="success">
<AlertContent className="inline">
<strong>
<Translation
id="page-staking:comp-withdrawal-credentials-upgraded-1"
values={{ validatorIndex: validator.validatorIndex }}
/>{" "}
</strong>
{t("comp-withdrawal-credentials-upgraded-2")}{" "}
<CopyToClipboard text={longAddress} inline>
{(isCopied) => (
<>
<strong title={longAddress}>{shortAddress}</strong>
{isCopied ? (
<>
<Emoji text="✅" className="mx-2 text-lg" />
<span title={longAddress}>{t("copied")}</span>
</>
) : (
<Emoji text="📋" className="mx-2 text-lg" />
)}
</>
)}
</CopyToClipboard>
</AlertContent>
</Alert>
)
return (
<Alert variant="error">
<AlertContent className="inline">
<strong>
{t("page-staking:comp-withdrawal-credentials-not-upgraded-1", {
network: validator.isTestnet
? t("page-staking:page-staking-network-testnet", {
network: CANONICAL_STAKING_TESTNET,
})
: "",
})}
</strong>{" "}
<Translation id="page-staking:comp-withdrawal-credentials-not-upgraded-2" />
</AlertContent>
</Alert>
)
}, [hasError, validator, longAddress, shortAddress, t])
const mainnetHref = `https://beaconcha.in/validator/${inputValue}#deposits`
const testnetHref = `https://hoodi.beaconcha.in/validator/${inputValue}#deposits`
const isDisabled = !inputValue.length
const disabledClass = isDisabled ? "pointer-events-none opacity-50" : ""

return (
<Flex className="flex-col gap-4">
Expand All @@ -150,28 +34,29 @@ const WithdrawalCredentials: FC = () => {
placeholder={t("comp-withdrawal-credentials-placeholder")}
/>
<Flex className="w-full flex-col gap-2 sm:w-fit sm:flex-row">
<Button
onClick={() => checkWithdrawalCredentials()}
disabled={!inputValue.length}
<ButtonLink
href={mainnetHref}
className={disabledClass}
aria-disabled={isDisabled || undefined}
tabIndex={isDisabled ? -1 : undefined}
>
{t("page-staking:comp-withdrawal-credentials-verify", {
network: "Mainnet",
})}
{isLoading.mainnet && <Spinner />}
</Button>
<Button
onClick={() => checkWithdrawalCredentials(true)}
disabled={!inputValue.length}
</ButtonLink>
<ButtonLink
href={testnetHref}
variant="outline"
className={disabledClass}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one is tricky for screen readers and tabbing because the link exists and the readers will announce them.

would recommend either conditionally render the href (pass href={inputValue ? mainnetHref : undefined}) or add aria-disabled="true" and tabIndex={-1} alongside the CSS classes.

aria-disabled={isDisabled || undefined}
tabIndex={isDisabled ? -1 : undefined}
>
{t("page-staking:comp-withdrawal-credentials-verify", {
network: CANONICAL_STAKING_TESTNET,
})}
{isLoading.testnet && <Spinner />}
</Button>
</ButtonLink>
</Flex>
</Flex>
{resultText}
</Flex>
)
}
Expand Down
19 changes: 17 additions & 2 deletions src/components/Staking/WithdrawalsTabComparison.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

import { trackCustomEvent } from "@/lib/utils/matomo"

import { Strong } from "../IntlStringElements"
import { ButtonLink } from "../ui/buttons/Button"
import InlineLink from "../ui/Link"

import { useTranslation } from "@/hooks/useTranslation"

Expand Down Expand Up @@ -51,8 +53,21 @@ const WithdrawalsTabComparison = () => {
<Translation id="page-staking:comp-withdrawal-comparison-current-li-2" />
</ListItem>
</UnorderedList>
<p className="font-bold">
<Translation id="page-staking:comp-withdrawal-comparison-current-p" />
<p>
{t.rich("page-staking.comp-withdrawal-comparison-current-p", {
strong: Strong,
// Intentionally kept in English to match Beaconcha.in destination
depositsTab: '"Deposits"',
withdrawalAddressLabel: '"Withdrawal Address"',
beaconchain: (chunks) => (
<InlineLink href="https://beaconcha.in">{chunks}</InlineLink>
),
prefix: (chunks) => (
<span className="font-mono font-bold text-warning-border dark:text-warning">
{chunks}
</span>
),
})}
</p>

<WithdrawalCredentials />
Expand Down
9 changes: 2 additions & 7 deletions src/intl/ar/page-staking.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
{
"comp-withdrawal-comparison-current-title": "المراهنون الحاليون",
"comp-withdrawal-comparison-current-li-1": "ربما قدم بعض المستخدمين عنوان سحب عند إعداد مبلغ إيداع مبدئي للتجميد، لا يحتاج هؤلاء المستخدمون إلى اتخاذ أي إجراء إضافي",
"comp-withdrawal-comparison-current-li-2": "لم يقدم معظم المراهنين عنوان سحب عند القيام بالإيداع المبدئي، وسيحتاجون إلى تحديث بيانات اعتماد السحب الخاصة بهم. تتضمن <a href=\"https://launchpad.ethereum.org/withdrawals\" target=\"_blank\" rel=\"noopener noreferrer\">منصة التشغيل الخاصة بالتحصيص</a> تعليمات بشأن كيفية إجراء ذلك",
"comp-withdrawal-comparison-current-p": "يمكنك إدخال رقم مؤشر برنامج المدقق الخاص بك هنا لتعرف إذا ما كنت بحاجة إلى تحديث بيانات اعتمادك أم لا <Text as=\"span\" fontWeight=\"normal\">(يمكن العثور على هذا في سجلات العميل الخاصة بك):</Text>",
"comp-withdrawal-comparison-current-li-2": "لم يقدم معظم المراهنين عنوان سحب عند القيام بالإيداع المبدئي، وسيحتاجون إلى تحديث بيانات اعتماد السحب الخاصة بهم. تتضمن <a href=\"https://launchpad.ethereum.org/withdrawals\" target=\"_blank\" rel=\"noopener noreferrer\">منصة التشغيل الخاصة بتجميد العملات</a> تعليمات بشأن كيفية إجراء ذلك",
"comp-withdrawal-comparison-current-p": "<strong>أدخل رقم فهرس المدقق الخاص بك أدناه لعرض تفاصيل المدقق الخاص بك على <beaconchain>Beaconcha.in</beaconchain>.</strong> يمكن العثور على عنوان السحب الخاص بك أسفل عنوان {withdrawalAddressLabel} في علامة التبويب {depositsTab}. تشير البادئة <prefix>0x00</prefix> إلى أن الحساب يحتاج إلى ترقية قبل تمكين عمليات السحب.",
"comp-withdrawal-comparison-new-title": "المراهنون الجدد (لم يتم إيداع أي مبالغ)",
"comp-withdrawal-comparison-new-li-1": "بشكل افتراضي، يجب على المراهنين الجدد الذين يتطلعون إلى تمكين مدفوعات المكافآت ووظائف السحب تلقائيًّا تقديم عنوان سحب في إيثريوم يتحكمون به عند إنشاء مفاتيح المدقق الخاص بهم باستخدام أداة واجهة خط الأوامر الخاص بإيداع مبالغ للتجميد",
"comp-withdrawal-comparison-new-li-2": "لا يلزم إجراء ذلك في وقت الإيداع، ولكن سيمنع الحاجة إلى تحديث هذه المفاتيح في وقت لاحق للحصول على أموالك",
"comp-withdrawal-comparison-new-p": "ستوجهك منصة التشغيل الخاصة بالتحصيص من خلال عملية التأهيل لالتحصيص.",
"comp-withdrawal-comparison-new-link": "تفضل بزيارة منصة التشغيل الخاصة بالتحصيص",
"comp-withdrawal-credentials-placeholder": "مؤشر برنامج المدقق",
"comp-withdrawal-credentials-error": "عذرًا! تحقّق مرة أخرى من رقم مؤشر برنامج المدقق وحاول مرة أخرى.",
"comp-withdrawal-credentials-upgraded-1": "مؤشر التحقق {validatorIndex} جاهز لبدء تلقي المكافآت!",
"comp-withdrawal-credentials-upgraded-2": "بيانات اعتماد السحب المرتبطة بعناوين التنفيذ:",
"comp-withdrawal-credentials-not-upgraded-1": "يحتاج مدقق {network} هذا إلى الترقية.",
"comp-withdrawal-credentials-not-upgraded-2": "يمكن العثور على التعليمات حول كيفية الترقية حاليًّا في <a href=\"https://launchpad.ethereum.org/withdrawals\" target=\"_blank\" rel=\"noopener noreferrer\">منصة التشغيل الخاصة بالتحصيص</a>",
"comp-withdrawal-credentials-verify": "التحقق على {network}",
"page-staking-withdrawals-when": "أصبح متاحًا!",
"page-staking-image-alt": "صورة جالب حظ وحيد القرن لمنصة التشغيل الخاصة بالتحصيص.",
Expand Down
7 changes: 1 addition & 6 deletions src/intl/bn/page-staking.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@
"comp-withdrawal-comparison-current-title": "বর্তমান স্টেকার",
"comp-withdrawal-comparison-current-li-1": "কিছু ব্যবহারকারী তাদের স্টেকিং ডিপোজিট সেট আপ করার সময় একটি উত্তোলনের এডড্রেস প্রদান করে থাকতে পারেন—এই ব্যবহারকারীদের আর কিছু করার প্রয়োজন নেই",
"comp-withdrawal-comparison-current-li-2": "অধিকাংশ স্টেকার প্রাথমিক ডিপোজিটের সময় উত্তোলনের এডড্রেস প্রদান করেননি, এবং তাদের উত্তোলনের ক্রেডেনশিয়াল আপডেট করতে হবে। <a href=\"https://launchpad.ethereum.org/withdrawals\" target=\"_blank\" rel=\"noopener noreferrer\">Staking Launchpad</a>-এ এটি কীভাবে করতে হবে তার নির্দেশিকা রয়েছে",
"comp-withdrawal-comparison-current-p": "আপনার ক্রেডেনশিয়াল এখনও আপডেট করার প্রয়োজন আছে কিনা তা দেখতে আপনি এখানে আপনার ভ্যালিডেটর ইনডেক্স নম্বর লিখতে পারেন <Text as=\"span\" fontWeight=\"normal\">(এটি আপনার ক্লায়েন্ট লগে পাওয়া যেতে পারে):</Text>",
"comp-withdrawal-comparison-current-p": "<strong><beaconchain>Beaconcha.in</beaconchain>-এ আপনার ভ্যালিডেটরের বিশদ বিবরণ দেখতে নিচে আপনার ভ্যালিডেটর ইনডেক্স নম্বর লিখুন।</strong> আপনার তোলার ঠিকানা {depositsTab} ট্যাবে {withdrawalAddressLabel} হেডারের নিচে পাওয়া যাবে। একটি <prefix>0x00</prefix> প্রিফিক্স নির্দেশ করে যে টাকা তোলার সুবিধা চালু করার আগে অ্যাকাউন্টটি আপগ্রেড করা প্রয়োজন।",
"comp-withdrawal-comparison-new-title": "নতুন স্টেকার (এখনও ডিপোজিট করেননি)",
"comp-withdrawal-comparison-new-li-1": "ডিফল্টরূপে, নতুন স্টেকার যারা স্বয়ংক্রিয়ভাবে রিওয়ার্ড পেমেন্ট এবং উত্তোলনের কার্যকারিতা সক্ষম করতে চান তাদের Staking Deposit CLI টুল ব্যবহার করে তাদের ভ্যালিডেটর কি তৈরি করার সময় তাদের নিয়ন্ত্রিত একটি Ethereum উত্তোলনের এডড্রেস প্রদান করা উচিত",
"comp-withdrawal-comparison-new-li-2": "ডিপোজিটের সময় এটি প্রয়োজনীয় নয়, তবে আপনার ফান্ড আনলক করার জন্য পরবর্তী তারিখে এই কিগুলো আপডেট করার প্রয়োজনীয়তা রোধ করবে",
"comp-withdrawal-comparison-new-p": "Staking Launchpad আপনাকে স্টেকিং অনবোর্ডিংয়ের মাধ্যমে গাইড করবে।",
"comp-withdrawal-comparison-new-link": "Staking Launchpad ভিজিট করুন",
"comp-withdrawal-credentials-placeholder": "ভ্যালিডেটর ইনডেক্স",
"comp-withdrawal-credentials-error": "উফ! ভ্যালিডেটর ইনডেক্স নম্বরটি দুবার চেক করুন এবং আবার চেষ্টা করুন।",
"comp-withdrawal-credentials-upgraded-1": "ভ্যালিডেটর ইনডেক্স {validatorIndex} রিওয়ার্ড পেতে শুরু করার জন্য প্রস্তুত!",
"comp-withdrawal-credentials-upgraded-2": "উত্তোলনের ক্রেডেনশিয়াল এক্সিকিউশন এডড্রেস এর সাথে লিঙ্ক করা হয়েছে:",
"comp-withdrawal-credentials-not-upgraded-1": "এই {network} ভ্যালিডেটর আপগ্রেড করা প্রয়োজন।",
"comp-withdrawal-credentials-not-upgraded-2": "কীভাবে আপগ্রেড করতে হবে তার নির্দেশিকা বর্তমানে <a href=\"https://launchpad.ethereum.org/withdrawals\" target=\"_blank\" rel=\"noopener noreferrer\">Staking Launchpad</a>-এ পাওয়া যাবে",
"comp-withdrawal-credentials-verify": "{network}-এ যাচাই করুন",
"page-staking-withdrawals-when": "শিপড!",
"page-staking-image-alt": "স্টেকিং লঞ্চপ্যাডের জন্য রাইনো মাসকটের ছবি।",
Expand Down
Loading
Loading