fix: use shortenAddress for mini portfolio addresses (#6774)
* fix: use shortenAddress for mini portfolio addresses * Update src/utils/addresses.ts Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com> --------- Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com>
This commit is contained in:
parent
6528fd136e
commit
f27bba9ffa
@ -24,8 +24,8 @@ import { useAppDispatch } from 'state/hooks'
|
|||||||
import { updateSelectedWallet } from 'state/user/reducer'
|
import { updateSelectedWallet } from 'state/user/reducer'
|
||||||
import styled, { useTheme } from 'styled-components/macro'
|
import styled, { useTheme } from 'styled-components/macro'
|
||||||
import { CopyHelper, ExternalLink, ThemedText } from 'theme'
|
import { CopyHelper, ExternalLink, ThemedText } from 'theme'
|
||||||
|
import { shortenAddress } from 'utils'
|
||||||
|
|
||||||
import { shortenAddress } from '../../nft/utils/address'
|
|
||||||
import { useCloseModal, useFiatOnrampAvailability, useOpenModal, useToggleModal } from '../../state/application/hooks'
|
import { useCloseModal, useFiatOnrampAvailability, useOpenModal, useToggleModal } from '../../state/application/hooks'
|
||||||
import { ApplicationModal } from '../../state/application/reducer'
|
import { ApplicationModal } from '../../state/application/reducer'
|
||||||
import { useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
import { useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
||||||
@ -244,12 +244,12 @@ export default function AuthenticatedHeader({ account, openSettings }: { account
|
|||||||
{account && (
|
{account && (
|
||||||
<AccountNamesWrapper>
|
<AccountNamesWrapper>
|
||||||
<ThemedText.SubHeader>
|
<ThemedText.SubHeader>
|
||||||
<CopyText toCopy={ENSName ?? account}>{ENSName ?? shortenAddress(account, 4, 4)}</CopyText>
|
<CopyText toCopy={ENSName ?? account}>{ENSName ?? shortenAddress(account)}</CopyText>
|
||||||
</ThemedText.SubHeader>
|
</ThemedText.SubHeader>
|
||||||
{/* Displays smaller view of account if ENS name was rendered above */}
|
{/* Displays smaller view of account if ENS name was rendered above */}
|
||||||
{ENSName && (
|
{ENSName && (
|
||||||
<ThemedText.BodySmall color="textTertiary">
|
<ThemedText.BodySmall color="textTertiary">
|
||||||
<CopyText toCopy={account}>{shortenAddress(account, 4, 4)}</CopyText>
|
<CopyText toCopy={account}>{shortenAddress(account)}</CopyText>
|
||||||
</ThemedText.BodySmall>
|
</ThemedText.BodySmall>
|
||||||
)}
|
)}
|
||||||
</AccountNamesWrapper>
|
</AccountNamesWrapper>
|
||||||
|
@ -7,6 +7,7 @@ import { TransactionStatus } from 'graphql/data/__generated__/types-and-hooks'
|
|||||||
import useENSName from 'hooks/useENSName'
|
import useENSName from 'hooks/useENSName'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { EllipsisStyle, ThemedText } from 'theme'
|
import { EllipsisStyle, ThemedText } from 'theme'
|
||||||
|
import { shortenAddress } from 'utils'
|
||||||
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
||||||
|
|
||||||
import { PortfolioLogo } from '../PortfolioLogo'
|
import { PortfolioLogo } from '../PortfolioLogo'
|
||||||
@ -52,7 +53,7 @@ export function ActivityRow({
|
|||||||
descriptor={
|
descriptor={
|
||||||
<ActivityRowDescriptor color="textSecondary">
|
<ActivityRowDescriptor color="textSecondary">
|
||||||
{descriptor}
|
{descriptor}
|
||||||
{ENSName ?? otherAccount}
|
{ENSName ?? shortenAddress(otherAccount)}
|
||||||
</ActivityRowDescriptor>
|
</ActivityRowDescriptor>
|
||||||
}
|
}
|
||||||
right={
|
right={
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
|
import { escapeRegExp } from 'utils'
|
||||||
import { escapeRegExp } from '../../utils'
|
|
||||||
|
|
||||||
const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string }>`
|
const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string }>`
|
||||||
color: ${({ error, theme }) => (error ? theme.accentFailure : theme.textPrimary)};
|
color: ${({ error, theme }) => (error ? theme.accentFailure : theme.textPrimary)};
|
||||||
|
@ -15,10 +15,10 @@ import { useCallback, useMemo } from 'react'
|
|||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { colors } from 'theme/colors'
|
import { colors } from 'theme/colors'
|
||||||
import { flexRowNoWrap } from 'theme/styles'
|
import { flexRowNoWrap } from 'theme/styles'
|
||||||
|
import { shortenAddress } from 'utils'
|
||||||
|
|
||||||
import { isTransactionRecent, useAllTransactions } from '../../state/transactions/hooks'
|
import { isTransactionRecent, useAllTransactions } from '../../state/transactions/hooks'
|
||||||
import { TransactionDetails } from '../../state/transactions/types'
|
import { TransactionDetails } from '../../state/transactions/types'
|
||||||
import { shortenAddress } from '../../utils'
|
|
||||||
import { ButtonSecondary } from '../Button'
|
import { ButtonSecondary } from '../Button'
|
||||||
import StatusIcon from '../Identicon/StatusIcon'
|
import StatusIcon from '../Identicon/StatusIcon'
|
||||||
import { RowBetween } from '../Row'
|
import { RowBetween } from '../Row'
|
||||||
|
@ -5,6 +5,7 @@ import { useWeb3React } from '@web3-react/core'
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
|
import { shortenAddress } from 'utils'
|
||||||
|
|
||||||
import Circle from '../../assets/images/blue-loader.svg'
|
import Circle from '../../assets/images/blue-loader.svg'
|
||||||
import tokenLogo from '../../assets/images/token-logo.png'
|
import tokenLogo from '../../assets/images/token-logo.png'
|
||||||
@ -12,7 +13,6 @@ import useENS from '../../hooks/useENS'
|
|||||||
import { useClaimCallback, useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
import { useClaimCallback, useUserHasAvailableClaim, useUserUnclaimedAmount } from '../../state/claim/hooks'
|
||||||
import { useIsTransactionPending } from '../../state/transactions/hooks'
|
import { useIsTransactionPending } from '../../state/transactions/hooks'
|
||||||
import { CloseIcon, CustomLightSpinner, ExternalLink, ThemedText, UniTokenAnimated } from '../../theme'
|
import { CloseIcon, CustomLightSpinner, ExternalLink, ThemedText, UniTokenAnimated } from '../../theme'
|
||||||
import { shortenAddress } from '../../utils'
|
|
||||||
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
import { ExplorerDataType, getExplorerLink } from '../../utils/getExplorerLink'
|
||||||
import AddressInputPanel from '../AddressInputPanel'
|
import AddressInputPanel from '../AddressInputPanel'
|
||||||
import { ButtonPrimary } from '../Button'
|
import { ButtonPrimary } from '../Button'
|
||||||
|
@ -32,8 +32,7 @@ import { WRAPPED_NATIVE_CURRENCY } from 'constants/tokens'
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { NonfungiblePositionManager, Quoter, QuoterV2, TickLens, UniswapInterfaceMulticall } from 'types/v3'
|
import { NonfungiblePositionManager, Quoter, QuoterV2, TickLens, UniswapInterfaceMulticall } from 'types/v3'
|
||||||
import { V3Migrator } from 'types/v3/V3Migrator'
|
import { V3Migrator } from 'types/v3/V3Migrator'
|
||||||
|
import { getContract } from 'utils'
|
||||||
import { getContract } from '../utils'
|
|
||||||
|
|
||||||
const { abi: IUniswapV2PairABI } = IUniswapV2PairJson
|
const { abi: IUniswapV2PairABI } = IUniswapV2PairJson
|
||||||
const { abi: IUniswapV2Router02ABI } = IUniswapV2Router02Json
|
const { abi: IUniswapV2Router02ABI } = IUniswapV2Router02Json
|
||||||
|
@ -25,7 +25,6 @@ import {
|
|||||||
TokenRarity,
|
TokenRarity,
|
||||||
} from 'nft/types'
|
} from 'nft/types'
|
||||||
import { getMarketplaceIcon } from 'nft/utils'
|
import { getMarketplaceIcon } from 'nft/utils'
|
||||||
import { shortenAddress } from 'nft/utils/address'
|
|
||||||
import { buildActivityAsset } from 'nft/utils/buildActivityAsset'
|
import { buildActivityAsset } from 'nft/utils/buildActivityAsset'
|
||||||
import { formatEth } from 'nft/utils/currency'
|
import { formatEth } from 'nft/utils/currency'
|
||||||
import { getTimeDifference } from 'nft/utils/date'
|
import { getTimeDifference } from 'nft/utils/date'
|
||||||
@ -33,6 +32,7 @@ import { putCommas } from 'nft/utils/putCommas'
|
|||||||
import { MouseEvent, ReactNode, useMemo, useState } from 'react'
|
import { MouseEvent, ReactNode, useMemo, useState } from 'react'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { ExternalLink } from 'theme'
|
import { ExternalLink } from 'theme'
|
||||||
|
import { shortenAddress } from 'utils'
|
||||||
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
import { ExplorerDataType, getExplorerLink } from 'utils/getExplorerLink'
|
||||||
|
|
||||||
import * as styles from './Activity.css'
|
import * as styles from './Activity.css'
|
||||||
@ -165,7 +165,7 @@ export const AddressCell = ({ address, desktopLBreakpoint, chainId }: AddressCel
|
|||||||
href={getExplorerLink(chainId ?? ChainId.MAINNET, address ?? '', ExplorerDataType.ADDRESS)}
|
href={getExplorerLink(chainId ?? ChainId.MAINNET, address ?? '', ExplorerDataType.ADDRESS)}
|
||||||
style={{ textDecoration: 'none' }}
|
style={{ textDecoration: 'none' }}
|
||||||
>
|
>
|
||||||
<Box onClick={(e) => e.stopPropagation()}>{address ? shortenAddress(address, 2, 4) : '-'}</Box>
|
<Box onClick={(e) => e.stopPropagation()}>{address ? shortenAddress(address, 2) : '-'}</Box>
|
||||||
</AddressLink>
|
</AddressLink>
|
||||||
</Column>
|
</Column>
|
||||||
)
|
)
|
||||||
|
@ -4,11 +4,11 @@ import { LoadingBubble } from 'components/Tokens/loading'
|
|||||||
import { EventCell } from 'nft/components/collection/ActivityCells'
|
import { EventCell } from 'nft/components/collection/ActivityCells'
|
||||||
import { ActivityEvent } from 'nft/types'
|
import { ActivityEvent } from 'nft/types'
|
||||||
import { getMarketplaceIcon } from 'nft/utils'
|
import { getMarketplaceIcon } from 'nft/utils'
|
||||||
import { shortenAddress } from 'nft/utils/address'
|
|
||||||
import { formatEth } from 'nft/utils/currency'
|
import { formatEth } from 'nft/utils/currency'
|
||||||
import { getTimeDifference } from 'nft/utils/date'
|
import { getTimeDifference } from 'nft/utils/date'
|
||||||
import { ReactNode } from 'react'
|
import { ReactNode } from 'react'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
|
import { shortenAddress } from 'utils'
|
||||||
|
|
||||||
const TR = styled.tr`
|
const TR = styled.tr`
|
||||||
border-bottom: ${({ theme }) => `1px solid ${theme.backgroundOutline}`};
|
border-bottom: ${({ theme }) => `1px solid ${theme.backgroundOutline}`};
|
||||||
@ -177,7 +177,7 @@ const AssetActivity = ({ events }: { events?: ActivityEvent[] }) => {
|
|||||||
<TD>
|
<TD>
|
||||||
{fromAddress && (
|
{fromAddress && (
|
||||||
<Link href={`https://etherscan.io/address/${fromAddress}`} target="_blank" rel="noopener noreferrer">
|
<Link href={`https://etherscan.io/address/${fromAddress}`} target="_blank" rel="noopener noreferrer">
|
||||||
{shortenAddress(fromAddress, 2, 4)}
|
{shortenAddress(fromAddress, 2)}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</TD>
|
</TD>
|
||||||
@ -185,7 +185,7 @@ const AssetActivity = ({ events }: { events?: ActivityEvent[] }) => {
|
|||||||
<TD>
|
<TD>
|
||||||
{toAddress && (
|
{toAddress && (
|
||||||
<Link href={`https://etherscan.io/address/${toAddress}`} target="_blank" rel="noopener noreferrer">
|
<Link href={`https://etherscan.io/address/${toAddress}`} target="_blank" rel="noopener noreferrer">
|
||||||
{shortenAddress(toAddress, 2, 4)}
|
{shortenAddress(toAddress, 2)}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</TD>
|
</TD>
|
||||||
|
@ -10,7 +10,6 @@ import { AssetPriceDetails } from 'nft/components/details/AssetPriceDetails'
|
|||||||
import { Center } from 'nft/components/Flex'
|
import { Center } from 'nft/components/Flex'
|
||||||
import { themeVars, vars } from 'nft/css/sprinkles.css'
|
import { themeVars, vars } from 'nft/css/sprinkles.css'
|
||||||
import { ActivityEventType, CollectionInfoForAsset, GenieAsset } from 'nft/types'
|
import { ActivityEventType, CollectionInfoForAsset, GenieAsset } from 'nft/types'
|
||||||
import { shortenAddress } from 'nft/utils/address'
|
|
||||||
import { formatEth } from 'nft/utils/currency'
|
import { formatEth } from 'nft/utils/currency'
|
||||||
import { isAudio } from 'nft/utils/isAudio'
|
import { isAudio } from 'nft/utils/isAudio'
|
||||||
import { isVideo } from 'nft/utils/isVideo'
|
import { isVideo } from 'nft/utils/isVideo'
|
||||||
@ -20,6 +19,7 @@ import InfiniteScroll from 'react-infinite-scroll-component'
|
|||||||
import { Link as RouterLink } from 'react-router-dom'
|
import { Link as RouterLink } from 'react-router-dom'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
import { useIsDarkMode } from 'theme/components/ThemeToggle'
|
import { useIsDarkMode } from 'theme/components/ThemeToggle'
|
||||||
|
import { shortenAddress } from 'utils/addresses'
|
||||||
|
|
||||||
import AssetActivity, { LoadingAssetActivity } from './AssetActivity'
|
import AssetActivity, { LoadingAssetActivity } from './AssetActivity'
|
||||||
import * as styles from './AssetDetails.css'
|
import * as styles from './AssetDetails.css'
|
||||||
@ -427,7 +427,7 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
{shortenAddress(asset.creator.address, 2, 4)}
|
{shortenAddress(asset.creator.address, 2)}
|
||||||
</AddressTextLink>
|
</AddressTextLink>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@ import {
|
|||||||
timeLeft,
|
timeLeft,
|
||||||
useUsdPrice,
|
useUsdPrice,
|
||||||
} from 'nft/utils'
|
} from 'nft/utils'
|
||||||
import { shortenAddress } from 'nft/utils/address'
|
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { Upload } from 'react-feather'
|
import { Upload } from 'react-feather'
|
||||||
import { useQuery } from 'react-query'
|
import { useQuery } from 'react-query'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
import styled, { css, useTheme } from 'styled-components/macro'
|
import styled, { css, useTheme } from 'styled-components/macro'
|
||||||
import { ExternalLink, ThemedText } from 'theme'
|
import { ExternalLink, ThemedText } from 'theme'
|
||||||
|
import { shortenAddress } from 'utils/addresses'
|
||||||
|
|
||||||
const TWITTER_WIDTH = 560
|
const TWITTER_WIDTH = 560
|
||||||
const TWITTER_HEIGHT = 480
|
const TWITTER_HEIGHT = 480
|
||||||
@ -425,7 +425,7 @@ export const AssetPriceDetails = ({ asset, collection }: AssetPriceDetailsProps)
|
|||||||
{asset.tokenType === 'ERC1155' ? (
|
{asset.tokenType === 'ERC1155' ? (
|
||||||
''
|
''
|
||||||
) : (
|
) : (
|
||||||
<span> {isOwner ? 'You' : asset.ownerAddress && shortenAddress(asset.ownerAddress, 2, 4)}</span>
|
<span> {isOwner ? 'You' : asset.ownerAddress && shortenAddress(asset.ownerAddress, 2)}</span>
|
||||||
)}
|
)}
|
||||||
</OwnerText>
|
</OwnerText>
|
||||||
</OwnerInformationContainer>
|
</OwnerInformationContainer>
|
||||||
|
@ -2,10 +2,10 @@ import { OpacityHoverState } from 'components/Common'
|
|||||||
import useCopyClipboard from 'hooks/useCopyClipboard'
|
import useCopyClipboard from 'hooks/useCopyClipboard'
|
||||||
import { CollectionInfoForAsset, GenieAsset } from 'nft/types'
|
import { CollectionInfoForAsset, GenieAsset } from 'nft/types'
|
||||||
import { putCommas } from 'nft/utils'
|
import { putCommas } from 'nft/utils'
|
||||||
import { shortenAddress } from 'nft/utils/address'
|
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { Copy } from 'react-feather'
|
import { Copy } from 'react-feather'
|
||||||
import styled from 'styled-components/macro'
|
import styled from 'styled-components/macro'
|
||||||
|
import { shortenAddress } from 'utils'
|
||||||
|
|
||||||
const Details = styled.div`
|
const Details = styled.div`
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -80,7 +80,7 @@ const DetailsContainer = ({ asset, collection }: { asset: GenieAsset; collection
|
|||||||
header="Contract address"
|
header="Contract address"
|
||||||
body={
|
body={
|
||||||
<Center onClick={copy}>
|
<Center onClick={copy}>
|
||||||
{shortenAddress(address, 2, 4)} <CopyIcon size={13} />
|
{shortenAddress(address, 2)} <CopyIcon size={13} />
|
||||||
</Center>
|
</Center>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -97,7 +97,7 @@ const DetailsContainer = ({ asset, collection }: { asset: GenieAsset; collection
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
{shortenAddress(creator.address, 2, 4)}
|
{shortenAddress(creator.address, 2)}
|
||||||
</CreatorLink>
|
</CreatorLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
import { isAddress } from '@ethersproject/address'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortens an Ethereum address by N characters
|
|
||||||
* @param address blockchain address
|
|
||||||
* @param charsStart amount of character to shorten (from both ends / in the beginning)
|
|
||||||
* @param charsEnd amount of characters to shorten in the end
|
|
||||||
* @returns formatted string
|
|
||||||
*/
|
|
||||||
export function shortenAddress(address: string, charsStart = 4, charsEnd?: number): string {
|
|
||||||
const parsed = isAddress(address)
|
|
||||||
if (!parsed) return ''
|
|
||||||
|
|
||||||
return `${address.substring(0, charsStart + 2)}...${address.substring(42 - (charsEnd || charsStart))}`
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import { isAddress, shortenAddress } from '.'
|
import { isAddress, shortenAddress } from './addresses'
|
||||||
|
|
||||||
describe('utils', () => {
|
describe('utils', () => {
|
||||||
describe('#isAddress', () => {
|
describe('#isAddress', () => {
|
||||||
@ -18,14 +18,15 @@ describe('utils', () => {
|
|||||||
it('succeeds even without prefix', () => {
|
it('succeeds even without prefix', () => {
|
||||||
expect(isAddress('f164fc0ec4e93095b804a4795bbe1e041497b92a')).toBe('0xf164fC0Ec4E93095b804a4795bBe1e041497b92a')
|
expect(isAddress('f164fc0ec4e93095b804a4795bbe1e041497b92a')).toBe('0xf164fC0Ec4E93095b804a4795bBe1e041497b92a')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('fails if too long', () => {
|
it('fails if too long', () => {
|
||||||
expect(isAddress('f164fc0ec4e93095b804a4795bbe1e041497b92a0')).toBe(false)
|
expect(isAddress('f164fc0ec4e93095b804a4795bbe1e041497b92a0')).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#shortenAddress', () => {
|
describe('#shortenAddress', () => {
|
||||||
it('throws on invalid address', () => {
|
it('doesnt throw on invalid address', () => {
|
||||||
expect(() => shortenAddress('abc')).toThrow("Invalid 'address'")
|
expect(shortenAddress('abc123')).toEqual('')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('truncates middle characters', () => {
|
it('truncates middle characters', () => {
|
||||||
@ -39,5 +40,16 @@ describe('utils', () => {
|
|||||||
it('renders checksummed address', () => {
|
it('renders checksummed address', () => {
|
||||||
expect(shortenAddress('0x2E1b342132A67Ea578e4E3B814bae2107dc254CC'.toLowerCase())).toBe('0x2E1b...54CC')
|
expect(shortenAddress('0x2E1b342132A67Ea578e4E3B814bae2107dc254CC'.toLowerCase())).toBe('0x2E1b...54CC')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('allows undefined', () => {
|
||||||
|
expect(shortenAddress()).toBe('')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('allows custom amounts of start/end chars', () => {
|
||||||
|
expect(shortenAddress('0x2E1b342132A67Ea578e4E3B814bae2107dc254CC', 2)).toBe('0x2E...54CC')
|
||||||
|
expect(shortenAddress('0x2E1b342132A67Ea578e4E3B814bae2107dc254CC', 6)).toBe('0x2E1b34...54CC')
|
||||||
|
expect(shortenAddress('0x2E1b342132A67Ea578e4E3B814bae2107dc254CC', 2, 2)).toBe('0x2E...CC')
|
||||||
|
expect(shortenAddress('0x2E1b342132A67Ea578e4E3B814bae2107dc254CC', 2, 6)).toBe('0x2E...c254CC')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
43
src/utils/addresses.ts
Normal file
43
src/utils/addresses.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { getAddress } from '@ethersproject/address'
|
||||||
|
|
||||||
|
// returns the checksummed address if the address is valid, otherwise returns false
|
||||||
|
export function isAddress(value: any): string | false {
|
||||||
|
try {
|
||||||
|
// Alphabetical letters must be made lowercase for getAddress to work.
|
||||||
|
// See documentation here: https://docs.ethers.io/v5/api/utils/address/
|
||||||
|
return getAddress(value.toLowerCase())
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shortens an Ethereum address
|
||||||
|
export function shortenAddress(address = '', charsStart = 4, charsEnd = 4): string {
|
||||||
|
const parsed = isAddress(address)
|
||||||
|
if (!parsed) return ''
|
||||||
|
return ellipseAddressAdd0x(parsed, charsStart, charsEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorten an address and add 0x to the start if missing
|
||||||
|
* @param targetAddress
|
||||||
|
* @param charsStart amount of character to shorten (from both ends / in the beginning)
|
||||||
|
* @param charsEnd amount of characters to shorten in the end
|
||||||
|
* @returns formatted string
|
||||||
|
*/
|
||||||
|
function ellipseAddressAdd0x(targetAddress: string, charsStart = 4, charsEnd = 4): string {
|
||||||
|
const hasPrefix = targetAddress.startsWith('0x')
|
||||||
|
const prefix = hasPrefix ? '' : '0x'
|
||||||
|
return ellipseMiddle(prefix + targetAddress, charsStart + 2, charsEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorten a string with "..." in the middle
|
||||||
|
* @param target
|
||||||
|
* @param charsStart amount of character to shorten (from both ends / in the beginning)
|
||||||
|
* @param charsEnd amount of characters to shorten in the end
|
||||||
|
* @returns formatted string
|
||||||
|
*/
|
||||||
|
function ellipseMiddle(target: string, charsStart = 4, charsEnd = 4): string {
|
||||||
|
return `${target.slice(0, charsStart)}...${target.slice(target.length - charsEnd)}`
|
||||||
|
}
|
3
src/utils/escapeRegExp.ts
Normal file
3
src/utils/escapeRegExp.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function escapeRegExp(string: string): string {
|
||||||
|
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
|
||||||
|
}
|
23
src/utils/getContract.ts
Normal file
23
src/utils/getContract.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { AddressZero } from '@ethersproject/constants'
|
||||||
|
import { Contract } from '@ethersproject/contracts'
|
||||||
|
import { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers'
|
||||||
|
|
||||||
|
import { isAddress } from './addresses'
|
||||||
|
|
||||||
|
// account is optional
|
||||||
|
|
||||||
|
export function getContract(address: string, ABI: any, provider: JsonRpcProvider, account?: string): Contract {
|
||||||
|
if (!isAddress(address) || address === AddressZero) {
|
||||||
|
throw Error(`Invalid 'address' parameter '${address}'.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Contract(address, ABI, getProviderOrSigner(provider, account) as any)
|
||||||
|
}
|
||||||
|
// account is not optional
|
||||||
|
function getSigner(provider: JsonRpcProvider, account: string): JsonRpcSigner {
|
||||||
|
return provider.getSigner(account).connectUnchecked()
|
||||||
|
}
|
||||||
|
// account is optional
|
||||||
|
function getProviderOrSigner(provider: JsonRpcProvider, account?: string): JsonRpcProvider | JsonRpcSigner {
|
||||||
|
return account ? getSigner(provider, account) : provider
|
||||||
|
}
|
@ -1,47 +1,3 @@
|
|||||||
import { getAddress } from '@ethersproject/address'
|
export * from './addresses'
|
||||||
import { AddressZero } from '@ethersproject/constants'
|
export * from './escapeRegExp'
|
||||||
import { Contract } from '@ethersproject/contracts'
|
export * from './getContract'
|
||||||
import type { JsonRpcProvider, JsonRpcSigner } from '@ethersproject/providers'
|
|
||||||
|
|
||||||
// returns the checksummed address if the address is valid, otherwise returns false
|
|
||||||
export function isAddress(value: any): string | false {
|
|
||||||
try {
|
|
||||||
// Alphabetical letters must be made lowercase for getAddress to work.
|
|
||||||
// See documentation here: https://docs.ethers.io/v5/api/utils/address/
|
|
||||||
return getAddress(value.toLowerCase())
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// shorten the checksummed version of the input address to have 0x + 4 characters at start and end
|
|
||||||
export function shortenAddress(address: string, chars = 4): string {
|
|
||||||
const parsed = isAddress(address)
|
|
||||||
if (!parsed) {
|
|
||||||
throw Error(`Invalid 'address' parameter '${address}'.`)
|
|
||||||
}
|
|
||||||
return `${parsed.substring(0, chars + 2)}...${parsed.substring(42 - chars)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// account is not optional
|
|
||||||
function getSigner(provider: JsonRpcProvider, account: string): JsonRpcSigner {
|
|
||||||
return provider.getSigner(account).connectUnchecked()
|
|
||||||
}
|
|
||||||
|
|
||||||
// account is optional
|
|
||||||
function getProviderOrSigner(provider: JsonRpcProvider, account?: string): JsonRpcProvider | JsonRpcSigner {
|
|
||||||
return account ? getSigner(provider, account) : provider
|
|
||||||
}
|
|
||||||
|
|
||||||
// account is optional
|
|
||||||
export function getContract(address: string, ABI: any, provider: JsonRpcProvider, account?: string): Contract {
|
|
||||||
if (!isAddress(address) || address === AddressZero) {
|
|
||||||
throw Error(`Invalid 'address' parameter '${address}'.`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Contract(address, ABI, getProviderOrSigner(provider, account) as any)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function escapeRegExp(string: string): string {
|
|
||||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user