Skip to content

Commit

Permalink
feat(holder-allocation): add new api (#392)
Browse files Browse the repository at this point in the history
* feat(holder-allocation): add new api

* style(holder-allocation): use ellipsis and match tag in frontend

* fix(xudt-allocation): wrong name

* feat(xudt-holder): add btc to list

* fix(holder-allocation): style

* fix(holder): fix for mobile
  • Loading branch information
Daryl-L authored Jul 5, 2024
1 parent 952e7b7 commit 3bf181d
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 90 deletions.
18 changes: 10 additions & 8 deletions src/models/Xudt/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { Script } from '../Script'

export interface XUDTHolderAllocation {
btcHolderCount: string
lockHashes: {
name: string
holderCount: string
codeHash: string
}[]
}

export interface XUDT {
addressesCount: string
createdAt: string
h24CkbTransactionsCount: string
issuerAddress: string
Expand All @@ -13,14 +23,6 @@ export interface XUDT {
typeScript: Script
udtType: 'xudt'
xudtTags?: string[]
holderAllocation?: {
ckbHoldersCount: string
btcHoldersCount: string
lockHoderAmount: {
lock: string
holderAmount: string
}[]
}
iconFile: string
operatorWebsite: string
email: string
Expand Down
2 changes: 2 additions & 0 deletions src/pages/Xudt/HolderAllocation.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
flex-direction: column;
align-items: center;
gap: 24px;
min-width: 397px;

@media (max-width: $mobileBreakPoint) {
min-width: 0;
align-items: flex-start;

p {
Expand Down
80 changes: 48 additions & 32 deletions src/pages/Xudt/HolderAllocation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,75 @@ import styles from './HolderAllocation.module.scss'
import { localeNumberString } from '../../utils/number'
import CloseIcon from '../../assets/modal_close.png'
import SimpleButton from '../../components/SimpleButton'
import { matchScript } from '../../utils/util'
import EllipsisMiddle from '../../components/EllipsisMiddle'

const HolderAllocation = ({
allocation,
ckbHolderAmount,
btcHolderAmount,
lockHoderAmount,
onClose,
}: {
allocation: Record<string, number>
ckbHolderAmount: string
btcHolderAmount: string
lockHoderAmount?: {
name: string
holderCount: string
codeHash: string
}[]
onClose: MouseEventHandler<HTMLDivElement>
}) => {
const [t] = useTranslation()
const total = Object.values(allocation).reduce((acc, cur) => acc + cur, 0)
const btc = +(allocation.BTC ?? 0)
const ckb = total - btc

return (
<div className={styles.holderAllocationContainer}>
<div className={styles.holderAllocationContent}>
<h2>{t('xudt.holder_allocation')}</h2>
<p>
{t('xudt.holder_allocation_description', {
ckb: localeNumberString(ckb),
btc: localeNumberString(btc),
ckb: ckbHolderAmount,
btc: localeNumberString(btcHolderAmount),
})}
</p>
<div className={styles.table}>
<table>
<thead>
<tr>
<td>
<div>{t('xudt.category')}</div>
</td>
<td>
<div>{t('xudt.count')}</div>
</td>
</tr>
</thead>
<tbody>
{Object.entries(allocation)
.sort((a, b) => b[1] - a[1])
.map(([label, count]) => {
return (
{lockHoderAmount && (
<div className={styles.table}>
<table>
<thead>
<tr>
<td>
<div>{t('xudt.lock_hash')}</div>
</td>
<td>
<div>{t('xudt.count')}</div>
</td>
</tr>
</thead>
<tbody>
{parseInt(btcHolderAmount, 10) > 0 && (
<tr>
<td>
<div>BTC</div>
</td>
<td>
<div>{localeNumberString(btcHolderAmount)}</div>
</td>
</tr>
)}
{lockHoderAmount
.sort((a, b) => +b.holderCount - +a.holderCount)
.map(amount => (
<tr>
<td>
<div>{label}</div>
<EllipsisMiddle>{matchScript(amount.codeHash)?.tag ?? amount.codeHash}</EllipsisMiddle>
</td>
<td>
<div>{localeNumberString(count)}</div>
<div>{localeNumberString(amount.holderCount)}</div>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
))}
</tbody>
</table>
</div>
)}
</div>
<SimpleButton onClick={onClose} className={styles.closeIcon}>
<img src={CloseIcon} alt="close icon" />
Expand Down
55 changes: 19 additions & 36 deletions src/pages/Xudt/UDTComp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,14 @@ import { SubmitTokenInfo, TokenInfo } from '../../components/SubmitTokenInfo'
import { useIsMobile } from '../../hooks'
import Script from '../../components/Script'
import { RawBtcRPC } from '../../services/ExplorerService'
import { XUDT } from '../../models/Xudt'
import { XUDT, XUDTHolderAllocation } from '../../models/Xudt'
import { getBtcTxList } from '../../services/ExplorerService/fetcher'
import { getHolderAllocation } from '../../services/MetricsService'
import XUDTTag from '../../components/XUDTTag'
import SimpleButton from '../../components/SimpleButton'
import SimpleModal from '../../components/Modal'
import HolderAllocation from './HolderAllocation'
import { ReactComponent as EditIcon } from '../../assets/edit.svg'
import XUDTTokenIcon from '../../assets/sudt_token.png'
import { IS_MAINNET } from '../../constants/common'

const IssuerContent: FC<{ address: string }> = ({ address }) => {
const { t } = useTranslation()
Expand Down Expand Up @@ -62,10 +60,12 @@ const IssuerContent: FC<{ address: string }> = ({ address }) => {
export const UDTOverviewCard = ({
typeHash,
xudt,
holderAllocation,
refetchUDT,
}: {
typeHash: string
xudt: XUDT | undefined
holderAllocation?: XUDTHolderAllocation
xudt?: XUDT
refetchUDT: () => void
}) => {
const { t } = useTranslation()
Expand Down Expand Up @@ -109,32 +109,8 @@ export const UDTOverviewCard = ({
},
)

const { data: holderAllocation = {}, isLoading: isHolderAllocationLoading } = useQuery({
queryKey: ['xudt-holder-allocation', typeHash],
queryFn: () =>
xudt
? getHolderAllocation({
code_hash: xudt.typeScript.codeHash,
hash_type: xudt.typeScript.hashType,
args: xudt.typeScript.args,
})
: ({} as Record<string, number>),
enabled: IS_MAINNET && !!xudt,
})

const holderCountFromBackend = xudt
? +(xudt.holderAllocation?.ckbHoldersCount ?? 0) + +(xudt.holderAllocation?.btcHoldersCount ?? 0)
: 0
const holderCountFromNode = Object.values(holderAllocation ?? {}).reduce((acc, cur) => acc + cur, 0)

const holderCount = IS_MAINNET ? holderCountFromNode : holderCountFromBackend

const allocationDisplay = IS_MAINNET
? holderAllocation
: {
BTC: +(xudt?.holderAllocation?.btcHoldersCount ?? 0),
others: +(xudt?.holderAllocation?.ckbHoldersCount ?? 0),
}
const ckbHolderAmount = holderAllocation?.lockHashes.reduce((acc, cur) => acc + +cur.holderCount, 0) ?? 0
const holderCount = holderAllocation ? ckbHolderAmount + +(holderAllocation?.btcHolderCount ?? 0) : 0

const items: CardCellInfo<'left' | 'right'>[] = [
{
Expand All @@ -148,14 +124,14 @@ export const UDTOverviewCard = ({
},
{
title: t('xudt.holders'),
content: xudt?.holderAllocation ? (
content: holderAllocation ? (
<SimpleButton
className={styles.holderAddressesButton}
onClick={() => {
setShowHolderAmountModal(true)
}}
>
{IS_MAINNET && isHolderAllocationLoading ? '-' : localeNumberString(holderCount)}
{localeNumberString(holderCount)}
</SimpleButton>
) : (
'-'
Expand Down Expand Up @@ -219,14 +195,21 @@ export const UDTOverviewCard = ({

<div className={styles.tags}>
{xudt?.xudtTags?.map(tag => (
<XUDTTag key={tag} tagName={tag} />
<XUDTTag tagName={tag} />
))}
</div>

<CardCellsLayout type="left-right" cells={items} borderTop />
<SimpleModal isShow={showHolderAmountModal} setIsShow={setShowHolderAmountModal}>
<HolderAllocation allocation={allocationDisplay} onClose={() => setShowHolderAmountModal(false)} />
</SimpleModal>
{holderAllocation && (
<SimpleModal isShow={showHolderAmountModal} setIsShow={setShowHolderAmountModal}>
<HolderAllocation
ckbHolderAmount={localeNumberString(ckbHolderAmount)}
btcHolderAmount={holderAllocation.btcHolderCount}
lockHoderAmount={holderAllocation.lockHashes}
onClose={() => setShowHolderAmountModal(false)}
/>
</SimpleModal>
)}

<SimpleButton className={styles.typeScriptController} onClick={toggleScriptDisplay}>
{isScriptDisplayed ? (
Expand Down
15 changes: 13 additions & 2 deletions src/pages/Xudt/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ export const Xudt = () => {
const { filter } = useSearchParams('filter')

const updateSearchParams = useUpdateSearchParams<'filter' | 'page'>()
const queryUDT = useQuery(['udt', typeHash], () => explorerService.api.fetchSimpleUDT(typeHash))

const queryXudt = useQuery(['xudt', typeHash], () => explorerService.api.fetchXudt(typeHash))
const xudt = queryXudt.data
const queryXudtHolderAllocation = useQuery(['xudt-holder-allocation', typeHash], () =>
explorerService.api.fetchXudtHolderAllocation(typeHash),
)
const holderAllocation = queryXudtHolderAllocation.data

const querySimpleUDTTransactions = useQuery(
['xudt-transactions', typeHash, currentPage, _pageSize, filter],
Expand Down Expand Up @@ -69,7 +72,15 @@ export const Xudt = () => {
return (
<Content>
<div className={classNames(styles.container, 'container')}>
<UDTOverviewCard typeHash={typeHash} xudt={xudt} refetchUDT={queryUDT.refetch} />
<UDTOverviewCard
typeHash={typeHash}
xudt={xudt}
holderAllocation={holderAllocation}
refetchUDT={() => {
queryXudt.refetch()
queryXudtHolderAllocation.refetch()
}}
/>

<div className={styles.udtTransactionTitlePanel}>
<div className={styles.udtTransactionContainer}>
Expand Down
10 changes: 2 additions & 8 deletions src/pages/Xudts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ const TokenInfo: FC<{ token: XUDT }> = ({ token }) => {
const { t } = useTranslation()

const symbol = token.symbol || `#${token.typeHash.substring(token.typeHash.length - 4)}`
const holderCount = token.holderAllocation
? +token.holderAllocation.btcHoldersCount + +token.holderAllocation.ckbHoldersCount
: 0

const fields: { name: string; value: ReactNode }[] = [
{
Expand All @@ -41,7 +38,7 @@ const TokenInfo: FC<{ token: XUDT }> = ({ token }) => {
},
{
name: t('xudt.unique_addresses'),
value: localeNumberString(holderCount),
value: localeNumberString(token.addressesCount),
},
{
name: t('xudt.created_time'),
Expand Down Expand Up @@ -203,10 +200,7 @@ const TokenTable: FC<{
</>
),
className: styles.colAddressCount,
render: (_, token) =>
token.holderAllocation
? localeNumberString(+token.holderAllocation.btcHoldersCount + +token.holderAllocation.ckbHoldersCount)
: 0,
render: (_, token) => localeNumberString(token.addressesCount),
},
{
title: (
Expand Down
4 changes: 3 additions & 1 deletion src/services/ExplorerService/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { Block } from '../../models/Block'
import { BtcTx, Transaction } from '../../models/Transaction'
import { Address, AddressType } from '../../models/Address'
import { OmigaInscriptionCollection, UDT } from '../../models/UDT'
import { XUDT } from '../../models/Xudt'
import { XUDT, XUDTHolderAllocation } from '../../models/Xudt'
import { HashType } from '../../constants/common'
import { Dob, getDobs } from '../DobsService'
import { isDob0 } from '../../utils/spore'
Expand Down Expand Up @@ -795,6 +795,8 @@ export const apiFetcher = {
},

fetchXudt: (typeHash: string) => v1GetUnwrapped<XUDT>(`/xudts/${typeHash}`),
fetchXudtHolderAllocation: (typeHash: string) =>
requesterV1.get(`/udts/${typeHash}/holder_allocation`).then(res => toCamelcase<XUDTHolderAllocation>(res.data)),

fetchXudts: (page: number, size: number, sort?: string, tags?: string) =>
v1GetUnwrappedPagedList<XUDT>(`/xudts`, {
Expand Down
10 changes: 7 additions & 3 deletions src/utils/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,18 @@ export const getContractHashTag = (script: Script): ContractHashTag | undefined
return contractHashTag
}

export const matchScript = (contractHash: string, hashType: string): ContractHashTag | undefined => {
export const matchScript = (contractHash: string, hashType?: string): ContractHashTag | undefined => {
if (isMainnet()) {
return MainnetContractHashTags.find(
scriptTag => scriptTag.codeHashes.find(codeHash => codeHash === contractHash) && scriptTag.hashType === hashType,
scriptTag =>
scriptTag.codeHashes.find(codeHash => codeHash === contractHash) &&
(!hashType || scriptTag.hashType === hashType),
)
}
return TestnetContractHashTags.find(
scriptTag => scriptTag.codeHashes.find(codeHash => codeHash === contractHash) && scriptTag.hashType === hashType,
scriptTag =>
scriptTag.codeHashes.find(codeHash => codeHash === contractHash) &&
(!hashType || scriptTag.hashType === hashType),
)
}

Expand Down

0 comments on commit 3bf181d

Please sign in to comment.