From 775940fb76a642cf580701def91dc2193d3ad4b2 Mon Sep 17 00:00:00 2001 From: dewanshparashar Date: Fri, 10 Oct 2025 17:03:25 +0400 Subject: [PATCH 1/9] feat: deprecate teleport transfers --- .../ISSUE_TEMPLATE/add-layerleap-request.yml | 76 ------- .../TransferPanel/TransferDisabledDialog.tsx | 110 +++------- .../TransferPanel/TransferPanel.tsx | 7 - .../hooks/useIsCanonicalTransfer.ts | 7 - .../TransferPanel/useTransferReadiness.ts | 19 +- .../useTransferReadinessUtils.ts | 4 - .../src/hooks/useNetworksRelationship.ts | 8 +- .../BridgeTransferStarterFactory.ts | 10 - .../token-bridge-sdk/Erc20TeleportStarter.ts | 188 ------------------ .../token-bridge-sdk/EthTeleportStarter.ts | 132 ------------ .../src/token-bridge-sdk/teleport.ts | 9 +- .../src/token-bridge-sdk/utils.ts | 26 +-- .../src/util/TokenTeleportEnabledUtils.ts | 52 ----- .../src/util/TokenUtils.ts | 14 +- .../arb-token-bridge-ui/src/util/networks.ts | 10 +- 15 files changed, 41 insertions(+), 631 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/add-layerleap-request.yml delete mode 100644 packages/arb-token-bridge-ui/src/token-bridge-sdk/Erc20TeleportStarter.ts delete mode 100644 packages/arb-token-bridge-ui/src/token-bridge-sdk/EthTeleportStarter.ts delete mode 100644 packages/arb-token-bridge-ui/src/util/TokenTeleportEnabledUtils.ts diff --git a/.github/ISSUE_TEMPLATE/add-layerleap-request.yml b/.github/ISSUE_TEMPLATE/add-layerleap-request.yml deleted file mode 100644 index dd9917810..000000000 --- a/.github/ISSUE_TEMPLATE/add-layerleap-request.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: Add Layer Leap Request -description: File a request to have your Orbit chain support Layer Leap transfers -title: '[feat]: enable Layer Leap for ' -labels: ['Type: Add LayerLeap'] -body: - - type: markdown - attributes: - value: | - Please provide the necessary config information for the Orbit chain. - - type: input - id: chain-id - attributes: - label: Chain ID - placeholder: Your Orbit Chain ID - validations: - required: true - - type: input - id: name - attributes: - label: Chain name - placeholder: Your Orbit Chain name - validations: - required: true - - - type: markdown - attributes: - value: | - Native Token Information - Please note that Layer Leap does not yet support custom gas token chains. We still encourage you to fill the form out to be part of our early release for the next Layer Leap version which will support custom gas token chains. - - type: input - id: native-token-address - attributes: - label: Native token address - placeholder: eg. 0x0000000000000000000000000000000000000000 - validations: - required: false - - type: input - id: native-token-name - attributes: - label: Native token name - placeholder: eg. Ether - validations: - required: false - - type: input - id: native-token-symbol - attributes: - label: Native token symbol - placeholder: eg. ETH - validations: - required: false - - - type: markdown - attributes: - value: | - Information for enabling Layer Leap transfers for your Orbit Chain - - type: checkboxes - attributes: - label: Enable Layer Leap - options: - - label: We would like to adopt Layer Leap on bridge.arbitrum.io - required: true - - type: input - id: layerleap-token-symbol - attributes: - description: ERC20 tokens listed here will be added to an allowlist for L1-to-L3 ERC20 transfers - label: Token symbol(s) to allow Layer Leap for (Comma-separated, if multiple) - placeholder: eg. WETH, LINK, etc. - validations: - required: true - - type: input - id: layerleap-token-addresses - attributes: - description: ERC20 addresses (L1) listed here will be added to an allowlist for L1-to-L3 ERC20 transfers (should correspond to the symbols above) - label: L1 token address(es) to allow Layer Leap for (Comma-separated, if multiple) - placeholder: eg. 0xfff9976782d46cc05630d1f6ebab18b2324d6b14, 0x779877A7B0D9E8603169DdbD7836e478b4624789 - validations: - required: true diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferDisabledDialog.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferDisabledDialog.tsx index 55f1cf3f9..c7beb3104 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferDisabledDialog.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferDisabledDialog.tsx @@ -5,16 +5,13 @@ import { ERC20BridgeToken } from '../../hooks/arbTokenBridge.types'; import { useNetworks } from '../../hooks/useNetworks'; import { useNetworksRelationship } from '../../hooks/useNetworksRelationship'; import { useSelectedToken } from '../../hooks/useSelectedToken'; -import { getL2ConfigForTeleport } from '../../token-bridge-sdk/teleport'; import { ChainId } from '../../types/ChainId'; import { addressesEqual } from '../../util/AddressUtils'; import { CommonAddress } from '../../util/CommonAddressUtils'; -import { isTeleportEnabledToken } from '../../util/TokenTeleportEnabledUtils'; import { isTransferDisabledToken } from '../../util/TokenTransferDisabledUtils'; import { sanitizeTokenSymbol } from '../../util/TokenUtils'; import { withdrawOnlyTokens } from '../../util/WithdrawOnlyUtils'; import { isLifiEnabled } from '../../util/featureFlag'; -import { getNetworkName } from '../../util/networks'; import { Dialog } from '../common/Dialog'; import { ExternalLink } from '../common/ExternalLink'; import { useSelectedTokenIsWithdrawOnly } from './hooks/useSelectedTokenIsWithdrawOnly'; @@ -22,7 +19,6 @@ import { useSelectedTokenIsWithdrawOnly } from './hooks/useSelectedTokenIsWithdr export function isDisabledCanonicalTransfer({ selectedToken, isDepositMode, - isTeleportMode, parentChainId, childChainId, isSelectedTokenWithdrawOnly, @@ -30,7 +26,6 @@ export function isDisabledCanonicalTransfer({ }: { selectedToken: ERC20BridgeToken | null; isDepositMode: boolean; - isTeleportMode: boolean; parentChainId: ChainId; childChainId: ChainId; isSelectedTokenWithdrawOnly: boolean | undefined; @@ -44,13 +39,6 @@ export function isDisabledCanonicalTransfer({ return true; } - if ( - isTeleportMode && - !isTeleportEnabledToken(selectedToken.address, parentChainId, childChainId) - ) { - return true; - } - if (parentChainId === ChainId.ArbitrumOne) { if ( childChainId === ChainId.ApeChain && @@ -77,8 +65,7 @@ export function isDisabledCanonicalTransfer({ export function TransferDisabledDialog() { const [networks] = useNetworks(); - const { isDepositMode, isTeleportMode, parentChain, childChain } = - useNetworksRelationship(networks); + const { isDepositMode, parentChain, childChain } = useNetworksRelationship(networks); const [selectedToken, setSelectedToken] = useSelectedToken(); // for tracking local state and prevent flickering with async URL params updating const [selectedTokenAddressLocalValue, setSelectedTokenAddressLocalValue] = useState< @@ -90,20 +77,6 @@ export function TransferDisabledDialog() { erc20L1Address: selectedToken?.address, chainId: networks.sourceChain.id, }); - const [l2ChainIdForTeleport, setL2ChainIdForTeleport] = useState(); - - useEffect(() => { - const updateL2ChainIdForTeleport = async () => { - if (!isTeleportMode) { - return; - } - const { l2ChainId } = await getL2ConfigForTeleport({ - destinationChainProvider: networks.destinationChainProvider, - }); - setL2ChainIdForTeleport(l2ChainId); - }; - updateL2ChainIdForTeleport(); - }, [isTeleportMode, networks.destinationChainProvider]); const shouldShowDialog = useMemo(() => { if ( @@ -128,7 +101,6 @@ export function TransferDisabledDialog() { return isDisabledCanonicalTransfer({ selectedToken, isDepositMode, - isTeleportMode, parentChainId: parentChain.id, childChainId: childChain.id, isSelectedTokenWithdrawOnly, @@ -139,18 +111,13 @@ export function TransferDisabledDialog() { isDepositMode, isSelectedTokenWithdrawOnly, isSelectedTokenWithdrawOnlyLoading, - isTeleportMode, parentChain.id, selectedToken, selectedTokenAddressLocalValue, + networks.destinationChain.id, + networks.sourceChain.id, ]); - const sourceChainName = getNetworkName(networks.sourceChain.id); - const destinationChainName = getNetworkName(networks.destinationChain.id); - const l2ChainIdForTeleportName = l2ChainIdForTeleport - ? getNetworkName(l2ChainIdForTeleport) - : null; - const isGHO = selectedToken && networks.destinationChain.id === ChainId.ArbitrumOne && @@ -185,58 +152,27 @@ export function TransferDisabledDialog() { onClose={onClose} >
- {isTeleportMode ? ( - // teleport transfer disabled content if token is not in the allowlist - <> -

- Unfortunately, {unsupportedToken} is not yet - supported for direct {sourceChainName} to {destinationChainName} transfers. -

- {l2ChainIdForTeleportName && ( -

- To bridge {unsupportedToken}: -

  • - First bridge from {sourceChainName} to {l2ChainIdForTeleportName}. -
  • -
  • - Then bridge from {l2ChainIdForTeleportName} to {destinationChainName}. -
  • -

    - )} -

    - For more information please contact us on{' '} - - Discord - {' '} - and reach out in #support for assistance. -

    - - ) : ( - // canonical transfer disabled content for all other cases - <> -

    - Unfortunately, {unsupportedToken} has a custom - bridge solution that is incompatible with the canonical Arbitrum bridge. -

    - {isGHO && ( -

    - Please use the{' '} - - CCIP bridge for GHO - {' '} - instead. -

    - )} -

    - For more information please contact{' '} - {unsupportedToken} - 's developer team directly or explore their docs. -

    - +

    + Unfortunately, {unsupportedToken} has a custom bridge + solution that is incompatible with the canonical Arbitrum bridge. +

    + {isGHO && ( +

    + Please use the{' '} + + CCIP bridge for GHO + {' '} + instead. +

    )} +

    + For more information please contact{' '} + {unsupportedToken} + 's developer team directly or explore their docs. +

    ); diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx index 1f990f0df..152c2b8aa 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx @@ -85,7 +85,6 @@ import { useDestinationAddressError } from './hooks/useDestinationAddressError'; import { useIsTransferAllowed } from './hooks/useIsTransferAllowed'; import { isLifiRoute, useRouteStore } from './hooks/useRouteStore'; import { getAmountToPay } from './useTransferReadiness'; -import { getSmartContractWalletTeleportTransfersNotSupportedErrorMessage } from './useTransferReadinessUtils'; const signerUndefinedError = 'Signer is undefined'; const transferNotAllowedError = 'Transfer not allowed'; @@ -849,12 +848,6 @@ export function TransferPanel() { throw new Error(signerUndefinedError); } - // SC Teleport transfers aren't enabled yet. Safety check, shouldn't be able to get here. - if (isSmartContractWallet && isTeleportMode) { - console.error(getSmartContractWalletTeleportTransfersNotSupportedErrorMessage()); - return; - } - const childChainName = getNetworkName(childChain.id); setTransferring(true); diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useIsCanonicalTransfer.ts b/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useIsCanonicalTransfer.ts index d3b62b13e..c21629938 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useIsCanonicalTransfer.ts +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useIsCanonicalTransfer.ts @@ -1,5 +1,3 @@ -import { isValidTeleportChainPair } from '@/token-bridge-sdk/teleport'; - import { ERC20BridgeToken } from '../../../hooks/arbTokenBridge.types'; import { useNetworks } from '../../../hooks/useNetworks'; import { useNetworksRelationship } from '../../../hooks/useNetworksRelationship'; @@ -27,10 +25,6 @@ export function isArbitrumCanonicalTransfer({ selectedToken: ERC20BridgeToken | null; }): boolean { const isDeposit = isDepositMode({ sourceChainId, destinationChainId }); - const isTeleportMode = isValidTeleportChainPair({ - destinationChainId, - sourceChainId, - }); const isValidPair = getDestinationChainIds(sourceChainId).includes(destinationChainId); if (!isValidPair) { @@ -43,7 +37,6 @@ export function isArbitrumCanonicalTransfer({ isDepositMode: isDeposit, isSelectedTokenWithdrawOnly, isSelectedTokenWithdrawOnlyLoading, - isTeleportMode, parentChainId: parentChainId, selectedToken, }) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/useTransferReadiness.ts b/packages/arb-token-bridge-ui/src/components/TransferPanel/useTransferReadiness.ts index 180a49f94..f0fff7ad5 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/useTransferReadiness.ts +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/useTransferReadiness.ts @@ -16,7 +16,6 @@ import { useNetworks } from '../../hooks/useNetworks'; import { useNetworksRelationship } from '../../hooks/useNetworksRelationship'; import { useSelectedToken } from '../../hooks/useSelectedToken'; import { formatAmount } from '../../util/NumberUtils'; -import { isTeleportEnabledToken } from '../../util/TokenTeleportEnabledUtils'; import { isTransferDisabledToken } from '../../util/TokenTransferDisabledUtils'; import { isTokenArbitrumOneNativeUSDC, @@ -32,7 +31,6 @@ import { TransferReadinessRichErrorMessage, getInsufficientFundsErrorMessage, getInsufficientFundsForGasFeesErrorMessage, - getSmartContractWalletTeleportTransfersNotSupportedErrorMessage, getWithdrawOnlyChainErrorMessage, } from './useTransferReadinessUtils'; @@ -202,7 +200,7 @@ export function useTransferReadiness(): UseTransferReadinessResult { layout: { isTransferring }, } = useAppContextState(); const [networks] = useNetworks(); - const { childChain, childChainProvider, parentChain, isDepositMode, isTeleportMode } = + const { childChain, childChainProvider, parentChain, isDepositMode } = useNetworksRelationship(networks); const { selectedRoute, selectedRouteContext } = useRouteStore( (state) => ({ @@ -345,15 +343,6 @@ export function useTransferReadiness(): UseTransferReadinessResult { }); } - // teleport transfers using SC wallets not enabled yet - if (isSmartContractWallet && isTeleportMode) { - return notReady({ - errorMessages: { - inputAmount1: getSmartContractWalletTeleportTransfersNotSupportedErrorMessage(), - }, - }); - } - // Check if destination address is valid for ERC20 transfers if (destinationAddressError) { return notReady(); @@ -361,10 +350,7 @@ export function useTransferReadiness(): UseTransferReadinessResult { // ERC-20 if (selectedToken) { - const selectedTokenIsDisabled = - isTransferDisabledToken(selectedToken.address, childChain.id) || - (isTeleportMode && - !isTeleportEnabledToken(selectedToken.address, parentChain.id, childChain.id)); + const selectedTokenIsDisabled = isTransferDisabledToken(selectedToken.address, childChain.id); const isValidLifiRoute = isLifiEnabled() && isValidLifiTransfer({ @@ -702,7 +688,6 @@ export function useTransferReadiness(): UseTransferReadinessResult { childChain.id, parentChain.id, networks.sourceChain.name, - isTeleportMode, isSelectedTokenWithdrawOnly, isSelectedTokenWithdrawOnlyLoading, childChain.name, diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/useTransferReadinessUtils.ts b/packages/arb-token-bridge-ui/src/components/TransferPanel/useTransferReadinessUtils.ts index 5adef3f44..6f695e32b 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/useTransferReadinessUtils.ts +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/useTransferReadinessUtils.ts @@ -40,10 +40,6 @@ export function getInsufficientFundsForGasFeesErrorMessage({ ); } -export function getSmartContractWalletTeleportTransfersNotSupportedErrorMessage() { - return `LayerLeap transfers using smart contract wallets aren't supported yet.`; -} - export function getWithdrawOnlyChainErrorMessage(chainName: string) { return `${chainName} has currently suspended deposits. You can only withdraw assets from this chain.`; } diff --git a/packages/arb-token-bridge-ui/src/hooks/useNetworksRelationship.ts b/packages/arb-token-bridge-ui/src/hooks/useNetworksRelationship.ts index 1d1025fd8..f5725b62a 100644 --- a/packages/arb-token-bridge-ui/src/hooks/useNetworksRelationship.ts +++ b/packages/arb-token-bridge-ui/src/hooks/useNetworksRelationship.ts @@ -2,8 +2,6 @@ import { StaticJsonRpcProvider } from '@ethersproject/providers'; import { useMemo } from 'react'; import { Chain } from 'wagmi/chains'; -import { isValidTeleportChainPair } from '@/token-bridge-sdk/teleport'; - import { isLifiTransfer } from '../app/api/crosschain-transfers/utils'; import { ChainId } from '../types/ChainId'; import { isDepositMode } from '../util/isDepositMode'; @@ -31,11 +29,7 @@ export function useNetworksRelationship({ destinationChainId: destinationChain.id, }); - const isTeleportMode = isValidTeleportChainPair({ - sourceChainId: sourceChain.id, - destinationChainId: destinationChain.id, - }); - + const isTeleportMode = false; const isLifi = isLifiTransfer({ sourceChainId: sourceChain.id, destinationChainId: destinationChain.id, diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/BridgeTransferStarterFactory.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/BridgeTransferStarterFactory.ts index b9716c884..0aa714a5f 100644 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/BridgeTransferStarterFactory.ts +++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/BridgeTransferStarterFactory.ts @@ -3,10 +3,8 @@ import { BridgeTransferStarterPropsWithChainIds, } from './BridgeTransferStarter'; import { Erc20DepositStarter } from './Erc20DepositStarter'; -import { Erc20TeleportStarter } from './Erc20TeleportStarter'; import { Erc20WithdrawalStarter } from './Erc20WithdrawalStarter'; import { EthDepositStarter } from './EthDepositStarter'; -import { EthTeleportStarter } from './EthTeleportStarter'; import { EthWithdrawalStarter } from './EthWithdrawalStarter'; import { LifiTransferStarter } from './LifiTransferStarter'; import { OftV2TransferStarter } from './OftV2TransferStarter'; @@ -55,7 +53,6 @@ export class BridgeTransferStarterFactory { isDeposit: isCanonicalDeposit, isNativeCurrencyTransfer, isSupported, - isTeleport, isWithdrawal: isCanonicalWithdrawal, } = getBridgeTransferProperties(props); @@ -87,13 +84,6 @@ export class BridgeTransferStarterFactory { return withCache(cacheKey, new OftV2TransferStarter(initProps)); } - if (isTeleport) { - if (isNativeCurrencyTransfer) { - return withCache(cacheKey, new EthTeleportStarter(initProps)); - } - return withCache(cacheKey, new Erc20TeleportStarter(initProps)); - } - if (isCanonicalDeposit) { if (!isNativeCurrencyTransfer) { return withCache(cacheKey, new Erc20DepositStarter(initProps)); diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/Erc20TeleportStarter.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/Erc20TeleportStarter.ts deleted file mode 100644 index 3adf1d925..000000000 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/Erc20TeleportStarter.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { Erc20L1L3Bridger, getArbitrumNetwork } from '@arbitrum/sdk'; -import { ERC20__factory } from '@arbitrum/sdk/dist/lib/abi/factories/ERC20__factory'; -import { StaticJsonRpcProvider } from '@ethersproject/providers'; -import { BigNumber, constants } from 'ethers'; - -import { fetchErc20Allowance } from '../util/TokenUtils'; -import { - ApproveTokenProps, - BridgeTransferStarter, - BridgeTransferStarterProps, - RequiresTokenApprovalProps, - TransferEstimateGasProps, - TransferProps, - TransferType, -} from './BridgeTransferStarter'; -import { getL2ConfigForTeleport } from './teleport'; -import { getAddressFromSigner, percentIncrease } from './utils'; - -export class Erc20TeleportStarter extends BridgeTransferStarter { - public transferType: TransferType = 'erc20_teleport'; - - private l1l3Bridger: Erc20L1L3Bridger | undefined; - private l2Provider: StaticJsonRpcProvider | undefined; - - constructor(props: BridgeTransferStarterProps) { - super(props); - - if (!this.sourceChainErc20Address) { - throw Error('Erc20 token address not found'); - } - } - - private async getBridger() { - if (this.l1l3Bridger) { - return this.l1l3Bridger; - } - - const l3Network = await getArbitrumNetwork(this.destinationChainProvider); - this.l1l3Bridger = new Erc20L1L3Bridger(l3Network); - - return this.l1l3Bridger; - } - - private async getL2Provider() { - if (this.l2Provider) { - return this.l2Provider; - } - - // get the intermediate L2 chain provider - const { l2Provider } = await getL2ConfigForTeleport({ - destinationChainProvider: this.destinationChainProvider, - }); - - this.l2Provider = l2Provider; - - return this.l2Provider; - } - - public async requiresNativeCurrencyApproval() { - return false; // false for now, will need to be implemented for custom-native-token teleports later - } - - public async approveNativeCurrency() { - // no-op, but will need to be implemented for custom-native-token teleports later - } - - public async approveNativeCurrencyEstimateGas() { - // no-op, but will need to be implemented for custom-native-token teleports later - } - - public requiresTokenApproval = async ({ amount, owner }: RequiresTokenApprovalProps) => { - if (!this.sourceChainErc20Address) { - throw Error('Erc20 token address not found'); - } - - const l1l3Bridger = await this.getBridger(); - const l1TeleporterAddress = l1l3Bridger.teleporter.l1Teleporter; - - const allowanceForTeleporter = await fetchErc20Allowance({ - address: this.sourceChainErc20Address, - provider: this.sourceChainProvider, - owner, - spender: l1TeleporterAddress, - }); - - return allowanceForTeleporter.lt(amount); - }; - - public async approveTokenEstimateGas({ signer, amount }: ApproveTokenProps) { - if (!this.sourceChainErc20Address) { - throw Error('Erc20 token address not found'); - } - const address = await getAddressFromSigner(signer); - - const l1l3Bridger = await this.getBridger(); - const l1TeleporterAddress = l1l3Bridger.teleporter.l1Teleporter; - - const contract = ERC20__factory.connect(this.sourceChainErc20Address, this.sourceChainProvider); - return contract.estimateGas.approve(l1TeleporterAddress, amount ?? constants.MaxUint256, { - from: address, - }); - } - - public async approveToken({ signer, amount }: ApproveTokenProps) { - if (!this.sourceChainErc20Address) { - throw Error('Erc20 token address not found'); - } - - const l1l3Bridger = await this.getBridger(); - - return l1l3Bridger.approveToken({ - erc20L1Address: this.sourceChainErc20Address, - l1Signer: signer, - amount, - }); - } - - public async transferEstimateGas({ amount, from }: TransferEstimateGasProps) { - if (!this.sourceChainErc20Address) { - throw Error('Erc20 token address not found'); - } - - const l2Provider = await this.getL2Provider(); - - const l1l3Bridger = await this.getBridger(); - - try { - const depositRequest = await l1l3Bridger.getDepositRequest({ - from, - erc20L1Address: this.sourceChainErc20Address, - amount, - l1Provider: this.sourceChainProvider, - l2Provider, - l3Provider: this.destinationChainProvider, - }); - - const estimatedParentChainGas = await this.sourceChainProvider.estimateGas( - depositRequest.txRequest, - ); - return { - estimatedParentChainGas: percentIncrease(estimatedParentChainGas, BigNumber.from(5)), - estimatedChildChainGas: constants.Zero, - }; - } catch (e) { - console.warn('Error while estimating gas, falling back to hardcoded values.', e); - return { - // fallback estimates - estimatedParentChainGas: BigNumber.from(800_000), - estimatedChildChainGas: constants.Zero, - }; - } - } - - public async transfer({ amount, signer }: TransferProps) { - if (!this.sourceChainErc20Address) { - throw Error('Erc20 token address not found'); - } - - const address = await getAddressFromSigner(signer); - - const l2Provider = await this.getL2Provider(); - - const l1l3Bridger = await this.getBridger(); - - const depositRequest = await l1l3Bridger.getDepositRequest({ - l1Signer: signer, - destinationAddress: address, - erc20L1Address: this.sourceChainErc20Address, - amount, - l1Provider: this.sourceChainProvider, - l2Provider, - l3Provider: this.destinationChainProvider, - }); - - const tx = await l1l3Bridger.deposit({ - txRequest: depositRequest.txRequest, - l1Signer: signer, - }); - - return { - transferType: this.transferType, - status: 'pending', - sourceChainProvider: this.sourceChainProvider, - sourceChainTransaction: tx, - destinationChainProvider: this.destinationChainProvider, - }; - } -} diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/EthTeleportStarter.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/EthTeleportStarter.ts deleted file mode 100644 index f2978f16f..000000000 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/EthTeleportStarter.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { EthL1L3Bridger, getArbitrumNetwork } from '@arbitrum/sdk'; -import { StaticJsonRpcProvider } from '@ethersproject/providers'; -import { BigNumber, constants } from 'ethers'; - -import { - BridgeTransferStarter, - BridgeTransferStarterProps, - TransferEstimateGasProps, - TransferProps, - TransferType, -} from './BridgeTransferStarter'; -import { getL2ConfigForTeleport } from './teleport'; -import { getAddressFromSigner, percentIncrease } from './utils'; - -export class EthTeleportStarter extends BridgeTransferStarter { - public transferType: TransferType = 'eth_teleport'; - private l1l3Bridger: EthL1L3Bridger | undefined; - private l2Provider: StaticJsonRpcProvider | undefined; - - constructor(props: BridgeTransferStarterProps) { - super(props); - } - - private async getBridger() { - if (this.l1l3Bridger) { - return this.l1l3Bridger; - } - - const l3Network = await getArbitrumNetwork(this.destinationChainProvider); - this.l1l3Bridger = new EthL1L3Bridger(l3Network); - - return this.l1l3Bridger; - } - - private async getL2Provider() { - if (this.l2Provider) { - return this.l2Provider; - } - - // get the intermediate L2 chain provider - const { l2Provider } = await getL2ConfigForTeleport({ - destinationChainProvider: this.destinationChainProvider, - }); - - this.l2Provider = l2Provider; - - return this.l2Provider; - } - - public async requiresNativeCurrencyApproval() { - return false; //false for now, but will need to be implemented for custom-native-token teleports later - } - - public async approveNativeCurrency() { - // no-op, but will need to be implemented for custom-native-token teleports later - } - - public async approveNativeCurrencyEstimateGas() { - // no-op, but will need to be implemented for custom-native-token teleports later - } - - public requiresTokenApproval = async () => false; - - public approveTokenEstimateGas = async () => { - // no-op - }; - - public approveToken = async () => { - // no-op - }; - - public async transferEstimateGas({ amount, from }: TransferEstimateGasProps) { - const l2Provider = await this.getL2Provider(); - - const l1l3Bridger = await this.getBridger(); - - try { - const depositRequest = await l1l3Bridger.getDepositRequest({ - from, - amount, - l1Provider: this.sourceChainProvider, - l2Provider, - l3Provider: this.destinationChainProvider, - }); - - const estimatedParentChainGas = await this.sourceChainProvider.estimateGas( - depositRequest.txRequest, - ); - return { - estimatedParentChainGas: percentIncrease(estimatedParentChainGas, BigNumber.from(5)), - estimatedChildChainGas: constants.Zero, - }; - } catch (e) { - console.warn('Error while estimating gas, falling back to hardcoded values.', e); - return { - // fallback estimates - estimatedParentChainGas: BigNumber.from(240_000), - estimatedChildChainGas: constants.Zero, - }; - } - } - - public async transfer({ amount, signer }: TransferProps) { - const address = await getAddressFromSigner(signer); - - const l2Provider = await this.getL2Provider(); - - const l1l3Bridger = await this.getBridger(); - - const depositRequest = await l1l3Bridger.getDepositRequest({ - l1Signer: signer, - destinationAddress: address, - amount, - l1Provider: this.sourceChainProvider, - l2Provider, - l3Provider: this.destinationChainProvider, - }); - - const tx = await l1l3Bridger.deposit({ - ...depositRequest, - l1Signer: signer, - }); - - return { - transferType: this.transferType, - status: 'pending', - sourceChainProvider: this.sourceChainProvider, - sourceChainTransaction: { ...tx }, - destinationChainProvider: this.destinationChainProvider, - }; - } -} diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts index 32f2aeab0..11c0acf4d 100644 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts +++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts @@ -6,11 +6,18 @@ import { IRollupCore__factory } from '@arbitrum/sdk/dist/lib/abi/factories/IRoll import { L1GatewayRouter__factory } from '@arbitrum/sdk/dist/lib/abi/factories/L1GatewayRouter__factory'; import { Provider } from '@ethersproject/providers'; +import { ChainId } from '../types/ChainId'; import { getAccountType } from '../util/AccountUtils'; import { addressIsSmartContract } from '../util/AddressUtils'; -import { TELEPORT_ALLOWLIST } from '../util/networks'; import { getChainIdFromProvider, getProviderForChainId } from './utils'; +// Teleport is deprecated for new transfers, but we keep this allowlist +// for historical transaction detection and status fetching +const TELEPORT_ALLOWLIST: { [id: number]: number[] } = { + [ChainId.Ethereum]: [1380012617, 55244], // Rari, Superposition + [ChainId.Sepolia]: [1918988905], // RARI Testnet +}; + export const isValidTeleportChainPair = ({ sourceChainId, destinationChainId, diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/utils.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/utils.ts index d8c1b2333..61f01011b 100644 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/utils.ts +++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/utils.ts @@ -1,10 +1,4 @@ -import { - Erc20Bridger, - Erc20L1L3Bridger, - EthBridger, - EthL1L3Bridger, - getArbitrumNetwork, -} from '@arbitrum/sdk'; +import { Erc20Bridger, EthBridger } from '@arbitrum/sdk'; import { Provider, StaticJsonRpcProvider } from '@ethersproject/providers'; import { BigNumber, Signer } from 'ethers'; @@ -14,7 +8,6 @@ import { isDepositMode } from '../util/isDepositMode'; import { isNetwork, rpcURLs } from '../util/networks'; import { BridgeTransferStarterPropsWithChainIds } from './BridgeTransferStarter'; import { EnhancedProvider } from './EnhancedProvider'; -import { isValidTeleportChainPair } from './teleport'; export const getAddressFromSigner = async (signer: Signer) => { const address = await signer.getAddress(); @@ -48,11 +41,6 @@ export const getBridgeTransferProperties = (props: BridgeTransferStarterPropsWit (isSourceChainOrbit && isDestinationChainArbitrum) || // l3 orbit chains to l1 (isSourceChainOrbit && isDestinationChainBase); // l3 orbit chain to Base l2 - const isTeleport = isValidTeleportChainPair({ - sourceChainId, - destinationChainId, - }); - const isLifi = isValidLifiTransfer({ sourceChainId, destinationChainId, @@ -65,8 +53,7 @@ export const getBridgeTransferProperties = (props: BridgeTransferStarterPropsWit isDeposit, isWithdrawal, isNativeCurrencyTransfer, - isTeleport, - isSupported: isDeposit || isWithdrawal || isTeleport || isLifi, + isSupported: isDeposit || isWithdrawal || isLifi, isLifi, }; }; @@ -79,7 +66,6 @@ export function percentIncrease(num: BigNumber, increase: BigNumber): BigNumber // We cannot hardcode Erc20Bridger anymore in code, especially while dealing with tokens // this function returns the Bridger matching the set providers export const getBridger = async ({ - sourceChainId, destinationChainId, isNativeCurrencyTransfer = false, }: { @@ -89,14 +75,6 @@ export const getBridger = async ({ }) => { const destinationChainProvider = getProviderForChainId(destinationChainId); - if (isValidTeleportChainPair({ sourceChainId, destinationChainId })) { - const l3Network = getArbitrumNetwork(destinationChainId); - - return isNativeCurrencyTransfer - ? new EthL1L3Bridger(l3Network) - : new Erc20L1L3Bridger(l3Network); - } - return isNativeCurrencyTransfer ? EthBridger.fromProvider(destinationChainProvider) : Erc20Bridger.fromProvider(destinationChainProvider); diff --git a/packages/arb-token-bridge-ui/src/util/TokenTeleportEnabledUtils.ts b/packages/arb-token-bridge-ui/src/util/TokenTeleportEnabledUtils.ts deleted file mode 100644 index 2888f6a34..000000000 --- a/packages/arb-token-bridge-ui/src/util/TokenTeleportEnabledUtils.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { ChainId } from '../types/ChainId'; - -export type TeleportEnabledToken = { - symbol: string; - l1Address: string; - allowedL3ChainIds: number[]; -}; - -const teleportEnabledTokens: { - [parentChainId: number]: TeleportEnabledToken[]; -} = { - [ChainId.Ethereum]: [ - { - symbol: 'WETH', - l1Address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - allowedL3ChainIds: [1380012617], - }, - { - symbol: 'RARI', - l1Address: '0xFca59Cd816aB1eaD66534D82bc21E7515cE441CF', - allowedL3ChainIds: [1380012617], // only allowed for RARI - }, - ], - [ChainId.Sepolia]: [ - { - symbol: 'WETH', - l1Address: '0xfff9976782d46cc05630d1f6ebab18b2324d6b14', - allowedL3ChainIds: [ - 1918988905, // RARI Testnet - ], - }, - { - symbol: 'LINK', - l1Address: '0x779877A7B0D9E8603169DdbD7836e478b4624789', - allowedL3ChainIds: [ - 1918988905, // RARI Testnet - ], - }, - ], -}; - -export function isTeleportEnabledToken( - erc20L1Address: string, - parentChainId: number, - childChainId: number, -) { - // check teleport enabled tokens and return true if the token is not enabled - return (teleportEnabledTokens[parentChainId] ?? []) - .filter((token) => token.allowedL3ChainIds.includes(childChainId)) - .map((token) => token.l1Address.toLowerCase()) - .includes(erc20L1Address.toLowerCase()); -} diff --git a/packages/arb-token-bridge-ui/src/util/TokenUtils.ts b/packages/arb-token-bridge-ui/src/util/TokenUtils.ts index 052689563..b1249e7ef 100644 --- a/packages/arb-token-bridge-ui/src/util/TokenUtils.ts +++ b/packages/arb-token-bridge-ui/src/util/TokenUtils.ts @@ -2,7 +2,6 @@ import { Erc20Bridger, Erc20L1L3Bridger, EthBridger, - EthL1L3Bridger, MultiCaller, getArbitrumNetwork, } from '@arbitrum/sdk'; @@ -307,10 +306,6 @@ export async function getL3ERC20Address({ ); } -function isErc20Bridger(bridger: Erc20Bridger | Erc20L1L3Bridger): bridger is Erc20Bridger { - return typeof (bridger as Erc20Bridger).isDepositDisabled !== 'undefined'; -} - /* Retrieves data about whether an ERC-20 token is disabled on the router. */ @@ -328,14 +323,13 @@ export async function l1TokenIsDisabled({ destinationChainId: await getChainIdFromProvider(l2Provider), }); - if (erc20Bridger instanceof EthL1L3Bridger || erc20Bridger instanceof EthBridger) { - // fail-safe to ensure `l1TokenIsDisabled` is called on the correct bridger-types + if (erc20Bridger instanceof EthBridger) { + // fail-safe to ensure we're working with Erc20Bridger return false; } - return isErc20Bridger(erc20Bridger) - ? erc20Bridger.isDepositDisabled(erc20L1Address, l1Provider) - : erc20Bridger.l1TokenIsDisabled(erc20L1Address, l1Provider); + // erc20Bridger is definitely Erc20Bridger at this point + return erc20Bridger.isDepositDisabled(erc20L1Address, l1Provider); } type SanitizeTokenOptions = { diff --git a/packages/arb-token-bridge-ui/src/util/networks.ts b/packages/arb-token-bridge-ui/src/util/networks.ts index 15baa76d4..be3696ead 100644 --- a/packages/arb-token-bridge-ui/src/util/networks.ts +++ b/packages/arb-token-bridge-ui/src/util/networks.ts @@ -503,16 +503,8 @@ function isBlockNumberReferenceNetwork(chain: { ); } -export const TELEPORT_ALLOWLIST: { [id: number]: number[] } = { - [ChainId.Ethereum]: [1380012617, 55244], // Rari, Superposition - [ChainId.Sepolia]: [1918988905], // RARI Testnet -}; - export function getChildChainIds(chain: ArbitrumNetwork | BlockNumberReferenceNetwork) { - const childChainIds = [ - ...getChildrenForNetwork(chain.chainId).map((chain) => chain.chainId), - ...(TELEPORT_ALLOWLIST[chain.chainId] ?? []), // for considering teleport (L1-L3 transfers) we will get the L3 children of the chain, if present - ]; + const childChainIds = [...getChildrenForNetwork(chain.chainId).map((chain) => chain.chainId)]; return Array.from(new Set(childChainIds)); } From d831066ef7890ee6f97dbf5578ba9a204215729a Mon Sep 17 00:00:00 2001 From: dewanshparashar Date: Fri, 10 Oct 2025 17:06:51 +0400 Subject: [PATCH 2/9] dev: remove more --- .../src/token-bridge-sdk/teleport.ts | 18 ------------------ .../arb-token-bridge-ui/src/util/TokenUtils.ts | 10 +--------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts index 11c0acf4d..9d2af57fa 100644 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts +++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts @@ -6,28 +6,10 @@ import { IRollupCore__factory } from '@arbitrum/sdk/dist/lib/abi/factories/IRoll import { L1GatewayRouter__factory } from '@arbitrum/sdk/dist/lib/abi/factories/L1GatewayRouter__factory'; import { Provider } from '@ethersproject/providers'; -import { ChainId } from '../types/ChainId'; import { getAccountType } from '../util/AccountUtils'; import { addressIsSmartContract } from '../util/AddressUtils'; import { getChainIdFromProvider, getProviderForChainId } from './utils'; -// Teleport is deprecated for new transfers, but we keep this allowlist -// for historical transaction detection and status fetching -const TELEPORT_ALLOWLIST: { [id: number]: number[] } = { - [ChainId.Ethereum]: [1380012617, 55244], // Rari, Superposition - [ChainId.Sepolia]: [1918988905], // RARI Testnet -}; - -export const isValidTeleportChainPair = ({ - sourceChainId, - destinationChainId, -}: { - sourceChainId: number; - destinationChainId: number; -}) => { - return !!TELEPORT_ALLOWLIST[sourceChainId]?.includes(destinationChainId); -}; - export const getL2ConfigForTeleport = async ({ destinationChainProvider, }: { diff --git a/packages/arb-token-bridge-ui/src/util/TokenUtils.ts b/packages/arb-token-bridge-ui/src/util/TokenUtils.ts index b1249e7ef..769c7c8bb 100644 --- a/packages/arb-token-bridge-ui/src/util/TokenUtils.ts +++ b/packages/arb-token-bridge-ui/src/util/TokenUtils.ts @@ -11,7 +11,7 @@ import { constants } from 'ethers'; import { defaultErc20Decimals } from '../defaults'; import { ERC20BridgeToken, TokenType } from '../hooks/arbTokenBridge.types'; -import { getL2ConfigForTeleport, isValidTeleportChainPair } from '../token-bridge-sdk/teleport'; +import { getL2ConfigForTeleport } from '../token-bridge-sdk/teleport'; import { getBridger, getChainIdFromProvider } from '../token-bridge-sdk/utils'; import { ChainId } from '../types/ChainId'; import { addressesEqual } from './AddressUtils'; @@ -455,14 +455,6 @@ export async function isGatewayRegistered({ parentChainProvider: Provider; childChainProvider: Provider; }): Promise { - // for teleport transfers - we will need to check for 2 gateway registrations - 1 for L1-L2 and then for L2-L3 transfer - // for now, we are returning true since we are limiting the tokens to teleport, but we will expand this once we expand the allowList - const sourceChainId = await getChainIdFromProvider(parentChainProvider); - const destinationChainId = await getChainIdFromProvider(childChainProvider); - if (isValidTeleportChainPair({ sourceChainId, destinationChainId })) { - return true; - } - const erc20Bridger = await Erc20Bridger.fromProvider(childChainProvider); return erc20Bridger.isRegistered({ From 175bbf5c068266c3cb2ed86479b4d5f7f1e03aa3 Mon Sep 17 00:00:00 2001 From: dewanshparashar Date: Fri, 10 Oct 2025 17:12:33 +0400 Subject: [PATCH 3/9] dev: less changes --- .../components/TransferPanel/TransferPanel.tsx | 18 +++++------------- .../src/token-bridge-sdk/teleport.ts | 11 +++++++++++ .../src/util/AnalyticsUtils.ts | 9 +-------- .../arb-token-bridge-ui/src/util/networks.ts | 5 +++++ 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx index 152c2b8aa..80b27e673 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx @@ -133,14 +133,7 @@ export function TransferPanel() { const tokensFromLists = useTokensFromLists(); const tokensFromUser = useTokensFromUser(); const { - current: { - childChain, - childChainProvider, - parentChain, - parentChainProvider, - isDepositMode, - isTeleportMode, - }, + current: { childChain, childChainProvider, parentChain, parentChainProvider, isDepositMode }, } = useLatest(useNetworksRelationship(latestNetworks.current)); const { isLoading: isLoadingTokenLists } = useTokenLists(childChain.id); const isBatchTransferSupported = useIsBatchTransferSupported(); @@ -1022,7 +1015,7 @@ export function TransferPanel() { if (isSmartContractWallet) { showDelayInSmartContractTransaction(); - trackEvent(isTeleportMode ? 'Teleport' : isDepositMode ? 'Deposit' : 'Withdraw', { + trackEvent(isDepositMode ? 'Deposit' : 'Withdraw', { tokenSymbol: selectedToken?.symbol, assetType: 'ERC-20', accountType: 'Smart Contract', @@ -1087,7 +1080,7 @@ export function TransferPanel() { const destinationAddress = latestDestinationAddress.current; if (!isSmartContractWallet) { - trackEvent(isTeleportMode ? 'Teleport' : isDepositMode ? 'Deposit' : 'Withdraw', { + trackEvent(isDepositMode ? 'Deposit' : 'Withdraw', { tokenSymbol: selectedToken?.symbol, assetType: selectedToken ? 'ERC-20' : 'ETH', accountType: 'EOA', @@ -1174,7 +1167,7 @@ export function TransferPanel() { const trackTransferButtonClick = useCallback(() => { trackEvent('Transfer Button Click', { - type: isTeleportMode ? 'Teleport' : isDepositMode ? 'Deposit' : 'Withdrawal', + type: isDepositMode ? 'Deposit' : 'Withdrawal', selectedRoute, tokenSymbol: selectedToken?.symbol, assetType: selectedToken ? 'ERC-20' : 'ETH', @@ -1192,7 +1185,6 @@ export function TransferPanel() { isBatchTransfer, isDepositMode, isSmartContractWallet, - isTeleportMode, selectedToken, isCustomDestinationTransfer, selectedRoute, @@ -1212,7 +1204,7 @@ export function TransferPanel() { setTransferring(true); if (isConnectedToTheWrongChain) { trackEvent('Switch Network and Transfer', { - type: isTeleportMode ? 'Teleport' : isDepositMode ? 'Deposit' : 'Withdrawal', + type: isDepositMode ? 'Deposit' : 'Withdrawal', tokenSymbol: selectedToken?.symbol, assetType: selectedToken ? 'ERC-20' : 'ETH', accountType: isSmartContractWallet ? 'Smart Contract' : 'EOA', diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts index 9d2af57fa..32f2aeab0 100644 --- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts +++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/teleport.ts @@ -8,8 +8,19 @@ import { Provider } from '@ethersproject/providers'; import { getAccountType } from '../util/AccountUtils'; import { addressIsSmartContract } from '../util/AddressUtils'; +import { TELEPORT_ALLOWLIST } from '../util/networks'; import { getChainIdFromProvider, getProviderForChainId } from './utils'; +export const isValidTeleportChainPair = ({ + sourceChainId, + destinationChainId, +}: { + sourceChainId: number; + destinationChainId: number; +}) => { + return !!TELEPORT_ALLOWLIST[sourceChainId]?.includes(destinationChainId); +}; + export const getL2ConfigForTeleport = async ({ destinationChainProvider, }: { diff --git a/packages/arb-token-bridge-ui/src/util/AnalyticsUtils.ts b/packages/arb-token-bridge-ui/src/util/AnalyticsUtils.ts index 57b7d3d25..891935dd3 100644 --- a/packages/arb-token-bridge-ui/src/util/AnalyticsUtils.ts +++ b/packages/arb-token-bridge-ui/src/util/AnalyticsUtils.ts @@ -7,7 +7,7 @@ import { FastBridgeNames, SpecialTokenSymbol } from './fastBridges'; type AccountType = 'EOA' | 'Smart Contract'; type AssetType = 'ETH' | 'ERC-20'; -type TransferDirection = 'Deposit' | 'Withdrawal' | 'Teleport'; +type TransferDirection = 'Deposit' | 'Withdrawal'; type FastBridgeName = `${FastBridgeNames}`; // TODO: maintain these wallet names in a central constants file (like networks.ts/wallet.ts) - can be consistently accessed all throughout the app? @@ -50,13 +50,6 @@ type AnalyticsEventMap = { network: string; amount: number; }; - 'Teleport': { - tokenSymbol?: string; - assetType: AssetType; - accountType: AccountType; - network: string; - amount: number; - }; 'Connect Wallet Click': { walletName: ProviderName }; 'Fast Bridge Click': { bridge: FastBridgeName; diff --git a/packages/arb-token-bridge-ui/src/util/networks.ts b/packages/arb-token-bridge-ui/src/util/networks.ts index be3696ead..6957507a0 100644 --- a/packages/arb-token-bridge-ui/src/util/networks.ts +++ b/packages/arb-token-bridge-ui/src/util/networks.ts @@ -503,6 +503,11 @@ function isBlockNumberReferenceNetwork(chain: { ); } +export const TELEPORT_ALLOWLIST: { [id: number]: number[] } = { + [ChainId.Ethereum]: [1380012617, 55244], // Rari, Superposition + [ChainId.Sepolia]: [1918988905], // RARI Testnet +}; + export function getChildChainIds(chain: ArbitrumNetwork | BlockNumberReferenceNetwork) { const childChainIds = [...getChildrenForNetwork(chain.chainId).map((chain) => chain.chainId)]; return Array.from(new Set(childChainIds)); From 50be68976368a8481dbb88630b532a840e7aa26d Mon Sep 17 00:00:00 2001 From: dewanshparashar Date: Mon, 13 Oct 2025 17:45:40 +0400 Subject: [PATCH 4/9] dev: test fix --- .../hooks/useIsCanonicalTransfer.test.ts | 74 +------------------ 1 file changed, 2 insertions(+), 72 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useIsCanonicalTransfer.test.ts b/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useIsCanonicalTransfer.test.ts index a9947f515..dbdb76097 100644 --- a/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useIsCanonicalTransfer.test.ts +++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useIsCanonicalTransfer.test.ts @@ -162,7 +162,7 @@ describe('isArbitrumCanonicalTransfer', () => { }); it('Should return true for USDC transfers', () => { - const ethTeleport = isArbitrumCanonicalTransfer({ + const usdcDeposit = isArbitrumCanonicalTransfer({ childChainId: ChainId.ArbitrumOne, parentChainId: ChainId.Ethereum, sourceChainId: ChainId.Ethereum, @@ -175,7 +175,7 @@ describe('isArbitrumCanonicalTransfer', () => { l2Address: CommonAddress.ArbitrumOne['USDC.e'], }, }); - expect(ethTeleport).toBe(true); + expect(usdcDeposit).toBe(true); }); }); @@ -310,74 +310,4 @@ describe('isArbitrumCanonicalTransfer', () => { expect(usdcWithdraw).toBe(true); }); }); - - describe('teleport mode', () => { - it('should return true from Ethereum to Rari for ETH', () => { - const teleport = isArbitrumCanonicalTransfer({ - childChainId: rariChainId, - parentChainId: ChainId.Ethereum, - sourceChainId: ChainId.Ethereum, - destinationChainId: rariChainId, - isSelectedTokenWithdrawOnly: false, - isSelectedTokenWithdrawOnlyLoading: false, - selectedToken: null, - }); - expect(teleport).toBe(true); - }); - it('should return false from Ethereum to Rari for ERC20', () => { - const teleport = isArbitrumCanonicalTransfer({ - childChainId: rariChainId, - parentChainId: ChainId.Ethereum, - sourceChainId: ChainId.Ethereum, - destinationChainId: rariChainId, - isSelectedTokenWithdrawOnly: false, - isSelectedTokenWithdrawOnlyLoading: false, - selectedToken: usdcToken, - }); - expect(teleport).toBe(false); - }); - it('should return true from Ethereum to Rari for enabled token', () => { - const teleport = isArbitrumCanonicalTransfer({ - childChainId: rariChainId, - parentChainId: ChainId.Ethereum, - sourceChainId: ChainId.Ethereum, - destinationChainId: rariChainId, - isSelectedTokenWithdrawOnly: false, - isSelectedTokenWithdrawOnlyLoading: false, - selectedToken: { - address: '0xFca59Cd816aB1eaD66534D82bc21E7515cE441CF', // RARI - decimals: 18, - symbol: 'RARI', - type: TokenType.ERC20, - name: 'RARI', - listIds: new Set(), - }, - }); - expect(teleport).toBe(true); - }); - - it('should return false from Ethereum to ApeChain', () => { - const ethTeleport = isArbitrumCanonicalTransfer({ - childChainId: ChainId.ApeChain, - parentChainId: ChainId.Ethereum, - sourceChainId: ChainId.Ethereum, - destinationChainId: ChainId.ApeChain, - isSelectedTokenWithdrawOnly: false, - isSelectedTokenWithdrawOnlyLoading: false, - selectedToken: null, - }); - expect(ethTeleport).toBe(false); - - const erc20Teleport = isArbitrumCanonicalTransfer({ - childChainId: ChainId.ApeChain, - parentChainId: ChainId.Ethereum, - sourceChainId: ChainId.Ethereum, - destinationChainId: ChainId.ApeChain, - isSelectedTokenWithdrawOnly: false, - isSelectedTokenWithdrawOnlyLoading: false, - selectedToken: usdcToken, - }); - expect(erc20Teleport).toBe(false); - }); - }); }); From bc0cdd2f59d2f50b9abff6e32947e4eea7be4d47 Mon Sep 17 00:00:00 2001 From: dewanshparashar Date: Mon, 13 Oct 2025 18:11:21 +0400 Subject: [PATCH 5/9] dev: modify childchain ids --- .../src/hooks/useTransactionHistory.ts | 2 +- packages/arb-token-bridge-ui/src/util/networks.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/hooks/useTransactionHistory.ts b/packages/arb-token-bridge-ui/src/hooks/useTransactionHistory.ts index d3d468fc0..c3baab3b5 100644 --- a/packages/arb-token-bridge-ui/src/hooks/useTransactionHistory.ts +++ b/packages/arb-token-bridge-ui/src/hooks/useTransactionHistory.ts @@ -133,7 +133,7 @@ function getMultiChainFetchList(): ChainPair[] { return getChains().flatMap((chain) => { // We only grab child chains because we don't want duplicates and we need the parent chain // Although the type is correct here we default to an empty array for custom networks backwards compatibility - const childChainIds = getChildChainIds(chain); + const childChainIds = getChildChainIds(chain, { includeTeleport: true }); // we only want to consider teleport for tx history to preserve historical data const isParentChain = childChainIds.length > 0; diff --git a/packages/arb-token-bridge-ui/src/util/networks.ts b/packages/arb-token-bridge-ui/src/util/networks.ts index 6957507a0..2d26d55d0 100644 --- a/packages/arb-token-bridge-ui/src/util/networks.ts +++ b/packages/arb-token-bridge-ui/src/util/networks.ts @@ -508,8 +508,14 @@ export const TELEPORT_ALLOWLIST: { [id: number]: number[] } = { [ChainId.Sepolia]: [1918988905], // RARI Testnet }; -export function getChildChainIds(chain: ArbitrumNetwork | BlockNumberReferenceNetwork) { - const childChainIds = [...getChildrenForNetwork(chain.chainId).map((chain) => chain.chainId)]; +export function getChildChainIds( + chain: ArbitrumNetwork | BlockNumberReferenceNetwork, + { includeTeleport }: { includeTeleport: boolean } = { includeTeleport: false }, +) { + const childChainIds = [ + ...getChildrenForNetwork(chain.chainId).map((chain) => chain.chainId), + ...(includeTeleport ? (TELEPORT_ALLOWLIST[chain.chainId] ?? []) : []), // for considering teleport (L1-L3 transfers) we will get the L3 children of the chain, if present + ]; return Array.from(new Set(childChainIds)); } From 064a58071fb31f7e680ce36f7eaab08a97449cbb Mon Sep 17 00:00:00 2001 From: dewanshparashar Date: Tue, 14 Oct 2025 16:51:24 +0400 Subject: [PATCH 6/9] dev: test --- .../src/app/api/chains/[chainId]/block-number.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts b/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts index dea1f61ec..ba0925145 100644 --- a/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts +++ b/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts @@ -58,6 +58,7 @@ export async function GET( } } `, + fetchPolicy: 'no-cache', }); return NextResponse.json( From 869ea4cdd34418cdbcabbaf7c2e2ef9e533156f3 Mon Sep 17 00:00:00 2001 From: dewanshparashar Date: Tue, 14 Oct 2025 16:55:46 +0400 Subject: [PATCH 7/9] dev: unstable --- .../src/app/api/chains/[chainId]/block-number.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts b/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts index ba0925145..8404c9fc4 100644 --- a/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts +++ b/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts @@ -1,4 +1,5 @@ import { gql } from '@apollo/client'; +import { unstable_noStore } from 'next/cache'; import { NextRequest, NextResponse } from 'next/server'; import { @@ -35,6 +36,8 @@ export async function GET( request: NextRequest, { params }: { params: { chainId: string } }, ): Promise> { + unstable_noStore(); + const { chainId } = params; try { From e2e4e05eba5d864421871a0fdb7b67961aedfbb4 Mon Sep 17 00:00:00 2001 From: dewanshparashar Date: Tue, 14 Oct 2025 16:59:46 +0400 Subject: [PATCH 8/9] dev: connection instead of unstbale --- .../src/app/api/chains/[chainId]/block-number.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts b/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts index 8404c9fc4..0c2fbd612 100644 --- a/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts +++ b/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts @@ -1,6 +1,5 @@ import { gql } from '@apollo/client'; -import { unstable_noStore } from 'next/cache'; -import { NextRequest, NextResponse } from 'next/server'; +import { NextRequest, NextResponse, connection } from 'next/server'; import { getL1SubgraphClient, @@ -36,7 +35,7 @@ export async function GET( request: NextRequest, { params }: { params: { chainId: string } }, ): Promise> { - unstable_noStore(); + await connection(); const { chainId } = params; From b8cc5022cc04a36a4e61ba95ed804533d08b6076 Mon Sep 17 00:00:00 2001 From: dewanshparashar Date: Tue, 14 Oct 2025 17:05:52 +0400 Subject: [PATCH 9/9] unstable cache --- .../src/app/api/chains/[chainId]/block-number.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts b/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts index 0c2fbd612..03121df59 100644 --- a/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts +++ b/packages/arb-token-bridge-ui/src/app/api/chains/[chainId]/block-number.ts @@ -1,5 +1,6 @@ import { gql } from '@apollo/client'; -import { NextRequest, NextResponse, connection } from 'next/server'; +import { unstable_noStore } from 'next/cache'; +import { NextRequest, NextResponse } from 'next/server'; import { getL1SubgraphClient, @@ -35,8 +36,7 @@ export async function GET( request: NextRequest, { params }: { params: { chainId: string } }, ): Promise> { - await connection(); - + unstable_noStore(); const { chainId } = params; try { @@ -60,7 +60,6 @@ export async function GET( } } `, - fetchPolicy: 'no-cache', }); return NextResponse.json(