diff --git a/packages/arb-token-bridge-ui/.env.local.sample b/packages/arb-token-bridge-ui/.env.local.sample
index 9ccb08c10a..9e0d6cfb67 100644
--- a/packages/arb-token-bridge-ui/.env.local.sample
+++ b/packages/arb-token-bridge-ui/.env.local.sample
@@ -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=
diff --git a/packages/arb-token-bridge-ui/public/images/BaseWhite.svg b/packages/arb-token-bridge-ui/public/images/BaseWhite.svg
new file mode 100644
index 0000000000..72e52ac2f8
--- /dev/null
+++ b/packages/arb-token-bridge-ui/public/images/BaseWhite.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/arb-token-bridge-ui/public/images/PolterTestnetLogo.png b/packages/arb-token-bridge-ui/public/images/PolterTestnetLogo.png
new file mode 100644
index 0000000000..70ee5c61fb
Binary files /dev/null and b/packages/arb-token-bridge-ui/public/images/PolterTestnetLogo.png differ
diff --git a/packages/arb-token-bridge-ui/public/images/ghst.png b/packages/arb-token-bridge-ui/public/images/ghst.png
new file mode 100644
index 0000000000..b571b7eef9
Binary files /dev/null and b/packages/arb-token-bridge-ui/public/images/ghst.png differ
diff --git a/packages/arb-token-bridge-ui/src/components/common/NetworkSelectionContainer.tsx b/packages/arb-token-bridge-ui/src/components/common/NetworkSelectionContainer.tsx
index 95994fa261..522a69e6cb 100644
--- a/packages/arb-token-bridge-ui/src/components/common/NetworkSelectionContainer.tsx
+++ b/packages/arb-token-bridge-ui/src/components/common/NetworkSelectionContainer.tsx
@@ -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'
}
@@ -48,6 +49,19 @@ const chainGroupInfo: { [key in NetworkType]: ChainGroupInfo } = {
core: {
name: ChainGroupName.core
},
+ other: {
+ name: ChainGroupName.other,
+ description: (
+
+
+
+ Independent projects using non-Arbitrum technology. These chains have
+ varying degrees of decentralization.{' '}
+ Bridge at your own risk.
+
+
+ )
+ },
orbit: {
name: ChainGroupName.orbit,
description: (
@@ -71,7 +85,7 @@ function ChainTypeInfoRow({
style: CSSProperties
}) {
const { name, description } = chainGroup
- const isCoreGroup = chainGroup.name === ChainGroupName.core
+ const isOrbitGroup = chainGroup.name === ChainGroupName.orbit
return (
@@ -236,7 +250,11 @@ 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
@@ -244,6 +262,7 @@ function NetworksPanel({
return {
core: coreNetworks,
+ other: otherNetworks,
orbit: orbitNetworks
}
}, [debouncedNetworkSearched, chainIds])
@@ -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)
}
@@ -302,6 +325,12 @@ function NetworksPanel({
)
}
+ if (networkOrChainTypeName === ChainGroupName.other) {
+ return (
+
+ )
+ }
+
if (networkOrChainTypeName === ChainGroupName.orbit) {
return (
diff --git a/packages/arb-token-bridge-ui/src/hooks/useNetworks.ts b/packages/arb-token-bridge-ui/src/hooks/useNetworks.ts
index 0e0df4907d..b141f2d144 100644
--- a/packages/arb-token-bridge-ui/src/hooks/useNetworks.ts
+++ b/packages/arb-token-bridge-ui/src/hooks/useNetworks.ts
@@ -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'
@@ -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,
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 7dbf694b29..54e7483bbf 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
@@ -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()
@@ -28,8 +29,6 @@ export const getBridgeTransferProperties = (
const sourceChainId = props.sourceChainId
const destinationChainId = props.destinationChainId
- const isSourceChainEthereumMainnetOrTestnet =
- isNetwork(sourceChainId).isEthereumMainnetOrTestnet
const isDestinationChainEthereumMainnetOrTestnet =
isNetwork(destinationChainId).isEthereumMainnetOrTestnet
@@ -37,16 +36,16 @@ export const getBridgeTransferProperties = (
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,
diff --git a/packages/arb-token-bridge-ui/src/types/ChainQueryParam.ts b/packages/arb-token-bridge-ui/src/types/ChainQueryParam.ts
index 99b20e8463..77abdf0b20 100644
--- a/packages/arb-token-bridge-ui/src/types/ChainQueryParam.ts
+++ b/packages/arb-token-bridge-ui/src/types/ChainQueryParam.ts
@@ -16,7 +16,9 @@ const chainQueryParams = [
'holesky',
'arbitrum-one',
'arbitrum-nova',
+ 'base',
'arbitrum-sepolia',
+ 'base-sepolia',
'custom-localhost',
'arbitrum-localhost',
'l3-localhost'
@@ -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'
@@ -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'
@@ -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
diff --git a/packages/arb-token-bridge-ui/src/util/__tests__/networks.test.ts b/packages/arb-token-bridge-ui/src/util/__tests__/networks.test.ts
index 554663bf91..2dbeb6f3cb 100644
--- a/packages/arb-token-bridge-ui/src/util/__tests__/networks.test.ts
+++ b/packages/arb-token-bridge-ui/src/util/__tests__/networks.test.ts
@@ -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', () => {
@@ -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)
+ })
})
diff --git a/packages/arb-token-bridge-ui/src/util/bridgeUiConfig.ts b/packages/arb-token-bridge-ui/src/util/bridgeUiConfig.ts
index d68e0a1719..d7d4461918 100644
--- a/packages/arb-token-bridge-ui/src/util/bridgeUiConfig.ts
+++ b/packages/arb-token-bridge-ui/src/util/bridgeUiConfig.ts
@@ -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]
diff --git a/packages/arb-token-bridge-ui/src/util/infura.ts b/packages/arb-token-bridge-ui/src/util/infura.ts
index 02124bb907..20fa95514d 100644
--- a/packages/arb-token-bridge-ui/src/util/infura.ts
+++ b/packages/arb-token-bridge-ui/src/util/infura.ts
@@ -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
@@ -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
}
diff --git a/packages/arb-token-bridge-ui/src/util/isDepositMode.ts b/packages/arb-token-bridge-ui/src/util/isDepositMode.ts
index 86f49391ed..dd22cceb7c 100644
--- a/packages/arb-token-bridge-ui/src/util/isDepositMode.ts
+++ b/packages/arb-token-bridge-ui/src/util/isDepositMode.ts
@@ -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
}
diff --git a/packages/arb-token-bridge-ui/src/util/networks.ts b/packages/arb-token-bridge-ui/src/util/networks.ts
index 06fe5ca182..5dc8e5627c 100644
--- a/packages/arb-token-bridge-ui/src/util/networks.ts
+++ b/packages/arb-token-bridge-ui/src/util/networks.ts
@@ -20,20 +20,23 @@ export enum ChainId {
// L2
ArbitrumOne = 42161,
ArbitrumNova = 42170,
+ Base = 8453,
// L2 Testnets
ArbitrumSepolia = 421614,
ArbitrumLocal = 412346,
+ BaseSepolia = 84532,
// L3 Testnets
L3Local = 333333
}
-type L1Network = {
+/** The network that you reference when calling `block.number` in solidity */
+type BlockNumberReferenceNetwork = {
chainId: ChainId
blockTime: number
isTestnet: boolean
}
-const l1Networks: { [chainId: number]: L1Network } = {
+const l1Networks: { [chainId: number]: BlockNumberReferenceNetwork } = {
[ChainId.Ethereum]: {
chainId: ChainId.Ethereum,
blockTime: 12,
@@ -56,12 +59,32 @@ const l1Networks: { [chainId: number]: L1Network } = {
}
}
+const baseNetworks: { [chainId: number]: BlockNumberReferenceNetwork } = {
+ [ChainId.Base]: {
+ chainId: ChainId.Base,
+ blockTime: 2,
+ isTestnet: false
+ },
+ [ChainId.BaseSepolia]: {
+ chainId: ChainId.BaseSepolia,
+ blockTime: 2,
+ isTestnet: true
+ }
+}
+
export const getChains = () => {
- const chains = [...Object.values(l1Networks), ...getArbitrumNetworks()]
+ const chains: (BlockNumberReferenceNetwork | ArbitrumNetwork)[] = [
+ ...Object.values(l1Networks),
+ ...Object.values(baseNetworks),
+ ...getArbitrumNetworks()
+ ]
return chains.filter(chain => {
- // exclude L1 chains with no child chains
- if (isL1Chain(chain) && getChildrenForNetwork(chain.chainId).length === 0) {
+ // exclude L1 chains or Base Chains with no child chains
+ if (
+ isBlockNumberReferenceNetwork(chain) &&
+ getChildrenForNetwork(chain.chainId).length === 0
+ ) {
return false
}
@@ -86,12 +109,12 @@ export function getBaseChainIdByChainId({
}: {
chainId: number
}): number {
- // the chain provided is an L1 chain, so we can return early
- if (isL1Chain({ chainId })) {
+ // the chain provided is an L1 chain or Base chain, so we can return early
+ if (isBlockNumberReferenceNetwork({ chainId })) {
return chainId
}
- let currentParentChain: L1Network | ArbitrumNetwork
+ let currentParentChain: BlockNumberReferenceNetwork | ArbitrumNetwork
try {
currentParentChain = getArbitrumNetwork(chainId)
@@ -99,9 +122,9 @@ export function getBaseChainIdByChainId({
return chainId
}
- // keep following the parent chains until we find the L1 chain
+ // keep following the parent chains until we find the L1/Base chain
while (true) {
- if (isL1Chain(currentParentChain)) {
+ if (isBlockNumberReferenceNetwork(currentParentChain)) {
return currentParentChain.chainId
}
@@ -184,10 +207,12 @@ export function removeCustomChainFromLocalStorage(chainId: number) {
)
}
+// Only support testnet chains
export const supportedCustomOrbitParentChains = [
ChainId.Sepolia,
ChainId.Holesky,
- ChainId.ArbitrumSepolia
+ ChainId.ArbitrumSepolia,
+ ChainId.BaseSepolia
]
export const rpcURLs: { [chainId: number]: string } = {
@@ -208,10 +233,18 @@ export const rpcURLs: { [chainId: number]: string } = {
fallback: 'https://arb1.arbitrum.io/rpc'
}),
[ChainId.ArbitrumNova]: 'https://nova.arbitrum.io/rpc',
+ [ChainId.Base]: loadEnvironmentVariableWithFallback({
+ env: chainIdToInfuraUrl(ChainId.Base),
+ fallback: 'https://mainnet.base.org'
+ }),
// L2 Testnets
[ChainId.ArbitrumSepolia]: loadEnvironmentVariableWithFallback({
env: chainIdToInfuraUrl(ChainId.ArbitrumSepolia),
fallback: 'https://sepolia-rollup.arbitrum.io/rpc'
+ }),
+ [ChainId.BaseSepolia]: loadEnvironmentVariableWithFallback({
+ env: chainIdToInfuraUrl(ChainId.BaseSepolia),
+ fallback: 'https://sepolia.base.org'
})
}
@@ -224,8 +257,10 @@ export const explorerUrls: { [chainId: number]: string } = {
// L2
[ChainId.ArbitrumNova]: 'https://nova.arbiscan.io',
[ChainId.ArbitrumOne]: 'https://arbiscan.io',
+ [ChainId.Base]: 'https://basescan.org',
// L2 Testnets
- [ChainId.ArbitrumSepolia]: 'https://sepolia.arbiscan.io'
+ [ChainId.ArbitrumSepolia]: 'https://sepolia.arbiscan.io',
+ [ChainId.BaseSepolia]: 'https://sepolia.basescan.org'
}
export const getExplorerUrl = (chainId: ChainId) => {
@@ -236,7 +271,7 @@ export const getExplorerUrl = (chainId: ChainId) => {
export const getL1BlockTime = (chainId: number) => {
const chain = getChainByChainId(getBaseChainIdByChainId({ chainId }))
- if (!chain || !isL1Chain(chain)) {
+ if (!chain || !isBlockNumberReferenceNetwork(chain)) {
throw new Error(`Couldn't get block time. Unexpected chain ID: ${chainId}`)
}
@@ -244,6 +279,11 @@ export const getL1BlockTime = (chainId: number) => {
}
export const getConfirmPeriodBlocks = (chainId: ChainId) => {
+ // Base is not an Arbitrum chain so it doesn't work in the same way, and we don't support deposits from L1, or withdrawals from Base chains
+ if (isNetwork(chainId).isBase) {
+ return 0
+ }
+
return getArbitrumNetwork(chainId).confirmPeriodBlocks
}
@@ -269,7 +309,7 @@ export const l2MoonGatewayAddresses: { [chainId: number]: string } = {
[ChainId.ArbitrumNova]: '0xA430a792c14d3E49d9D00FD7B4BA343F516fbB81'
}
-const defaultL1Network: L1Network = {
+const defaultL1Network: BlockNumberReferenceNetwork = {
blockTime: 10,
chainId: 1337,
isTestnet: true
@@ -377,6 +417,11 @@ function isTestnetChain(chainId: ChainId) {
return l1Network.isTestnet
}
+ const baseNetwork = baseNetworks[chainId]
+ if (baseNetwork) {
+ return baseNetwork.isTestnet
+ }
+
try {
return getArbitrumNetwork(chainId).isTestnet
} catch {
@@ -405,12 +450,17 @@ export function isNetwork(chainId: ChainId) {
const isArbitrumSepolia = chainId === ChainId.ArbitrumSepolia
const isArbitrumLocal = chainId === ChainId.ArbitrumLocal
+ const isBaseMainnet = chainId === ChainId.Base
+ const isBaseSepolia = chainId === ChainId.BaseSepolia
+
const isEthereumMainnetOrTestnet =
isEthereumMainnet || isSepolia || isHolesky || isLocal
const isArbitrum =
isArbitrumOne || isArbitrumNova || isArbitrumLocal || isArbitrumSepolia
+ const isBase = isBaseMainnet || isBaseSepolia
+
const isCoreChain = isEthereumMainnetOrTestnet || isArbitrum
const isOrbitChain = getIsArbitrumChain(chainId) && !isCoreChain
@@ -424,8 +474,11 @@ export function isNetwork(chainId: ChainId) {
isArbitrum,
isArbitrumOne,
isArbitrumNova,
+ isBase,
+ isBaseMainnet,
// L2 Testnets
isArbitrumSepolia,
+ isBaseSepolia,
// Orbit chains
isOrbitChain,
// General
@@ -472,22 +525,29 @@ export function mapCustomChainToNetworkData(chain: ChainWithRpcUrl) {
explorerUrls[chain.chainId] = chain.explorerUrl
}
-function isL1Chain(chain: { chainId: number }): chain is L1Network {
- return typeof l1Networks[chain.chainId] !== 'undefined'
-}
-
function isArbitrumChain(
- chain: L1Network | ArbitrumNetwork
+ chain: BlockNumberReferenceNetwork | ArbitrumNetwork
): chain is ArbitrumNetwork {
return typeof (chain as ArbitrumNetwork).parentChainId !== 'undefined'
}
+function isBlockNumberReferenceNetwork(chain: {
+ chainId: number
+}): chain is BlockNumberReferenceNetwork {
+ return (
+ typeof l1Networks[chain.chainId] !== 'undefined' ||
+ typeof baseNetworks[chain.chainId] !== 'undefined'
+ )
+}
+
export const TELEPORT_ALLOWLIST: { [id: number]: number[] } = {
[ChainId.Ethereum]: [1380012617, 70700, 70701], // Rari, PopApex and PopBoss
[ChainId.Sepolia]: [1918988905] // RARI Testnet
}
-export function getChildChainIds(chain: ArbitrumNetwork | L1Network) {
+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
diff --git a/packages/arb-token-bridge-ui/src/util/orbitChainsData.json b/packages/arb-token-bridge-ui/src/util/orbitChainsData.json
index baad064429..406f89a78b 100644
--- a/packages/arb-token-bridge-ui/src/util/orbitChainsData.json
+++ b/packages/arb-token-bridge-ui/src/util/orbitChainsData.json
@@ -880,6 +880,56 @@
"logoUrl": "/images/xrTokenLogo.png"
}
}
+ },
+ {
+ "chainId": 631571,
+ "confirmPeriodBlocks": 900,
+ "ethBridge": {
+ "bridge": "0x133634FA8F372e59422744759a67796F01428BDD",
+ "inbox": "0x81Bf51dEC736adA7E256ed6C092CAe24D62a1ca7",
+ "outbox": "0x020e1cb41cF68999D988c20Ef40E2C58e1947db2",
+ "rollup": "0xAFcb6cF53AB01ac39577A592E141F614171c9371",
+ "sequencerInbox": "0x2453eb0d6F58C01Adb87505A4348fB5EEceB007D"
+ },
+ "nativeToken": "0xe97f36a00058AA7DfC4E85d23532C3f70453a7aE",
+ "explorerUrl": "https://polter-testnet.explorer.alchemy.com",
+ "rpcUrl": "https://geist-polter.g.alchemy.com/public",
+ "isCustom": true,
+ "isTestnet": true,
+ "name": "Polter Testnet",
+ "slug": "polter-testnet",
+ "parentChainId": 84532,
+ "retryableLifetimeSeconds": 604800,
+ "tokenBridge": {
+ "parentCustomGateway": "0x24e1e6375f0f0Eecd38266357cADE57cA3A348F3",
+ "parentErc20Gateway": "0x9014E7244116b965F0D1059f80e2bD8169957117",
+ "parentGatewayRouter": "0xE38553a7989feD9e240DE8B0f5ed166BF75a088A",
+ "parentMultiCall": "0xE0753Df74d86D6B25aCd2d049389c7E52e2dd728",
+ "parentProxyAdmin": "0x0000000000000000000000000000000000000000",
+ "parentWeth": "0x0000000000000000000000000000000000000000",
+ "parentWethGateway": "0x0000000000000000000000000000000000000000",
+ "childCustomGateway": "0x7965162499751ABf89b8e3C640f8229AD8EeB022",
+ "childErc20Gateway": "0xA8E8b5D957e4ad9335E504442e877E513BD50729",
+ "childGatewayRouter": "0xF654086B1118fE98ea045De8D6dC0F1C53Da5B76",
+ "childMultiCall": "0xb97c5bC7DB7532471726550480A855484a408d00",
+ "childProxyAdmin": "0xda11A4ecaAcA51b1f2e2109a2EEFaC438409b68D",
+ "childWeth": "0x0000000000000000000000000000000000000000",
+ "childWethGateway": "0x0000000000000000000000000000000000000000"
+ },
+ "bridgeUiConfig": {
+ "color": "#03AB2A",
+ "network": {
+ "name": "Polter Testnet",
+ "logo": "/images/PolterTestnetLogo.png",
+ "description": "A gaming testnet for Aavegotchi's Geist Mainnet."
+ },
+ "nativeTokenData": {
+ "name": "Aavegotchi GHST Token",
+ "symbol": "GHST",
+ "decimals": 18,
+ "logoUrl": "/images/ghst.png"
+ }
+ }
}
]
}
diff --git a/packages/arb-token-bridge-ui/src/util/wagmi/getWagmiChain.ts b/packages/arb-token-bridge-ui/src/util/wagmi/getWagmiChain.ts
index bd6774c656..66de1b1b0f 100644
--- a/packages/arb-token-bridge-ui/src/util/wagmi/getWagmiChain.ts
+++ b/packages/arb-token-bridge-ui/src/util/wagmi/getWagmiChain.ts
@@ -9,7 +9,9 @@ import {
arbitrumSepolia,
localL1Network,
localL2Network,
- localL3Network
+ localL3Network,
+ baseSepolia,
+ base
} from './wagmiAdditionalNetworks'
import { ChainId } from '../networks'
import { getCustomChainFromLocalStorageById } from '../networks'
@@ -37,6 +39,9 @@ export function getWagmiChain(chainId: number): Chain {
case ChainId.ArbitrumNova:
return arbitrumNova
+ case ChainId.Base:
+ return base
+
// Testnets
case ChainId.Sepolia:
return sepolia
@@ -47,6 +52,9 @@ export function getWagmiChain(chainId: number): Chain {
case ChainId.ArbitrumSepolia:
return arbitrumSepolia
+ case ChainId.BaseSepolia:
+ return baseSepolia
+
// Local networks
case ChainId.Local:
return localL1Network
diff --git a/packages/arb-token-bridge-ui/src/util/wagmi/setup.ts b/packages/arb-token-bridge-ui/src/util/wagmi/setup.ts
index 0023574b53..fac6d8c971 100644
--- a/packages/arb-token-bridge-ui/src/util/wagmi/setup.ts
+++ b/packages/arb-token-bridge-ui/src/util/wagmi/setup.ts
@@ -11,7 +11,9 @@ import {
localL1Network as local,
localL2Network as arbitrumLocal,
localL3Network as l3Local,
- holesky
+ holesky,
+ base,
+ baseSepolia
} from './wagmiAdditionalNetworks'
import { isTestingEnvironment } from '../CommonUtils'
import { getCustomChainsFromLocalStorage, ChainId } from '../networks'
@@ -26,16 +28,22 @@ const wagmiOrbitChains = getOrbitChains().map(chain =>
getWagmiChain(chain.chainId)
)
+const defaultChains = [
+ // mainnet, arb1, & arb nova are for network switch tests
+ mainnet,
+ arbitrum,
+ arbitrumNova,
+ base,
+ // sepolia & arb sepolia are for tx history panel tests
+ sepolia,
+ arbitrumSepolia,
+ baseSepolia,
+ holesky
+]
+
const chainList = isTestingEnvironment
? [
- // mainnet, arb1, & arb nova are for network switch tests
- mainnet,
- arbitrum,
- arbitrumNova,
- // sepolia & arb sepolia are for tx history panel tests
- sepolia,
- arbitrumSepolia,
- holesky,
+ ...defaultChains,
// Orbit chains
...wagmiOrbitChains,
// add local environments during testing
@@ -45,16 +53,7 @@ const chainList = isTestingEnvironment
// user-added custom chains
...customChains
]
- : [
- mainnet,
- arbitrum,
- arbitrumNova,
- sepolia,
- arbitrumSepolia,
- holesky,
- ...wagmiOrbitChains,
- ...customChains
- ]
+ : [...defaultChains, ...wagmiOrbitChains, ...customChains]
const projectId = process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID!
@@ -71,8 +70,10 @@ enum TargetChainKey {
Ethereum = 'mainnet',
ArbitrumOne = 'arbitrum-one',
ArbitrumNova = 'arbitrum-nova',
+ Base = 'base',
Sepolia = 'sepolia',
- ArbitrumSepolia = 'arbitrum-sepolia'
+ ArbitrumSepolia = 'arbitrum-sepolia',
+ BaseSepolia = 'base-sepolia'
}
function sanitizeTargetChainKey(targetChainKey: string | null): TargetChainKey {
@@ -100,11 +101,17 @@ function getChainId(targetChainKey: TargetChainKey): number {
case TargetChainKey.ArbitrumNova:
return ChainId.ArbitrumNova
+ case TargetChainKey.Base:
+ return ChainId.Base
+
case TargetChainKey.Sepolia:
return ChainId.Sepolia
case TargetChainKey.ArbitrumSepolia:
return ChainId.ArbitrumSepolia
+
+ case TargetChainKey.BaseSepolia:
+ return ChainId.BaseSepolia
}
}
diff --git a/packages/arb-token-bridge-ui/src/util/wagmi/wagmiAdditionalNetworks.ts b/packages/arb-token-bridge-ui/src/util/wagmi/wagmiAdditionalNetworks.ts
index 4ab0f3b6a9..857f4f8bee 100644
--- a/packages/arb-token-bridge-ui/src/util/wagmi/wagmiAdditionalNetworks.ts
+++ b/packages/arb-token-bridge-ui/src/util/wagmi/wagmiAdditionalNetworks.ts
@@ -85,6 +85,28 @@ export const arbitrumSepolia: Chain = {
}
}
+export const baseSepolia: Chain = {
+ id: ChainId.BaseSepolia,
+ name: 'Base Sepolia',
+ network: 'base-sepolia',
+ nativeCurrency: ether,
+ rpcUrls: {
+ default: {
+ http: [rpcURLs[ChainId.BaseSepolia]!]
+ },
+ public: {
+ http: [rpcURLs[ChainId.BaseSepolia]!]
+ }
+ },
+ blockExplorers: {
+ etherscan: {
+ name: 'Basescan',
+ url: explorerUrls[ChainId.BaseSepolia]!
+ },
+ default: { name: 'Basescan', url: explorerUrls[ChainId.BaseSepolia]! }
+ }
+}
+
export const arbitrumNova: Chain = {
id: ChainId.ArbitrumNova,
name: 'Arbitrum Nova',
@@ -104,6 +126,25 @@ export const arbitrumNova: Chain = {
}
}
+export const base: Chain = {
+ id: ChainId.Base,
+ name: 'Base',
+ network: 'base',
+ nativeCurrency: ether,
+ rpcUrls: {
+ default: {
+ http: [rpcURLs[ChainId.Base]!]
+ },
+ public: {
+ http: [rpcURLs[ChainId.Base]!]
+ }
+ },
+ blockExplorers: {
+ etherscan: { name: 'Basescan', url: explorerUrls[ChainId.Base]! },
+ default: { name: 'Basescan', url: explorerUrls[ChainId.Base]! }
+ }
+}
+
/**
* For e2e testing
*/