Skip to content

Commit

Permalink
feat: support Base and Base Sepolia as parent chains (#1996)
Browse files Browse the repository at this point in the history
  • Loading branch information
fionnachan authored Oct 21, 2024
1 parent 7fba894 commit 7251f61
Show file tree
Hide file tree
Showing 17 changed files with 327 additions and 55 deletions.
2 changes: 2 additions & 0 deletions packages/arb-token-bridge-ui/.env.local.sample
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ NEXT_PUBLIC_INFURA_KEY_SEPOLIA=

# L2
NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE=
NEXT_PUBLIC_INFURA_KEY_BASE=
# L2 Testnet
NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA=
NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA=

NEXT_PUBLIC_SENTRY_DSN=

Expand Down
3 changes: 3 additions & 0 deletions packages/arb-token-bridge-ui/public/images/BaseWhite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ import { useActions } from '../../state'
import { useChainIdsForNetworkSelection } from '../../hooks/TransferPanel/useChainIdsForNetworkSelection'
import { useAccountType } from '../../hooks/useAccountType'

type NetworkType = 'core' | 'orbit'
type NetworkType = 'core' | 'other' | 'orbit'

enum ChainGroupName {
core = 'CORE CHAINS',
other = 'OTHER CHAINS',
orbit = 'ORBIT CHAINS'
}

Expand All @@ -48,6 +49,19 @@ const chainGroupInfo: { [key in NetworkType]: ChainGroupInfo } = {
core: {
name: ChainGroupName.core
},
other: {
name: ChainGroupName.other,
description: (
<p className="mt-2 flex gap-1 whitespace-normal rounded bg-orange-dark px-2 py-1 text-xs text-orange">
<ShieldExclamationIcon className="h-4 w-4 shrink-0" />
<span>
Independent projects using non-Arbitrum technology. These chains have
varying degrees of decentralization.{' '}
<span className="font-semibold">Bridge at your own risk.</span>
</span>
</p>
)
},
orbit: {
name: ChainGroupName.orbit,
description: (
Expand All @@ -71,15 +85,15 @@ function ChainTypeInfoRow({
style: CSSProperties
}) {
const { name, description } = chainGroup
const isCoreGroup = chainGroup.name === ChainGroupName.core
const isOrbitGroup = chainGroup.name === ChainGroupName.orbit

return (
<div
key={name}
style={style}
className={twMerge(
'px-4 py-3',
!isCoreGroup &&
!isOrbitGroup &&
'before:-mt-3 before:mb-3 before:block before:h-[1px] before:w-full before:bg-white/30 before:content-[""]'
)}
>
Expand Down Expand Up @@ -236,14 +250,19 @@ function NetworksPanel({
}

const coreNetworks = chainIds.filter(
chainId => !isNetwork(chainId).isOrbitChain
chainId => isNetwork(chainId).isCoreChain
)
const otherNetworks = chainIds.filter(
chainId =>
!isNetwork(chainId).isCoreChain && !isNetwork(chainId).isOrbitChain
)
const orbitNetworks = chainIds.filter(
chainId => isNetwork(chainId).isOrbitChain
)

return {
core: coreNetworks,
other: otherNetworks,
orbit: orbitNetworks
}
}, [debouncedNetworkSearched, chainIds])
Expand All @@ -262,6 +281,10 @@ function NetworksPanel({
groupedNetworks.push(ChainGroupName.core, ...networksToShow.core)
}

if (networksToShow.other.length > 0) {
groupedNetworks.push(ChainGroupName.other, ...networksToShow.other)
}

if (networksToShow.orbit.length > 0) {
groupedNetworks.push(ChainGroupName.orbit, ...networksToShow.orbit)
}
Expand Down Expand Up @@ -302,6 +325,12 @@ function NetworksPanel({
)
}

if (networkOrChainTypeName === ChainGroupName.other) {
return (
<ChainTypeInfoRow chainGroup={chainGroupInfo.other} style={style} />
)
}

if (networkOrChainTypeName === ChainGroupName.orbit) {
return (
<ChainTypeInfoRow chainGroup={chainGroupInfo.orbit} style={style} />
Expand Down
6 changes: 5 additions & 1 deletion packages/arb-token-bridge-ui/src/hooks/useNetworks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import {
arbitrumSepolia,
localL1Network as local,
localL2Network as arbitrumLocal,
localL3Network as l3Local
localL3Network as l3Local,
base,
baseSepolia
} from '../util/wagmi/wagmiAdditionalNetworks'

import { getDestinationChainIds } from '../util/networks'
Expand All @@ -37,7 +39,9 @@ export function isSupportedChainId(
holesky.id,
arbitrum.id,
arbitrumNova.id,
base.id,
arbitrumSepolia.id,
baseSepolia.id,
arbitrumLocal.id,
l3Local.id,
local.id,
Expand Down
13 changes: 6 additions & 7 deletions packages/arb-token-bridge-ui/src/token-bridge-sdk/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
EthL1L3Bridger,
getArbitrumNetwork
} from '@arbitrum/sdk'
import { isDepositMode } from '../util/isDepositMode'

export const getAddressFromSigner = async (signer: Signer) => {
const address = await signer.getAddress()
Expand All @@ -28,25 +29,23 @@ export const getBridgeTransferProperties = (
const sourceChainId = props.sourceChainId
const destinationChainId = props.destinationChainId

const isSourceChainEthereumMainnetOrTestnet =
isNetwork(sourceChainId).isEthereumMainnetOrTestnet
const isDestinationChainEthereumMainnetOrTestnet =
isNetwork(destinationChainId).isEthereumMainnetOrTestnet

const isSourceChainArbitrum = isNetwork(sourceChainId).isArbitrum
const isDestinationChainArbitrum = isNetwork(destinationChainId).isArbitrum

const isSourceChainOrbit = isNetwork(sourceChainId).isOrbitChain
const isDestinationChainOrbit = isNetwork(destinationChainId).isOrbitChain

const isDeposit =
isSourceChainEthereumMainnetOrTestnet ||
(isSourceChainArbitrum && isDestinationChainOrbit)
const { isBase: isDestinationChainBase } = isNetwork(destinationChainId)

const isDeposit = isDepositMode({ sourceChainId, destinationChainId })

const isWithdrawal =
(isSourceChainArbitrum && isDestinationChainEthereumMainnetOrTestnet) || // l2 arbitrum chains to l1
(isSourceChainOrbit && isDestinationChainEthereumMainnetOrTestnet) || // l2 orbit chains to l1
(isSourceChainOrbit && isDestinationChainArbitrum) // l3 orbit chains to l1
(isSourceChainOrbit && isDestinationChainArbitrum) || // l3 orbit chains to l1
(isSourceChainOrbit && isDestinationChainBase) // l3 orbit chain to Base l2

const isTeleport = isValidTeleportChainPair({
sourceChainId,
Expand Down
14 changes: 14 additions & 0 deletions packages/arb-token-bridge-ui/src/types/ChainQueryParam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ const chainQueryParams = [
'holesky',
'arbitrum-one',
'arbitrum-nova',
'base',
'arbitrum-sepolia',
'base-sepolia',
'custom-localhost',
'arbitrum-localhost',
'l3-localhost'
Expand Down Expand Up @@ -51,6 +53,9 @@ export function getChainQueryParamForChain(chainId: ChainId): ChainQueryParam {
case ChainId.ArbitrumNova:
return 'arbitrum-nova'

case ChainId.Base:
return 'base'

case ChainId.Holesky:
return 'holesky'

Expand All @@ -60,6 +65,9 @@ export function getChainQueryParamForChain(chainId: ChainId): ChainQueryParam {
case ChainId.ArbitrumSepolia:
return 'arbitrum-sepolia'

case ChainId.BaseSepolia:
return 'base-sepolia'

case ChainId.Local:
return 'custom-localhost'

Expand Down Expand Up @@ -107,9 +115,15 @@ export function getChainForChainKeyQueryParam(
case 'arbitrum-nova':
return customChains.arbitrumNova

case 'base':
return customChains.base

case 'arbitrum-sepolia':
return customChains.arbitrumSepolia

case 'base-sepolia':
return customChains.baseSepolia

case 'custom-localhost':
return customChains.localL1Network

Expand Down
25 changes: 25 additions & 0 deletions packages/arb-token-bridge-ui/src/util/__tests__/networks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ beforeAll(() => {
})

registerCustomArbitrumNetwork(xaiTestnet)

const polterTestnetChainId = 631571
const polterTestnet = orbitTestnets[polterTestnetChainId]

if (!polterTestnet) {
throw new Error(`Could not find Polter Testnet in the Orbit chains list.`)
}

registerCustomArbitrumNetwork(polterTestnet)
})

describe('getBaseChainIdByChainId', () => {
Expand Down Expand Up @@ -254,4 +263,20 @@ describe('getDestinationChainIds', () => {
expect(defaultChainId).toBe(ChainId.Sepolia)
expect(isAscending(nonDefaultChainIds)).toBe(true)
})

it('should return a sorted list for Base Sepolia', () => {
const destinationChainIds = getDestinationChainIds(ChainId.BaseSepolia)
const defaultChainId = destinationChainIds[0]
const nonDefaultChainIds = destinationChainIds.slice(1)

expect(defaultChainId).toBe(631571)
expect(isAscending(nonDefaultChainIds)).toBe(true)
})

// Enable when there are Orbit Chains on Base
it('should not return a list for Base', () => {
const destinationChainIds = getDestinationChainIds(ChainId.Base)

expect(destinationChainIds).toHaveLength(0)
})
})
19 changes: 19 additions & 0 deletions packages/arb-token-bridge-ui/src/util/bridgeUiConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,25 @@ export function getBridgeUiConfigForChain(chainId: number): BridgeUiConfig {
'AnyTrust protocol. Low fees for high-volume transactions. Secured by a trust-minimized Data Availability Committee (DAC).'
}
}
case ChainId.Base:
return {
color: '#0052ff',
network: {
name: 'Base',
logo: '/images/BaseWhite.svg',
description:
'Base is an Optimistic Rollup built by Coinbase with the OP Stack.'
}
}
case ChainId.BaseSepolia:
return {
color: '#0052ff',
network: {
name: 'Base Sepolia',
logo: '/images/BaseWhite.svg',
description: 'Base Sepolia is an Ethereum L2 testnet by Coinbase.'
}
}
default: {
// added Orbit chains
const orbitChain = orbitChains[chainId]
Expand Down
8 changes: 8 additions & 0 deletions packages/arb-token-bridge-ui/src/util/infura.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,14 @@ export function chainIdToInfuraKey(chainId: ChainId) {
return process.env.NEXT_PUBLIC_INFURA_KEY_SEPOLIA || defaultInfuraKey
case ChainId.ArbitrumOne:
return process.env.NEXT_PUBLIC_INFURA_KEY_ARBITRUM_ONE || defaultInfuraKey
case ChainId.Base:
return process.env.NEXT_PUBLIC_INFURA_KEY_BASE || defaultInfuraKey
case ChainId.ArbitrumSepolia:
return (
process.env.NEXT_PUBLIC_INFURA_KEY_ARBITRUM_SEPOLIA || defaultInfuraKey
)
case ChainId.BaseSepolia:
return process.env.NEXT_PUBLIC_INFURA_KEY_BASE_SEPOLIA || defaultInfuraKey

default:
return defaultInfuraKey
Expand All @@ -81,8 +85,12 @@ export function chainIdToInfuraUrl(chainId: ChainId) {
return `https://sepolia.infura.io/v3/${infuraKey}`
case ChainId.ArbitrumOne:
return `https://arbitrum-mainnet.infura.io/v3/${infuraKey}`
case ChainId.Base:
return `https://base-mainnet.infura.io/v3/${infuraKey}`
case ChainId.ArbitrumSepolia:
return `https://arbitrum-sepolia.infura.io/v3/${infuraKey}`
case ChainId.BaseSepolia:
return `https://base-sepolia.infura.io/v3/${infuraKey}`
default:
return undefined
}
Expand Down
7 changes: 5 additions & 2 deletions packages/arb-token-bridge-ui/src/util/isDepositMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ export function isDepositMode({
}) {
const {
isEthereumMainnetOrTestnet: isSourceChainEthereum,
isArbitrum: isSourceChainArbitrum
isArbitrum: isSourceChainArbitrum,
isBase: isSourceChainBase
} = isNetwork(sourceChainId)
const { isOrbitChain: isDestinationChainOrbit } =
isNetwork(destinationChainId)

const isDepositMode =
isSourceChainEthereum || (isSourceChainArbitrum && isDestinationChainOrbit)
isSourceChainEthereum ||
isSourceChainBase ||
(isSourceChainArbitrum && isDestinationChainOrbit)

return isDepositMode
}
Loading

0 comments on commit 7251f61

Please sign in to comment.