diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelSummary.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelSummary.tsx index 0a5200018c..a26be83a8b 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelSummary.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelSummary.tsx @@ -1,4 +1,5 @@ import React, { useMemo } from 'react' +import { InformationCircleIcon } from '@heroicons/react/24/outline' import { twMerge } from 'tailwind-merge' import { formatAmount } from '../../util/NumberUtils' @@ -13,10 +14,12 @@ import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' import { NativeCurrencyPrice, useIsBridgingEth } from './NativeCurrencyPrice' import { useAppState } from '../../state' import { Loader } from '../common/atoms/Loader' +import { Tooltip } from '../common/Tooltip' import { isTokenNativeUSDC } from '../../util/TokenUtils' import { NoteBox } from '../common/NoteBox' import { DISABLED_CHAIN_IDS } from './useTransferReadiness' import { useIsBatchTransferSupported } from '../../hooks/TransferPanel/useIsBatchTransferSupported' +import { getConfirmationTime } from '../../util/WithdrawalUtils' export type TransferPanelSummaryToken = { symbol: string @@ -259,6 +262,47 @@ export function TransferPanelSummary({ token }: TransferPanelSummaryProps) { )} + {!isDepositMode && + (isDestinationChainArbitrumOne || + isDestinationChainArbitrumSepolia) && ( +
+ +
+ )} ) } + +function ConfirmationTimeInfo({ chainId }: { chainId: number }) { + const { + confirmationTimeInReadableFormat, + confirmationTimeInReadableFormatShort, + isDefaultConfirmationTime + } = getConfirmationTime(chainId) + return ( + <> + Confirmation time: + + + {confirmationTimeInReadableFormat} + + + {confirmationTimeInReadableFormatShort} + + {!isDefaultConfirmationTime && ( + + + + )} + + + ) +} diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/WithdrawalConfirmationDialog.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/WithdrawalConfirmationDialog.tsx index 5b57633497..eda5f9edda 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/WithdrawalConfirmationDialog.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/WithdrawalConfirmationDialog.tsx @@ -12,12 +12,16 @@ import { useAppState } from '../../state' import { trackEvent } from '../../util/AnalyticsUtils' import { getNetworkName, isNetwork } from '../../util/networks' import { getFastBridges } from '../../util/fastBridges' -import { CONFIRMATION_PERIOD_ARTICLE_LINK } from '../../constants' +import { + CONFIRMATION_PERIOD_ARTICLE_LINK, + FAST_WITHDRAWAL_DOCS_ARTICLE_LINK +} from '../../constants' import { useNativeCurrency } from '../../hooks/useNativeCurrency' import { useNetworks } from '../../hooks/useNetworks' import { useNetworksRelationship } from '../../hooks/useNetworksRelationship' import { SecurityGuaranteed, SecurityNotGuaranteed } from './SecurityLabels' import { getWithdrawalConfirmationDate } from '../../hooks/useTransferDuration' +import { getConfirmationTime } from '../../util/WithdrawalUtils' function getCalendarUrl( withdrawalDate: dayjs.Dayjs, @@ -42,6 +46,8 @@ export function WithdrawalConfirmationDialog( const { childChain, childChainProvider, parentChain } = useNetworksRelationship(networks) + const { fastWithdrawalActive } = getConfirmationTime(childChain.id) + const [selectedIndex, setSelectedIndex] = useState(0) const destinationNetworkName = getNetworkName(parentChain.id) @@ -63,9 +69,14 @@ export function WithdrawalConfirmationDialog( const [checkbox1Checked, setCheckbox1Checked] = useState(false) const [checkbox2Checked, setCheckbox2Checked] = useState(false) + const [checkbox3Checked, setCheckbox3Checked] = useState(false) const { isArbitrumOne } = isNetwork(childChain.id) - const bothCheckboxesChecked = checkbox1Checked && checkbox2Checked + + const allCheckboxesChecked = + checkbox1Checked && + checkbox2Checked && + (fastWithdrawalActive ? checkbox3Checked : true) const estimatedConfirmationDate = getWithdrawalConfirmationDate({ createdAt: null, @@ -81,6 +92,7 @@ export function WithdrawalConfirmationDialog( setCheckbox1Checked(false) setCheckbox2Checked(false) + setCheckbox3Checked(false) setSelectedIndex(0) } @@ -91,7 +103,7 @@ export function WithdrawalConfirmationDialog( className="max-w-[700px]" title={`Move funds to ${destinationNetworkName}`} actionButtonProps={{ - disabled: !bothCheckboxesChecked, + disabled: !allCheckboxesChecked, hidden: isFastBridgesTab }} > @@ -157,6 +169,29 @@ export function WithdrawalConfirmationDialog( onChange={setCheckbox2Checked} /> + {fastWithdrawalActive && ( + + I understand that ~{confirmationPeriod} is an estimate, + and it's possible the committee fails and it will + default back to the 8 days.{' '} + { + e.stopPropagation() + }} + > + Learn more. + + + } + checked={checkbox3Checked} + onChange={setCheckbox3Checked} + /> + )} +
diff --git a/packages/arb-token-bridge-ui/src/constants.ts b/packages/arb-token-bridge-ui/src/constants.ts index 2e62500b05..85b03a5336 100644 --- a/packages/arb-token-bridge-ui/src/constants.ts +++ b/packages/arb-token-bridge-ui/src/constants.ts @@ -20,6 +20,8 @@ export const ETH_BALANCE_ARTICLE_LINK = `${SUPPORT_LINK_BASE}/hc/en-us/articles/ export const CONFIRMATION_PERIOD_ARTICLE_LINK = `${SUPPORT_LINK_BASE}/hc/en-us/articles/18213843096091` +export const FAST_WITHDRAWAL_DOCS_ARTICLE_LINK = `${DOCS_DOMAIN}/run-arbitrum-node/arbos-releases/arbos31#additional-requirement-for-arbitrum-orbit-chains-who-wish-to-enable-fast-withdrawals` + export const ORBIT_QUICKSTART_LINK = 'https://docs.arbitrum.io/launch-orbit-chain/orbit-quickstart' diff --git a/packages/arb-token-bridge-ui/src/hooks/useTransferDuration.ts b/packages/arb-token-bridge-ui/src/hooks/useTransferDuration.ts index 771454a252..f8671e23e2 100644 --- a/packages/arb-token-bridge-ui/src/hooks/useTransferDuration.ts +++ b/packages/arb-token-bridge-ui/src/hooks/useTransferDuration.ts @@ -9,6 +9,7 @@ import { getL1BlockTime, isNetwork } from '../util/networks' +import { getConfirmationTime } from '../util/WithdrawalUtils' const DEPOSIT_TIME_MINUTES = { mainnet: 15, @@ -121,6 +122,12 @@ export function getWithdrawalConfirmationDate({ // For new txs createdAt won't be defined yet, we default to the current time in that case const createdAtDate = createdAt ? dayjs(createdAt) : dayjs() + const { confirmationTimeInSeconds, fastWithdrawalActive } = + getConfirmationTime(withdrawalFromChainId) + if (fastWithdrawalActive && confirmationTimeInSeconds) { + return createdAtDate.add(confirmationTimeInSeconds, 'second') + } + const blockNumberReferenceChainId = getBlockNumberReferenceChainIdByChainId({ chainId: withdrawalFromChainId }) diff --git a/packages/arb-token-bridge-ui/src/util/WithdrawalUtils.ts b/packages/arb-token-bridge-ui/src/util/WithdrawalUtils.ts index 2bf9334593..fe6f091928 100644 --- a/packages/arb-token-bridge-ui/src/util/WithdrawalUtils.ts +++ b/packages/arb-token-bridge-ui/src/util/WithdrawalUtils.ts @@ -9,6 +9,8 @@ import { BigNumber } from 'ethers' import { GasEstimates } from '../hooks/arbTokenBridge.types' import { Address } from './AddressUtils' import { captureSentryErrorWithExtraData } from './SentryUtils' +import { getBridgeUiConfigForChain } from './bridgeUiConfig' +import { isNetwork } from './networks' export async function withdrawInitTxEstimateGas({ amount, @@ -105,3 +107,69 @@ export async function withdrawInitTxEstimateGas({ } } } + +const SECONDS_IN_MINUTE = 60 +const SECONDS_IN_HOUR = 3600 +const SECONDS_IN_DAY = 86400 +const DEFAULT_CONFIRMATION_TIME = 7 * SECONDS_IN_DAY +const DEFAULT_FAST_WITHDRAWAL_TIME = SECONDS_IN_DAY +const DEFAULT_TESTNET_CONFIRMATION_TIME = SECONDS_IN_HOUR + +function formatDuration(seconds: number, short = false): string { + if (seconds < SECONDS_IN_MINUTE) { + return `${seconds} ${short ? 'secs' : 'seconds'}` + } + if (seconds < SECONDS_IN_HOUR) { + return `${Math.round(seconds / SECONDS_IN_MINUTE)} ${ + short ? 'mins' : 'minutes' + }` + } + if (seconds < SECONDS_IN_DAY) { + return `${Math.round(seconds / SECONDS_IN_HOUR)} hours` + } + return `${Math.round(seconds / SECONDS_IN_DAY)} days` +} + +/** + * Calculate confirmation time for bridge transactions. + * @param {number} chainId - The ID of the parent chain. + */ +export function getConfirmationTime(chainId: number) { + const { fastWithdrawalTime, fastWithdrawalActive } = + getBridgeUiConfigForChain(chainId) + const isTestnet = isNetwork(chainId).isTestnet + + const isDefaultConfirmationTime = !fastWithdrawalActive + const isDefaultFastWithdrawal = fastWithdrawalActive && !fastWithdrawalTime + const isCustomFastWithdrawal = fastWithdrawalActive && !!fastWithdrawalTime + + let confirmationTimeInSeconds: number + + if (isDefaultFastWithdrawal) { + confirmationTimeInSeconds = DEFAULT_FAST_WITHDRAWAL_TIME + } else if (isCustomFastWithdrawal) { + confirmationTimeInSeconds = fastWithdrawalTime / 1000 + } else { + confirmationTimeInSeconds = isTestnet + ? DEFAULT_TESTNET_CONFIRMATION_TIME + : DEFAULT_CONFIRMATION_TIME + } + + const confirmationTimeInReadableFormat = formatDuration( + confirmationTimeInSeconds + ) + const confirmationTimeInReadableFormatShort = formatDuration( + confirmationTimeInSeconds, + true + ) + + return { + fastWithdrawalActive, + isDefaultConfirmationTime, + isDefaultFastWithdrawal, + isCustomFastWithdrawal, + confirmationTimeInSeconds, + confirmationTimeInReadableFormat, + confirmationTimeInReadableFormatShort + } +} diff --git a/packages/arb-token-bridge-ui/src/util/orbitChainsData.json b/packages/arb-token-bridge-ui/src/util/orbitChainsData.json index 36738bab09..0c614f96ac 100644 --- a/packages/arb-token-bridge-ui/src/util/orbitChainsData.json +++ b/packages/arb-token-bridge-ui/src/util/orbitChainsData.json @@ -768,7 +768,9 @@ "symbol": "CHEESE", "decimals": 18, "logoUrl": "/images/CheeseChain_NativeTokenLogo.jpg" - } + }, + "fastWithdrawalTime": 900000, + "fastWithdrawalActive": true } }, { diff --git a/packages/arb-token-bridge-ui/src/util/orbitChainsList.ts b/packages/arb-token-bridge-ui/src/util/orbitChainsList.ts index 03602d9495..5888a68167 100644 --- a/packages/arb-token-bridge-ui/src/util/orbitChainsList.ts +++ b/packages/arb-token-bridge-ui/src/util/orbitChainsList.ts @@ -17,6 +17,8 @@ export type BridgeUiConfig = { description?: string } nativeTokenData?: NativeCurrencyBase + fastWithdrawalTime?: number + fastWithdrawalActive?: boolean } export type OrbitChainConfig = ChainWithRpcUrl & {