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

add token id erc-155 holders #1179

Merged
merged 1 commit into from
Sep 14, 2023
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
27 changes: 26 additions & 1 deletion mocks/tokens/tokenHolders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,40 @@ import type { TokenHolders } from 'types/api/token';

import { withName, withoutName } from 'mocks/address/address';

export const tokenHolders: TokenHolders = {
import { tokenInfoERC1155a, tokenInfoERC20a } from './tokenInfo';

export const tokenHoldersERC20: TokenHolders = {
items: [
{
address: withName,
token: tokenInfoERC20a,
value: '107014805905725000000',
},
{
address: withoutName,
token: tokenInfoERC20a,
value: '207014805905725000000',
},
],
next_page_params: {
value: '50',
items_count: 50,
},
};

export const tokenHoldersERC1155: TokenHolders = {
items: [
{
address: withName,
token: tokenInfoERC1155a,
value: '107014805905725000000',
token_id: '12345',
},
{
address: withoutName,
token: tokenInfoERC1155a,
value: '207014805905725000000',
token_id: '12345',
},
],
next_page_params: {
Expand Down
24 changes: 12 additions & 12 deletions mocks/tokens/tokenInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const tokenCounters: TokenCounters = {
transfers_count: '88282281',
};

export const tokenInfoERC20a: TokenInfo = {
export const tokenInfoERC20a: TokenInfo<'ERC-20'> = {
address: '0xb2a90505dc6680a7a695f7975d0d32EeF610f456',
circulating_market_cap: '117268489.23970924',
decimals: '18',
Expand All @@ -31,7 +31,7 @@ export const tokenInfoERC20a: TokenInfo = {
icon_url: 'https://example.com/token-icon.png',
};

export const tokenInfoERC20b: TokenInfo = {
export const tokenInfoERC20b: TokenInfo<'ERC-20'> = {
address: '0xc1116c98ba622a6218433fF90a2E40DEa482d7A7',
circulating_market_cap: '115060192.36105014',
decimals: '6',
Expand All @@ -44,7 +44,7 @@ export const tokenInfoERC20b: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC20c: TokenInfo = {
export const tokenInfoERC20c: TokenInfo<'ERC-20'> = {
address: '0xc1116c98ba622a6218433fF90a2E40DEa482d7A7',
circulating_market_cap: null,
decimals: '18',
Expand All @@ -57,7 +57,7 @@ export const tokenInfoERC20c: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC20d: TokenInfo = {
export const tokenInfoERC20d: TokenInfo<'ERC-20'> = {
address: '0xCc7bb2D219A0FC08033E130629C2B854b7bA9195',
circulating_market_cap: null,
decimals: '18',
Expand All @@ -70,7 +70,7 @@ export const tokenInfoERC20d: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC20LongSymbol: TokenInfo = {
export const tokenInfoERC20LongSymbol: TokenInfo<'ERC-20'> = {
address: '0xCc7bb2D219A0FC08033E130629C2B854b7bA9195',
circulating_market_cap: '112855875.75888918',
decimals: '18',
Expand All @@ -83,7 +83,7 @@ export const tokenInfoERC20LongSymbol: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC721a: TokenInfo = {
export const tokenInfoERC721a: TokenInfo<'ERC-721'> = {
address: '0xDe7cAc71E072FCBd4453E5FB3558C2684d1F88A0',
circulating_market_cap: null,
decimals: null,
Expand All @@ -96,7 +96,7 @@ export const tokenInfoERC721a: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC721b: TokenInfo = {
export const tokenInfoERC721b: TokenInfo<'ERC-721'> = {
address: '0xA8d5C7beEA8C9bB57f5fBa35fB638BF45550b11F',
circulating_market_cap: null,
decimals: null,
Expand All @@ -109,7 +109,7 @@ export const tokenInfoERC721b: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC721c: TokenInfo = {
export const tokenInfoERC721c: TokenInfo<'ERC-721'> = {
address: '0x47646F1d7dc4Dd2Db5a41D092e2Cf966e27A4992',
circulating_market_cap: null,
decimals: null,
Expand All @@ -122,7 +122,7 @@ export const tokenInfoERC721c: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC721LongSymbol: TokenInfo = {
export const tokenInfoERC721LongSymbol: TokenInfo<'ERC-721'> = {
address: '0x47646F1d7dc4Dd2Db5a41D092e2Cf966e27A4992',
circulating_market_cap: null,
decimals: null,
Expand All @@ -135,7 +135,7 @@ export const tokenInfoERC721LongSymbol: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC1155a: TokenInfo = {
export const tokenInfoERC1155a: TokenInfo<'ERC-1155'> = {
address: '0x4b333DEd10c7ca855EA2C8D4D90A0a8b73788c8e',
circulating_market_cap: null,
decimals: null,
Expand All @@ -148,7 +148,7 @@ export const tokenInfoERC1155a: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC1155b: TokenInfo = {
export const tokenInfoERC1155b: TokenInfo<'ERC-1155'> = {
address: '0xf4b71b179132ad457f6bcae2a55efa9e4b26eefc',
circulating_market_cap: null,
decimals: null,
Expand All @@ -161,7 +161,7 @@ export const tokenInfoERC1155b: TokenInfo = {
icon_url: null,
};

export const tokenInfoERC1155WithoutName: TokenInfo = {
export const tokenInfoERC1155WithoutName: TokenInfo<'ERC-1155'> = {
address: '0x4b333DEd10c7ca855EA2C8D4D90A0a8b73788c8e',
circulating_market_cap: null,
decimals: null,
Expand Down
10 changes: 9 additions & 1 deletion stubs/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,16 @@ export const TOKEN_COUNTERS: TokenCounters = {
transfers_count: '123456',
};

export const TOKEN_HOLDER: TokenHolder = {
export const TOKEN_HOLDER_ERC_20: TokenHolder = {
address: ADDRESS_PARAMS,
token: TOKEN_INFO_ERC_20,
value: '1021378038331138520',
};

export const TOKEN_HOLDER_ERC_1155: TokenHolder = {
address: ADDRESS_PARAMS,
token: TOKEN_INFO_ERC_1155,
token_id: '12345',
value: '1021378038331138520',
};

Expand Down
13 changes: 12 additions & 1 deletion types/api/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,22 @@ export interface TokenHolders {
next_page_params: TokenHoldersPagination | null;
}

export type TokenHolder = {
export type TokenHolder = TokenHolderERC20ERC721 | TokenHolderERC1155;

export type TokenHolderBase = {
address: AddressParam;
value: string;
}

export type TokenHolderERC20ERC721 = TokenHolderBase & {
token: TokenInfo<'ERC-20'> | TokenInfo<'ERC-721'>;
}

export type TokenHolderERC1155 = TokenHolderBase & {
token: TokenInfo<'ERC-1155'>;
token_id: string;
}

export type TokenHoldersPagination = {
items_count: number;
value: string;
Expand Down
3 changes: 2 additions & 1 deletion ui/pages/Token.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ const TokenPageContent = () => {
scrollRef,
options: {
enabled: Boolean(hashString && tab === 'holders' && hasData),
placeholderData: generateListStub<'token_holders'>(tokenStubs.TOKEN_HOLDER, 50, { next_page_params: null }),
placeholderData: generateListStub<'token_holders'>(
tokenQuery.data?.type === 'ERC-1155' ? tokenStubs.TOKEN_HOLDER_ERC_1155 : tokenStubs.TOKEN_HOLDER_ERC_20, 50, { next_page_params: null }),
},
});

Expand Down
3 changes: 2 additions & 1 deletion ui/pages/TokenInstance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ const TokenInstanceContent = () => {
scrollRef,
options: {
enabled: Boolean(hash && tab === 'holders' && shouldFetchHolders),
placeholderData: generateListStub<'token_instance_holders'>(tokenStubs.TOKEN_HOLDER, 10, { next_page_params: null }),
placeholderData: generateListStub<'token_instance_holders'>(
tokenInstanceQuery.data?.token.type === 'ERC-1155' ? tokenStubs.TOKEN_HOLDER_ERC_1155 : tokenStubs.TOKEN_HOLDER_ERC_20, 10, { next_page_params: null }),
},
});

Expand Down
18 changes: 14 additions & 4 deletions ui/token/TokenHolders/TokenHoldersList.pw.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import { test, expect, devices } from '@playwright/experimental-ct-react';
import React from 'react';

import { tokenHolders } from 'mocks/tokens/tokenHolders';
import { tokenInfo } from 'mocks/tokens/tokenInfo';
import { tokenHoldersERC20, tokenHoldersERC1155 } from 'mocks/tokens/tokenHolders';
import { tokenInfo, tokenInfoERC1155a } from 'mocks/tokens/tokenInfo';
import TestApp from 'playwright/TestApp';

import TokenHoldersList from './TokenHoldersList';

test.use({ viewport: devices['iPhone 13 Pro'].viewport });

test('base view', async({ mount }) => {
test('base view without IDs', async({ mount }) => {
const component = await mount(
<TestApp>
<TokenHoldersList data={ tokenHolders.items } token={ tokenInfo }/>
<TokenHoldersList data={ tokenHoldersERC20.items } token={ tokenInfo }/>
</TestApp>,
);

await expect(component).toHaveScreenshot();
});

test('base view with IDs', async({ mount }) => {
const component = await mount(
<TestApp>
<TokenHoldersList data={ tokenHoldersERC1155.items } token={ tokenInfoERC1155a }/>
</TestApp>,
);

Expand Down
60 changes: 40 additions & 20 deletions ui/token/TokenHolders/TokenHoldersListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Box, Flex, Skeleton } from '@chakra-ui/react';
import { Skeleton } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import React from 'react';

import type { TokenHolder, TokenInfo } from 'types/api/token';

import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import ListItemMobileGrid from 'ui/shared/ListItemMobile/ListItemMobileGrid';
import Utilization from 'ui/shared/Utilization/Utilization';

interface Props {
Expand All @@ -18,30 +18,50 @@ const TokenHoldersListItem = ({ holder, token, isLoading }: Props) => {
const quantity = BigNumber(holder.value).div(BigNumber(10 ** Number(token.decimals))).dp(6).toFormat();

return (
<ListItemMobile rowGap={ 3 }>
<AddressEntity
address={ holder.address }
isLoading={ isLoading }
fontWeight="700"
maxW="100%"
/>
<Flex justifyContent="space-between" alignItems="center" width="100%">
<Skeleton isLoaded={ !isLoading } display="inline-block" width="100%">
<Box as="span" wordBreak="break-word" mr={ 6 }>
{ quantity }
</Box>
{ token.total_supply && (
<ListItemMobileGrid.Container>
<ListItemMobileGrid.Label isLoading={ isLoading }>Address</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<AddressEntity
address={ holder.address }
isLoading={ isLoading }
fontWeight="700"
maxW="100%"
/>
</ListItemMobileGrid.Value>

{ token.type === 'ERC-1155' && 'token_id' in holder && (
<>
<ListItemMobileGrid.Label isLoading={ isLoading }>ID#</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<Skeleton isLoaded={ !isLoading } display="inline-block">
{ holder.token_id }
</Skeleton>
</ListItemMobileGrid.Value>
</>
) }

<ListItemMobileGrid.Label isLoading={ isLoading }>Quantity</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<Skeleton isLoaded={ !isLoading } display="inline-block">
{ quantity }
</Skeleton>
</ListItemMobileGrid.Value>

{ token.total_supply && (
<>
<ListItemMobileGrid.Label isLoading={ isLoading }>Percentage</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value>
<Utilization
value={ BigNumber(holder.value).div(BigNumber(token.total_supply)).dp(4).toNumber() }
colorScheme="green"
isLoading={ isLoading }
display="inline-flex"
float="right"
/>
) }
</Skeleton>
</Flex>
</ListItemMobile>
</ListItemMobileGrid.Value>
</>
) }

</ListItemMobileGrid.Container>
);
};

Expand Down
19 changes: 15 additions & 4 deletions ui/token/TokenHolders/TokenHoldersTable.pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,28 @@ import { Box } from '@chakra-ui/react';
import { test, expect } from '@playwright/experimental-ct-react';
import React from 'react';

import { tokenHolders } from 'mocks/tokens/tokenHolders';
import { tokenInfo } from 'mocks/tokens/tokenInfo';
import { tokenHoldersERC20, tokenHoldersERC1155 } from 'mocks/tokens/tokenHolders';
import { tokenInfo, tokenInfoERC1155a } from 'mocks/tokens/tokenInfo';
import TestApp from 'playwright/TestApp';

import TokenHoldersTable from './TokenHoldersTable';

test('base view', async({ mount }) => {
test('base view without IDs', async({ mount }) => {
const component = await mount(
<TestApp>
<Box h="128px"/>
<TokenHoldersTable data={ tokenHolders.items } token={ tokenInfo } top={ 80 }/>
<TokenHoldersTable data={ tokenHoldersERC20.items } token={ tokenInfo } top={ 80 }/>
</TestApp>,
);

await expect(component).toHaveScreenshot();
});

test('base view with IDs', async({ mount }) => {
const component = await mount(
<TestApp>
<Box h="128px"/>
<TokenHoldersTable data={ tokenHoldersERC1155.items } token={ tokenInfoERC1155a } top={ 80 }/>
</TestApp>,
);

Expand Down
1 change: 1 addition & 0 deletions ui/token/TokenHolders/TokenHoldersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const TokenHoldersTable = ({ data, token, top, isLoading }: Props) => {
<Thead top={ top }>
<Tr>
<Th>Holder</Th>
{ token.type === 'ERC-1155' && <Th>ID#</Th> }
<Th isNumeric>Quantity</Th>
{ token.total_supply && <Th isNumeric width="175px">Percentage</Th> }
</Tr>
Expand Down
7 changes: 7 additions & 0 deletions ui/token/TokenHolders/TokenHoldersTableItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ const TokenTransferTableItem = ({ holder, token, isLoading }: Props) => {
fontWeight="700"
/>
</Td>
{ token.type === 'ERC-1155' && 'token_id' in holder && (
<Td verticalAlign="middle">
<Skeleton isLoaded={ !isLoading } display="inline-block">
{ 'token_id' in holder && holder.token_id }
</Skeleton>
</Td>
) }
<Td verticalAlign="middle" isNumeric>
<Skeleton isLoaded={ !isLoading } display="inline-block" wordBreak="break-word">
{ quantity }
Expand Down
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading