Skip to content
This repository was archived by the owner on Nov 10, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
with:
message: |
## Deployment links
:orange_circle: [Safe Rinkeby](${{ env.REVIEW_FEATURE_URL }}/rinkeby) | :white_circle: [Safe Mainnet](${{ env.REVIEW_FEATURE_URL }}/mainnet) | :purple_circle: [Safe Polygon](${{ env.REVIEW_FEATURE_URL }}/polygon) | :yellow_circle: [Safe BSC](${{ env.REVIEW_FEATURE_URL }}/bsc) | :black_circle: [Safe Arbitrum](${{ env.REVIEW_FEATURE_URL }}/arbitrum) | :green_circle: [Safe xDai](${{ env.REVIEW_FEATURE_URL }}/xdai)
:orange_circle: [Rinkeby](${{ env.REVIEW_FEATURE_URL }}/rin) | :white_circle: [Mainnet](${{ env.REVIEW_FEATURE_URL }}/eth) | :purple_circle: [Polygon](${{ env.REVIEW_FEATURE_URL }}/matic) | :yellow_circle: [BSC](${{ env.REVIEW_FEATURE_URL }}/bnb) | :black_circle: [Arbitrum](${{ env.REVIEW_FEATURE_URL }}/arb1) | :green_circle: [Gnosis Chain](${{ env.REVIEW_FEATURE_URL }}/gno)
-|-|-|-|-|-
repo-token: ${{ secrets.GITHUB_TOKEN }}
repo-token-user-login: 'github-actions[bot]'
Expand Down
9 changes: 1 addition & 8 deletions src/components/Root/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import App from 'src/components/App'
import GlobalErrorBoundary from 'src/components/GlobalErrorBoundary'
import AppRoutes from 'src/routes'
import { store } from 'src/store'
import { history, WELCOME_ROUTE } from 'src/routes/routes'
import { history } from 'src/routes/routes'
import theme from 'src/theme/mui'
import { wrapInSuspense } from 'src/utils/wrapInSuspense'
import Providers from '../Providers'
Expand All @@ -18,9 +18,6 @@ import StoreMigrator from 'src/components/StoreMigrator'
import LegacyRouteRedirection from './LegacyRouteRedirection'
import { logError, Errors, CodedException } from 'src/logic/exceptions/CodedException'
import { loadChains } from 'src/config/cache/chains'
import { isValidChainId, _getChainId } from 'src/config'
import { DEFAULT_CHAIN_ID } from 'src/utils/constants'
import { setChainId } from 'src/logic/config/utils'

// Preloader is rendered outside of '#root' and acts as a loading spinner
// for the app and then chains loading
Expand All @@ -36,10 +33,6 @@ const RootConsumer = (): React.ReactElement | null => {
const initChains = async () => {
try {
await loadChains()
if (!isValidChainId(_getChainId())) {
setChainId(DEFAULT_CHAIN_ID)
history.push(WELCOME_ROUTE)
}
setHasChains(true)
} catch (err) {
logError(Errors._904, err.message)
Expand Down
2 changes: 1 addition & 1 deletion src/config/cache/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let chains: ChainInfo[] = []
export const getChains = (): ChainInfo[] => chains

export const loadChains = async () => {
const { results = [] } = await getChainsConfig(GATEWAY_URL, { limit: 100 })
const { results = [] } = await getChainsConfig(GATEWAY_URL)
Copy link
Member Author

Choose a reason for hiding this comment

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

Also removed limit: 100.

chains = results
// Set the initail web3 provider after loading chains
setWeb3ReadOnly()
Expand Down
2 changes: 1 addition & 1 deletion src/config/chain.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const CHAIN_ID: Record<ChainName, ChainId> = {
OPTIMISM: '10',
KOVAN: '42',
BSC: '56',
XDAI: '100',
GNOSIS_CHAIN: '100',
POLYGON: '137',
ENERGY_WEB_CHAIN: '246',
LOCAL: '4447',
Expand Down
53 changes: 53 additions & 0 deletions src/logic/safe/utils/mocks/remoteConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,59 @@
"SPENDING_LIMIT"
]
},
{
"transactionService": "https://safe-transaction.xdai.gnosis.io",
"chainId": "100",
"chainName": "Gnosis Chain",
"shortName": "gno",
"l2": true,
"description": "Gnosis Chain",
"rpcUri": {
"authentication": "NO_AUTHENTICATION",
"value": "https://rpc.xdaichain.com/oe-only/"
},
"safeAppsRpcUri": {
"authentication": "NO_AUTHENTICATION",
"value": "https://rpc.xdaichain.com/oe-only/"
},
"publicRpcUri": {
"authentication": "NO_AUTHENTICATION",
"value": "https://rpc.xdaichain.com/oe-only/"
},
"blockExplorerUriTemplate": {
"address": "https://blockscout.com/xdai/mainnet/address/{{address}}/transactions",
"txHash": "https://blockscout.com/xdai/mainnet/tx/{{txHash}}/",
"api": "https://blockscout.com/poa/xdai/api?module={{module}}&action={{action}}&address={{address}}&apiKey={{apiKey}}"
},
"nativeCurrency": {
"name": "xDai",
"symbol": "XDAI",
"decimals": 18,
"logoUri": "https://safe-transaction-assets.staging.gnosisdev.com/chains/100/currency_logo.png"
},
"theme": {
"textColor": "#ffffff",
"backgroundColor": "#48A9A6"
},
"gasPrice": [
{
"type": "FIXED",
"weiValue": "4000000000"
}
],
"disabledWallets": [
"metamask",
"walletConnect"
],
"features": [
"CONTRACT_INTERACTION",
"EIP1559",
"ERC721",
"SAFE_APPS",
"SAFE_TX_GAS_OPTIONAL",
"SPENDING_LIMIT"
]
},
{
"transactionService": "https://safe-transaction-polygon.staging.gnosisdev.com",
"chainId": "137",
Expand Down
35 changes: 24 additions & 11 deletions src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import {
} from './routes'
import { getShortName } from 'src/config'
import { setChainId } from 'src/logic/config/utils'
import { switchNetworkWithUrl } from 'src/utils/history'
import { isDeeplinkedTx } from './safe/components/Transactions/TxList/utils'
import { useAddressedRouteKey } from './safe/container/hooks/useAddressedRouteKey'
import { setChainIdFromUrl } from 'src/utils/history'

const Welcome = React.lazy(() => import('./welcome/Welcome'))
const CreateSafePage = React.lazy(() => import('./CreateSafePage/CreateSafePage'))
Expand All @@ -41,6 +41,7 @@ const Routes = (): React.ReactElement => {
// Component key that changes when addressed route slug changes
const { key } = useAddressedRouteKey()

// Google Analytics
useEffect(() => {
let trackedPath = pathname

Expand All @@ -59,12 +60,6 @@ const Routes = (): React.ReactElement => {
}

trackPage(trackedPath + search)

// Set the initial network id from the URL.
// It depends on the chains
switchNetworkWithUrl({ pathname })

// Track when pathname changes
}, [pathname, search, trackPage])

return (
Expand All @@ -74,19 +69,33 @@ const Routes = (): React.ReactElement => {
path="/:url*(/+)"
render={() => <Redirect to={location.pathname.replace(/\/+$/, `${location.search}${location.hash}`)} />}
/>

<Route
// Redirect /xdai root to /gno
path="/xdai"
exact
render={() => <Redirect to="/gno" />}
/>
<Route
// Redirect xdai: shortName to gno:
path="/xdai\::url*"
render={() => <Redirect to={location.pathname.replace(/\/xdai:/, `/gno:`)} />}
/>

{
// Redirection to open network specific welcome pages
getNetworkRootRoutes().map(({ chainId, route }) => (
getNetworkRootRoutes().map(({ chainId, route, shortName }) => (
<Route
key={chainId}
path={route}
path={[route, `/${shortName}`]}
render={() => {
setChainId(chainId)
return <Redirect to={ROOT_ROUTE} />
}}
/>
))
}

<Route
exact
path={ROOT_ROUTE}
Expand All @@ -113,13 +122,17 @@ const Routes = (): React.ReactElement => {
return <Redirect to={WELCOME_ROUTE} />
}}
/>

<Route component={Welcome} exact path={WELCOME_ROUTE} />

<Route component={CreateSafePage} exact path={OPEN_SAFE_ROUTE} />

<Route
path={ADDRESSED_ROUTE}
render={() => {
// Rerender the container/reset its state when prefix/address changes
return <SafeContainer key={key} />
// Routes with a shortName prefix
const validShortName = setChainIdFromUrl(pathname)
return validShortName ? <SafeContainer key={key} /> : <Redirect to={WELCOME_ROUTE} />
}}
/>
<Route component={LoadSafePage} path={[LOAD_SAFE_ROUTE, LOAD_SPECIFIC_SAFE_ROUTE]} />
Expand Down
5 changes: 3 additions & 2 deletions src/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ export const SAFE_ROUTES = {
SETTINGS_ADVANCED: `${ADDRESSED_ROUTE}/settings/advanced`,
}

export const getNetworkRootRoutes = (): Array<{ chainId: ChainId; route: string }> =>
getChains().map(({ chainId, chainName }) => ({
export const getNetworkRootRoutes = (): Array<{ chainId: ChainId; route: string; shortName: string }> =>
getChains().map(({ chainId, chainName, shortName }) => ({
chainId,
route: `/${chainName.replaceAll(' ', '-').toLowerCase()}`,
shortName,
}))

export type SafeRouteParams = { shortName: ShortName; safeAddress: string }
Expand Down
39 changes: 23 additions & 16 deletions src/utils/__tests__/history.test.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,51 @@
import { getShortName } from 'src/config'
import * as configUtils from 'src/logic/config/utils'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { history, WELCOME_ROUTE } from 'src/routes/routes'
import { switchNetworkWithUrl } from '../history'
import { history } from 'src/routes/routes'
import { setChainIdFromUrl } from '../history'

describe('switchNetworkWithUrl', () => {
describe('setChainIdFromUrl', () => {
it('does not switch the network when there is no shortName in the url', () => {
const setChainIdMock = jest.spyOn(configUtils, 'setChainId')
const pathname = `/welcome`

history.push(`/rin:${ZERO_ADDRESS}`)
history.push(pathname)

switchNetworkWithUrl({ pathname: '/welcome' })
const result = setChainIdFromUrl(pathname)

expect(result).toBe(false)
expect(setChainIdMock).not.toHaveBeenCalled()
})
it('does not switch the network when the shortName has not changed', () => {
// chainId defaults to RINKEBY in non-production environments if it can't be read from LS
it('does not switch the network when the chainId has not changed', () => {
const setChainIdMock = jest.spyOn(configUtils, 'setChainId')
const pathname = `/rin:${ZERO_ADDRESS}`

history.push(`/rin:${ZERO_ADDRESS}`)
history.push(pathname)

switchNetworkWithUrl(history.location)
const result = setChainIdFromUrl(pathname)

expect(result).toBe(true)
expect(setChainIdMock).not.toHaveBeenCalled()
})
it('switches the network when the shortName changes', () => {
// chainId defaults to RINKEBY in non-production environments if it can't be read from LS
const setChainIdMock = jest.spyOn(configUtils, 'setChainId')
const pathname = `/eth:${ZERO_ADDRESS}`

history.push(`/eth:${ZERO_ADDRESS}`)
history.push(pathname)

switchNetworkWithUrl(history.location)
const result = setChainIdFromUrl(pathname)

expect(result).toBe(true)
expect(setChainIdMock).toHaveBeenCalled()
})
it('redirects to the Welcome page when incorrect shortName is in the URL', () => {
history.push(`/fakechain:${ZERO_ADDRESS}`)
const setChainIdMock = jest.spyOn(configUtils, 'setChainId')
const pathname = `/fakechain:${ZERO_ADDRESS}`

history.push(pathname)

switchNetworkWithUrl(history.location)
const result = setChainIdFromUrl(pathname)

expect(history.location.pathname).toBe(WELCOME_ROUTE)
expect(result).toBe(false)
expect(setChainIdMock).not.toHaveBeenCalled()
})
})
29 changes: 10 additions & 19 deletions src/utils/history.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
import { LocationDescriptorObject } from 'history'
import { getShortName } from 'src/config'
import { _getChainId } from 'src/config'
import { getChains } from 'src/config/cache/chains'
import { setChainId } from 'src/logic/config/utils'
import { hasPrefixedSafeAddressInUrl, extractPrefixedSafeAddress, history, WELCOME_ROUTE } from 'src/routes/routes'
import { DEFAULT_CHAIN_ID } from './constants'
import { hasPrefixedSafeAddressInUrl, extractPrefixedSafeAddress } from 'src/routes/routes'

export const switchNetworkWithUrl = ({ pathname }: LocationDescriptorObject): void => {
if (!hasPrefixedSafeAddressInUrl()) {
return
}
export const setChainIdFromUrl = (pathname: string): boolean => {
if (!hasPrefixedSafeAddressInUrl()) return false

const { shortName } = extractPrefixedSafeAddress(pathname)
const currentShortName = getShortName()

if (shortName === currentShortName) {
return
}

const chainId = getChains().find((chain) => chain.shortName === shortName)?.chainId

if (!chainId) {
setChainId(DEFAULT_CHAIN_ID)
history.push(WELCOME_ROUTE)
return
if (chainId) {
if (chainId !== _getChainId()) {
setChainId(chainId)
}
return true
}

setChainId(chainId)
return false
}
2 changes: 1 addition & 1 deletion src/utils/storage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const STORAGE_KEYS: Record<ChainId, string> = {
[CHAIN_ID.ETHEREUM]: 'MAINNET',
[CHAIN_ID.RINKEBY]: 'RINKEBY',
[CHAIN_ID.BSC]: 'BSC',
[CHAIN_ID.XDAI]: 'XDAI',
[CHAIN_ID.GNOSIS_CHAIN]: 'XDAI',
[CHAIN_ID.POLYGON]: 'POLYGON',
[CHAIN_ID.ENERGY_WEB_CHAIN]: 'ENERGY_WEB_CHAIN',
[CHAIN_ID.ARBITRUM]: 'ARBITRUM',
Expand Down