Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Localnet support #1628

Merged
merged 6 commits into from
Nov 11, 2024
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
1 change: 1 addition & 0 deletions .changelog/1628.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Localnet support
6 changes: 6 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ REACT_APP_ENABLE_OASIS_MATOMO_ANALYTICS=true
# REACT_APP_TESTNET_API=https://testnet.nexus.stg.oasis.io/v1/
REACT_APP_API=https://nexus.oasis.io/v1/
REACT_APP_TESTNET_API=https://testnet.nexus.oasis.io/v1/
REACT_APP_LOCALNET_API=http://localhost:8547/v1/
REACT_APP_META_TITLE="Oasis Explorer"
REACT_APP_META_IMAGE="Oasis Explorer - OpenGraph Banner.png"
REACT_APP_META_MANIFEST=app.webmanifest
Expand All @@ -29,3 +30,8 @@ REACT_APP_SHOW_BUILD_BANNERS=true
# REACT_APP_FIXED_LAYER=sapphire
# REACT_APP_SKIP_GRAPH=true
REACT_APP_SHOW_FIAT_VALUES=true

# LOCALNET SETTINGS
REACT_APP_LOCALNET_CONSENSUS=false
REACT_APP_LOCALNET_SAPPHIRE=false
REACT_APP_LOCALNET_EMERALD=false
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export const AbiPlaygroundLink: FC<{
[Layer.emerald]: `${externalLinks.dapps.abiPlayground}?network=42261&contractAddress=${address_eth}`,
[Layer.sapphire]: `${externalLinks.dapps.abiPlayground}?network=23295&contractAddress=${address_eth}`,
},
[Network.localnet]: {
[Layer.emerald]: `${externalLinks.dapps.abiPlayground}?network=42260&contractAddress=${address_eth}`,
[Layer.sapphire]: `${externalLinks.dapps.abiPlayground}?network=23293&contractAddress=${address_eth}`,
},
}
const abiPlaygroundLinkProps = {
href: scopeToPlaygroundURL[scope.network]?.[scope.layer],
Expand Down
5 changes: 4 additions & 1 deletion src/app/components/ContractVerificationIcon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Link from '@mui/material/Link'
import Typography from '@mui/material/Typography'
import { SearchScope } from '../../../types/searchScope'
import * as externalLinks from '../../utils/externalLinks'
import { isLocalnet } from '../../utils/route-utils'
import { AbiPlaygroundLink } from './AbiPlaygroundLink'

type VerificationStatus = 'verified' | 'unverified'
Expand Down Expand Up @@ -60,7 +61,9 @@ export const VerificationIcon: FC<{
}> = ({ address_eth, scope, verified, noLink = false }) => {
const { t } = useTranslation()
const [explainDelay, setExplainDelay] = useState(false)

if (isLocalnet(scope.network)) {
return null
}
const status: VerificationStatus = verified ? 'verified' : 'unverified'
const statusLabel: Record<VerificationStatus, string> = {
verified: t('contract.verification.isVerified'),
Expand Down
131 changes: 76 additions & 55 deletions src/app/components/LayerPicker/LayerDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ import { useScreenSize } from '../../hooks/useScreensize'

type LayerDetailsContent = {
description: string
rpcHttp: string
rpcHttp?: string
rpcWebSockets?: string
chainHexId: string
chainDecimalId: string
docs: string
docs?: string
}

type NetworkDetails = Partial<Record<Layer, LayerDetailsContent>>
Expand Down Expand Up @@ -85,6 +85,18 @@ const getDetails = (t: TFunction): Details => ({
docs: docs.pontusx1,
},
},
[Network.localnet]: {
[Layer.sapphire]: {
chainHexId: '0x5afd',
chainDecimalId: '23293',
description: t('layerPicker.localnet.sapphire'),
},
[Layer.emerald]: {
chainHexId: '0xa514',
chainDecimalId: '42260',
description: t('layerPicker.localnet.emerald'),
},
},
})

export const StyledButton = styled(Button)(({ theme }) => ({
Expand All @@ -105,6 +117,7 @@ type LayerDetailsProps = {
handleConfirm: () => void
network: Network
selectedLayer: Layer
selectedNetwork: Network
isOutOfDate: boolean | undefined
}

Expand All @@ -114,17 +127,19 @@ const contentMinHeight = '270px'
export const LayerDetails: FC<LayerDetailsProps> = (props: LayerDetailsProps) =>
props.selectedLayer === Layer.consensus ? <ConsensusDetails {...props} /> : <RuntimeDetails {...props} />

const ConsensusDetails: FC<LayerDetailsProps> = props => {
const ConsensusDetails: FC<LayerDetailsProps & { selectedNetwork: Network }> = props => {
const { t } = useTranslation()
const { handleConfirm, network, selectedLayer } = props
const { handleConfirm, network, selectedLayer, selectedNetwork } = props
const isOutOfDate = useConsensusFreshness(network).outOfDate
const isLocal = selectedNetwork === 'localnet'

return (
<LayerDetailsSection
docsUrl={docs.consensus}
docsUrl={isLocal ? undefined : docs.consensus}
handleConfirm={handleConfirm}
isOutOfDate={isOutOfDate}
selectedLayer={selectedLayer}
selectedNetwork={selectedNetwork}
network={network}
>
<Typography sx={{ fontSize: '14px', color: COLORS.brandExtraDark, pb: 4 }}>
Expand All @@ -136,60 +151,64 @@ const ConsensusDetails: FC<LayerDetailsProps> = props => {

const RuntimeDetails: FC<LayerDetailsProps> = props => {
const { t } = useTranslation()
const { handleConfirm, network, selectedLayer } = props
const { handleConfirm, network, selectedLayer, selectedNetwork } = props
const isOutOfDate = useRuntimeFreshness({ network, layer: selectedLayer }).outOfDate
const details = getDetails(t)[network][selectedLayer]
if (!details) {
return null
}
const details = getDetails(t)[network]?.[selectedLayer]

return (
<LayerDetailsSection
docsUrl={details.docs}
docsUrl={details?.docs}
handleConfirm={handleConfirm}
isOutOfDate={isOutOfDate}
selectedLayer={selectedLayer}
selectedNetwork={selectedNetwork}
network={network}
>
<Typography sx={{ fontSize: '14px', color: COLORS.brandExtraDark, pb: 4 }}>
{details.description}
</Typography>
{details?.description && (
<Typography sx={{ fontSize: '14px', color: COLORS.brandExtraDark, pb: 4 }}>
{details.description}
</Typography>
)}
<TextList>
<TextListItem>
{t('layerPicker.rpcHttp', {
endpoint: details.rpcHttp,
})}
</TextListItem>
{details.rpcWebSockets && (
{details?.rpcHttp && (
<TextListItem>
{t('layerPicker.rpcHttp', {
endpoint: details.rpcHttp,
})}
</TextListItem>
)}
{details?.rpcWebSockets && (
<TextListItem>
{t('layerPicker.rpcWebSockets', {
endpoint: details.rpcWebSockets,
})}
</TextListItem>
)}
<TextListItem>
{t('layerPicker.chainId')}
<TextList>
<TextListItem>
{t('layerPicker.hex', {
id: details.chainHexId,
})}
</TextListItem>
<TextListItem>
{t('layerPicker.decimal', {
id: details.chainDecimalId,
})}
</TextListItem>
</TextList>
</TextListItem>
{details?.chainHexId && details?.chainDecimalId && (
<TextListItem>
{t('layerPicker.chainId')}
<TextList>
<TextListItem>
{t('layerPicker.hex', {
id: details.chainHexId,
})}
</TextListItem>
<TextListItem>
{t('layerPicker.decimal', {
id: details.chainDecimalId,
})}
</TextListItem>
</TextList>
</TextListItem>
)}
</TextList>
</LayerDetailsSection>
)
}

type LayerDetailsSectionProps = LayerDetailsProps & {
children: React.ReactNode
docsUrl: string
docsUrl?: string
}

export const LayerDetailsSection: FC<LayerDetailsSectionProps> = ({
Expand Down Expand Up @@ -236,25 +255,27 @@ export const LayerDetailsSection: FC<LayerDetailsSectionProps> = ({
<LayerStatus isOutOfDate={isOutOfDate} withTooltip />
</Box>
{children}
<Link
component={RouterLink}
to={docsUrl}
target="_blank"
rel="noopener noreferrer"
sx={{
display: 'flex',
alignItems: 'center',
gap: 2,
fontSize: '14px',
fontWeight: 400,
}}
>
{t('layerPicker.readMore', {
layer: layerLabels[selectedLayer],
network: labels[network],
})}
<OpenInNewIcon sx={{ fontSize: '16px' }} />
</Link>
{docsUrl && (
<Link
component={RouterLink}
to={docsUrl}
target="_blank"
rel="noopener noreferrer"
sx={{
display: 'flex',
alignItems: 'center',
gap: 2,
fontSize: '14px',
fontWeight: 400,
}}
>
{t('layerPicker.readMore', {
layer: layerLabels[selectedLayer],
network: labels[network],
})}
<OpenInNewIcon sx={{ fontSize: '16px' }} />
</Link>
)}
</Box>
</Box>
)
Expand Down
1 change: 1 addition & 0 deletions src/app/components/LayerPicker/LayerMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export const LayerMenu: FC<LayerMenuProps> = ({
<MenuList>
{options.map((option, index) => {
if (!option.enabled) {
if (selectedNetwork === 'localnet') return null
return (
<DisabledLayerMenuItem
divider={index !== options.length - 1}
Expand Down
1 change: 1 addition & 0 deletions src/app/components/LayerPicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ const LayerPickerContent: FC<LayerPickerContentProps> = ({ isOutOfDate, onClose,
<LayerDetails
handleConfirm={handleConfirm}
selectedLayer={selectedLayer}
selectedNetwork={selectedNetwork}
network={selectedNetwork}
isOutOfDate={isOutOfDate}
/>
Expand Down
23 changes: 23 additions & 0 deletions src/app/components/Search/search-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,29 @@ export const searchSuggestionTerms = {
},
consensus: undefined,
},
localnet: {
emerald: {
suggestedBlock: '',
suggestedTransaction: '',
suggestedAccount: '',
suggestedTokenFragment: '',
},
sapphire: {
suggestedBlock: '',
suggestedTransaction: '',
suggestedAccount: '',
suggestedTokenFragment: '',
},
cipher: undefined,
pontusxdev: undefined,
pontusxtest: undefined,
consensus: {
suggestedBlock: '',
suggestedTransaction: '',
suggestedAccount: '',
suggestedTokenFragment: '',
},
},
} satisfies SpecifiedPerEnabledLayer<LayerSuggestions>

export const textSearchMinimumLength = 3
Expand Down
3 changes: 3 additions & 0 deletions src/app/config/dapps/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ const dappsForToken: Record<Network, Partial<Record<Layer, Record<string, DappRe
[wRose.mainnetAddress]: wRose.app,
},
},
[Network.localnet]: {
[Layer.sapphire]: undefined,
},
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/app/data/oasis-account-names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ const dataSources: Record<Network, Partial<Record<Layer, string>>> = {
[Layer.sapphire]:
'https://raw.githubusercontent.com/oasisprotocol/nexus/main/account-names/testnet_paratime.json',
},
[Network.localnet]: {
[Layer.consensus]: undefined,
[Layer.emerald]: undefined,
[Layer.sapphire]: undefined,
},
}

const getOasisAccountsMetadata = async (network: Network, layer: Layer): Promise<AccountData> => {
Expand Down
3 changes: 2 additions & 1 deletion src/app/hooks/useAccountMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { usePontusXAccountMetadata, useSearchForPontusXAccountsByName } from '..
import { AccountMetadataInfo, AccountNameSearchResults } from '../data/named-accounts'
import { useOasisAccountMetadata, useSearchForOasisAccountsByName } from '../data/oasis-account-names'
import { getOasisAddress } from '../utils/helpers'
import { isLocalnet } from '../utils/route-utils'

/**
* Find out the metadata for an account
Expand All @@ -20,7 +21,7 @@ export const useAccountMetadata = (scope: SearchScope, address: string): Account
useErrorBoundary: false,
})
const oasisData = useOasisAccountMetadata(scope.network, scope.layer, getOasisAddress(address), {
enabled: !isPontusX,
enabled: !isPontusX && !isLocalnet(scope.network),
useErrorBoundary: false,
})
return isPontusX ? pontusXData : oasisData
Expand Down
Loading
Loading