Commit a9cbaf92 authored by isstuev's avatar isstuev

Add support of ERC-404 type

parent fd7d9e2f
...@@ -22,6 +22,7 @@ SocketMessage.AddressTokenBalance | ...@@ -22,6 +22,7 @@ SocketMessage.AddressTokenBalance |
SocketMessage.AddressTokenBalancesErc20 | SocketMessage.AddressTokenBalancesErc20 |
SocketMessage.AddressTokenBalancesErc721 | SocketMessage.AddressTokenBalancesErc721 |
SocketMessage.AddressTokenBalancesErc1155 | SocketMessage.AddressTokenBalancesErc1155 |
SocketMessage.AddressTokenBalancesErc404 |
SocketMessage.AddressCoinBalance | SocketMessage.AddressCoinBalance |
SocketMessage.AddressTxs | SocketMessage.AddressTxs |
SocketMessage.AddressTxsPending | SocketMessage.AddressTxsPending |
...@@ -57,6 +58,7 @@ export namespace SocketMessage { ...@@ -57,6 +58,7 @@ export namespace SocketMessage {
export type AddressTokenBalancesErc20 = SocketMessageParamsGeneric<'updated_token_balances_erc_20', AddressTokensBalancesSocketMessage>; export type AddressTokenBalancesErc20 = SocketMessageParamsGeneric<'updated_token_balances_erc_20', AddressTokensBalancesSocketMessage>;
export type AddressTokenBalancesErc721 = SocketMessageParamsGeneric<'updated_token_balances_erc_721', AddressTokensBalancesSocketMessage>; export type AddressTokenBalancesErc721 = SocketMessageParamsGeneric<'updated_token_balances_erc_721', AddressTokensBalancesSocketMessage>;
export type AddressTokenBalancesErc1155 = SocketMessageParamsGeneric<'updated_token_balances_erc_1155', AddressTokensBalancesSocketMessage>; export type AddressTokenBalancesErc1155 = SocketMessageParamsGeneric<'updated_token_balances_erc_1155', AddressTokensBalancesSocketMessage>;
export type AddressTokenBalancesErc404 = SocketMessageParamsGeneric<'updated_token_balances_erc_404', AddressTokensBalancesSocketMessage>;
export type AddressCoinBalance = SocketMessageParamsGeneric<'coin_balance', { coin_balance: AddressCoinBalanceHistoryItem }>; export type AddressCoinBalance = SocketMessageParamsGeneric<'coin_balance', { coin_balance: AddressCoinBalanceHistoryItem }>;
export type AddressTxs = SocketMessageParamsGeneric<'transaction', { transactions: Array<Transaction> }>; export type AddressTxs = SocketMessageParamsGeneric<'transaction', { transactions: Array<Transaction> }>;
export type AddressTxsPending = SocketMessageParamsGeneric<'pending_transaction', { transactions: Array<Transaction> }>; export type AddressTxsPending = SocketMessageParamsGeneric<'pending_transaction', { transactions: Array<Transaction> }>;
......
...@@ -3,6 +3,7 @@ import type { NFTTokenType, TokenType } from 'types/api/token'; ...@@ -3,6 +3,7 @@ import type { NFTTokenType, TokenType } from 'types/api/token';
export const NFT_TOKEN_TYPES: Array<{ title: string; id: NFTTokenType }> = [ export const NFT_TOKEN_TYPES: Array<{ title: string; id: NFTTokenType }> = [
{ title: 'ERC-721', id: 'ERC-721' }, { title: 'ERC-721', id: 'ERC-721' },
{ title: 'ERC-1155', id: 'ERC-1155' }, { title: 'ERC-1155', id: 'ERC-1155' },
{ title: 'ERC-404', id: 'ERC-404' },
]; ];
export const TOKEN_TYPES: Array<{ title: string; id: TokenType }> = [ export const TOKEN_TYPES: Array<{ title: string; id: TokenType }> = [
......
...@@ -105,6 +105,20 @@ export const erc1155LongId: AddressTokenBalance = { ...@@ -105,6 +105,20 @@ export const erc1155LongId: AddressTokenBalance = {
value: '42', value: '42',
}; };
export const erc404a: AddressTokenBalance = {
token: tokens.tokenInfoERC404,
token_id: '42',
token_instance: tokenInstance.base,
value: '240000000000000',
};
export const erc404b: AddressTokenBalance = {
token: tokens.tokenInfoERC404,
token_instance: null,
value: '11',
token_id: null,
};
export const erc20List = { export const erc20List = {
items: [ items: [
erc20a, erc20a,
...@@ -129,6 +143,13 @@ export const erc1155List = { ...@@ -129,6 +143,13 @@ export const erc1155List = {
], ],
}; };
export const erc404List = {
items: [
erc404a,
erc404b,
],
};
export const nfts: AddressNFTsResponse = { export const nfts: AddressNFTsResponse = {
items: [ items: [
{ {
...@@ -143,6 +164,12 @@ export const nfts: AddressNFTsResponse = { ...@@ -143,6 +164,12 @@ export const nfts: AddressNFTsResponse = {
token_type: 'ERC-721', token_type: 'ERC-721',
value: '1', value: '1',
}, },
{
...tokenInstance.unique,
token: tokens.tokenInfoERC404,
token_type: 'ERC-404',
value: '11000',
},
], ],
next_page_params: null, next_page_params: null,
}; };
......
...@@ -174,6 +174,19 @@ export const tokenInfoERC1155WithoutName: TokenInfo<'ERC-1155'> = { ...@@ -174,6 +174,19 @@ export const tokenInfoERC1155WithoutName: TokenInfo<'ERC-1155'> = {
icon_url: null, icon_url: null,
}; };
export const tokenInfoERC404: TokenInfo<'ERC-404'> = {
address: '0xB5C457dDB4cE3312a6C5a2b056a1652bd542a208',
circulating_market_cap: '0.0',
decimals: '18',
exchange_rate: '1484.13',
holders: '81',
icon_url: null,
name: 'OMNI404',
symbol: 'O404',
total_supply: '6482275000000000000',
type: 'ERC-404',
};
export const bridgedTokenA: TokenInfo<'ERC-20'> = { export const bridgedTokenA: TokenInfo<'ERC-20'> = {
...tokenInfoERC20a, ...tokenInfoERC20a,
is_bridged: true, is_bridged: true,
......
...@@ -170,6 +170,63 @@ export const erc1155D: TokenTransfer = { ...@@ -170,6 +170,63 @@ export const erc1155D: TokenTransfer = {
total: { token_id: '456', value: '42', decimals: null }, total: { token_id: '456', value: '42', decimals: null },
}; };
export const erc404A: TokenTransfer = {
from: {
hash: '0x0000000000000000000000000000000000000000',
implementation_name: null,
is_contract: false,
is_verified: false,
name: null,
private_tags: [],
public_tags: [],
watchlist_names: [],
ens_domain_name: null,
},
to: {
hash: '0xBb36c792B9B45Aaf8b848A1392B0d6559202729E',
implementation_name: null,
is_contract: false,
is_verified: false,
name: null,
private_tags: [],
public_tags: [],
watchlist_names: [],
ens_domain_name: 'kitty.kitty.cat.eth',
},
token: {
address: '0xF56b7693E4212C584de4a83117f805B8E89224CB',
circulating_market_cap: null,
decimals: null,
exchange_rate: null,
holders: '1',
name: null,
symbol: 'MY_SYMBOL_IS_VERY_LONG',
type: 'ERC-404',
total_supply: '0',
icon_url: null,
},
total: {
value: '42000000000000000000000000',
decimals: '18',
},
tx_hash: '0x05d6589367633c032d757a69c5fb16c0e33e3994b0d9d1483f82aeee1f05d746',
type: 'token_transfer',
method: 'swap',
timestamp: '2022-10-10T14:34:30.000000Z',
block_hash: '1',
log_index: '1',
};
export const erc404B: TokenTransfer = {
...erc404A,
token: {
...erc404A.token,
name: 'SastanaNFT',
symbol: 'ipfs://QmUpFUfVKDCWeZQk5pvDFUxnpQP9N6eLSHhNUy49T1JVtY',
},
total: { token_id: '4625304364899952' },
};
export const mixTokens: TokenTransferResponse = { export const mixTokens: TokenTransferResponse = {
items: [ items: [
erc20, erc20,
...@@ -178,6 +235,8 @@ export const mixTokens: TokenTransferResponse = { ...@@ -178,6 +235,8 @@ export const mixTokens: TokenTransferResponse = {
erc1155B, erc1155B,
erc1155C, erc1155C,
erc1155D, erc1155D,
erc404A,
erc404B,
], ],
next_page_params: null, next_page_params: null,
}; };
...@@ -127,6 +127,8 @@ export const withTokenTransfer: Transaction = { ...@@ -127,6 +127,8 @@ export const withTokenTransfer: Transaction = {
tokenTransferMock.erc1155B, tokenTransferMock.erc1155B,
tokenTransferMock.erc1155C, tokenTransferMock.erc1155C,
tokenTransferMock.erc1155D, tokenTransferMock.erc1155D,
tokenTransferMock.erc404A,
tokenTransferMock.erc404B,
], ],
token_transfers_overflow: true, token_transfers_overflow: true,
tx_types: [ tx_types: [
......
...@@ -62,6 +62,7 @@ export function sendMessage(socket: WebSocket, channel: Channel, msg: 'token_bal ...@@ -62,6 +62,7 @@ export function sendMessage(socket: WebSocket, channel: Channel, msg: 'token_bal
export function sendMessage(socket: WebSocket, channel: Channel, msg: 'updated_token_balances_erc_20', payload: AddressTokensBalancesSocketMessage): void; export function sendMessage(socket: WebSocket, channel: Channel, msg: 'updated_token_balances_erc_20', payload: AddressTokensBalancesSocketMessage): void;
export function sendMessage(socket: WebSocket, channel: Channel, msg: 'updated_token_balances_erc_721', payload: AddressTokensBalancesSocketMessage): void; export function sendMessage(socket: WebSocket, channel: Channel, msg: 'updated_token_balances_erc_721', payload: AddressTokensBalancesSocketMessage): void;
export function sendMessage(socket: WebSocket, channel: Channel, msg: 'updated_token_balances_erc_1155', payload: AddressTokensBalancesSocketMessage): void; export function sendMessage(socket: WebSocket, channel: Channel, msg: 'updated_token_balances_erc_1155', payload: AddressTokensBalancesSocketMessage): void;
export function sendMessage(socket: WebSocket, channel: Channel, msg: 'updated_token_balances_erc_404', payload: AddressTokensBalancesSocketMessage): void;
export function sendMessage(socket: WebSocket, channel: Channel, msg: 'transaction', payload: { transaction: number }): void; export function sendMessage(socket: WebSocket, channel: Channel, msg: 'transaction', payload: { transaction: number }): void;
export function sendMessage(socket: WebSocket, channel: Channel, msg: 'transaction', payload: { transactions: Array<Transaction> }): void; export function sendMessage(socket: WebSocket, channel: Channel, msg: 'transaction', payload: { transactions: Array<Transaction> }): void;
export function sendMessage(socket: WebSocket, channel: Channel, msg: 'pending_transaction', payload: { pending_transaction: number }): void; export function sendMessage(socket: WebSocket, channel: Channel, msg: 'pending_transaction', payload: { pending_transaction: number }): void;
......
...@@ -10,7 +10,7 @@ import type { ...@@ -10,7 +10,7 @@ import type {
import type { AddressesItem } from 'types/api/addresses'; import type { AddressesItem } from 'types/api/addresses';
import { ADDRESS_HASH } from './addressParams'; import { ADDRESS_HASH } from './addressParams';
import { TOKEN_INFO_ERC_1155, TOKEN_INFO_ERC_20, TOKEN_INFO_ERC_721, TOKEN_INSTANCE } from './token'; import { TOKEN_INFO_ERC_1155, TOKEN_INFO_ERC_20, TOKEN_INFO_ERC_721, TOKEN_INFO_ERC_404, TOKEN_INSTANCE } from './token';
import { TX_HASH } from './tx'; import { TX_HASH } from './tx';
export const ADDRESS_INFO: Address = { export const ADDRESS_INFO: Address = {
...@@ -104,6 +104,13 @@ export const ADDRESS_NFT_1155: AddressNFT = { ...@@ -104,6 +104,13 @@ export const ADDRESS_NFT_1155: AddressNFT = {
...TOKEN_INSTANCE, ...TOKEN_INSTANCE,
}; };
export const ADDRESS_NFT_404: AddressNFT = {
token_type: 'ERC-404',
token: TOKEN_INFO_ERC_404,
value: '10',
...TOKEN_INSTANCE,
};
export const ADDRESS_COLLECTION: AddressCollection = { export const ADDRESS_COLLECTION: AddressCollection = {
token: TOKEN_INFO_ERC_1155, token: TOKEN_INFO_ERC_1155,
amount: '4', amount: '4',
......
import type { TokenCounters, TokenHolder, TokenInfo, TokenInstance, TokenType } from 'types/api/token'; import type {
TokenCounters,
TokenHolder,
TokenHolders,
TokenHoldersPagination,
TokenInfo,
TokenInstance,
TokenType,
} from 'types/api/token';
import type { TokenInstanceTransferPagination, TokenInstanceTransferResponse } from 'types/api/tokens';
import type { TokenTransfer, TokenTransferPagination, TokenTransferResponse } from 'types/api/tokenTransfer'; import type { TokenTransfer, TokenTransferPagination, TokenTransferResponse } from 'types/api/tokenTransfer';
import { ADDRESS_PARAMS, ADDRESS_HASH } from './addressParams'; import { ADDRESS_PARAMS, ADDRESS_HASH } from './addressParams';
...@@ -31,6 +40,12 @@ export const TOKEN_INFO_ERC_1155: TokenInfo<'ERC-1155'> = { ...@@ -31,6 +40,12 @@ export const TOKEN_INFO_ERC_1155: TokenInfo<'ERC-1155'> = {
type: 'ERC-1155', type: 'ERC-1155',
}; };
export const TOKEN_INFO_ERC_404: TokenInfo<'ERC-404'> = {
...TOKEN_INFO_ERC_20,
circulating_market_cap: null,
type: 'ERC-404',
};
export const TOKEN_COUNTERS: TokenCounters = { export const TOKEN_COUNTERS: TokenCounters = {
token_holders_count: '123456', token_holders_count: '123456',
transfers_count: '123456', transfers_count: '123456',
...@@ -47,6 +62,32 @@ export const TOKEN_HOLDER_ERC_1155: TokenHolder = { ...@@ -47,6 +62,32 @@ export const TOKEN_HOLDER_ERC_1155: TokenHolder = {
value: '1021378038331138520', value: '1021378038331138520',
}; };
export const getTokenHoldersStub = (type?: TokenType, pagination: TokenHoldersPagination | null = null): TokenHolders => {
switch (type) {
case 'ERC-721':
return generateListStub<'token_holders'>(TOKEN_HOLDER_ERC_20, 50, { next_page_params: pagination });
case 'ERC-1155':
return generateListStub<'token_holders'>(TOKEN_HOLDER_ERC_1155, 50, { next_page_params: pagination });
case 'ERC-404':
return generateListStub<'token_holders'>(TOKEN_HOLDER_ERC_1155, 50, { next_page_params: pagination });
default:
return generateListStub<'token_holders'>(TOKEN_HOLDER_ERC_20, 50, { next_page_params: pagination });
}
};
export const getTokenInstanceHoldersStub = (type?: TokenType, pagination: TokenHoldersPagination | null = null): TokenHolders => {
switch (type) {
case 'ERC-721':
return generateListStub<'token_instance_holders'>(TOKEN_HOLDER_ERC_20, 10, { next_page_params: pagination });
case 'ERC-1155':
return generateListStub<'token_instance_holders'>(TOKEN_HOLDER_ERC_1155, 10, { next_page_params: pagination });
case 'ERC-404':
return generateListStub<'token_instance_holders'>(TOKEN_HOLDER_ERC_1155, 10, { next_page_params: pagination });
default:
return generateListStub<'token_instance_holders'>(TOKEN_HOLDER_ERC_20, 10, { next_page_params: pagination });
}
};
export const TOKEN_TRANSFER_ERC_20: TokenTransfer = { export const TOKEN_TRANSFER_ERC_20: TokenTransfer = {
block_hash: BLOCK_HASH, block_hash: BLOCK_HASH,
from: ADDRESS_PARAMS, from: ADDRESS_PARAMS,
...@@ -81,17 +122,42 @@ export const TOKEN_TRANSFER_ERC_1155: TokenTransfer = { ...@@ -81,17 +122,42 @@ export const TOKEN_TRANSFER_ERC_1155: TokenTransfer = {
token: TOKEN_INFO_ERC_1155, token: TOKEN_INFO_ERC_1155,
}; };
export const TOKEN_TRANSFER_ERC_404: TokenTransfer = {
...TOKEN_TRANSFER_ERC_20,
total: {
token_id: '35870',
value: '123',
decimals: '18',
},
token: TOKEN_INFO_ERC_404,
};
export const getTokenTransfersStub = (type?: TokenType, pagination: TokenTransferPagination | null = null): TokenTransferResponse => { export const getTokenTransfersStub = (type?: TokenType, pagination: TokenTransferPagination | null = null): TokenTransferResponse => {
switch (type) { switch (type) {
case 'ERC-721': case 'ERC-721':
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_721, 50, { next_page_params: pagination }); return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_721, 50, { next_page_params: pagination });
case 'ERC-1155': case 'ERC-1155':
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_1155, 50, { next_page_params: pagination }); return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_1155, 50, { next_page_params: pagination });
case 'ERC-404':
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_404, 50, { next_page_params: pagination });
default: default:
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_20, 50, { next_page_params: pagination }); return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_20, 50, { next_page_params: pagination });
} }
}; };
export const getTokenInstanceTransfersStub = (type?: TokenType, pagination: TokenInstanceTransferPagination | null = null): TokenInstanceTransferResponse => {
switch (type) {
case 'ERC-721':
return generateListStub<'token_instance_transfers'>(TOKEN_TRANSFER_ERC_721, 10, { next_page_params: pagination });
case 'ERC-1155':
return generateListStub<'token_instance_transfers'>(TOKEN_TRANSFER_ERC_1155, 10, { next_page_params: pagination });
case 'ERC-404':
return generateListStub<'token_instance_transfers'>(TOKEN_TRANSFER_ERC_404, 10, { next_page_params: pagination });
default:
return generateListStub<'token_instance_transfers'>(TOKEN_TRANSFER_ERC_20, 10, { next_page_params: pagination });
}
};
export const TOKEN_INSTANCE: TokenInstance = { export const TOKEN_INSTANCE: TokenInstance = {
animation_url: null, animation_url: null,
external_app_url: 'https://vipsland.com/nft/collections/genesis/188882', external_app_url: 'https://vipsland.com/nft/collections/genesis/188882',
......
import type { TokenInfoApplication } from './account'; import type { TokenInfoApplication } from './account';
import type { AddressParam } from './addressParams'; import type { AddressParam } from './addressParams';
export type NFTTokenType = 'ERC-721' | 'ERC-1155'; export type NFTTokenType = 'ERC-721' | 'ERC-1155' | 'ERC-404';
export type TokenType = 'ERC-20' | NFTTokenType; export type TokenType = 'ERC-20' | NFTTokenType;
export interface TokenInfo<T extends TokenType = TokenType> { export interface TokenInfo<T extends TokenType = TokenType> {
......
...@@ -16,6 +16,13 @@ export type Erc1155TotalPayload = { ...@@ -16,6 +16,13 @@ export type Erc1155TotalPayload = {
token_id: string | null; token_id: string | null;
} }
export type Erc404TotalPayload = {
decimals: string | null;
value: string | null;
} | {
token_id: string | null;
};
export type TokenTransfer = ( export type TokenTransfer = (
{ {
token: TokenInfo<'ERC-20'>; token: TokenInfo<'ERC-20'>;
...@@ -28,6 +35,10 @@ export type TokenTransfer = ( ...@@ -28,6 +35,10 @@ export type TokenTransfer = (
{ {
token: TokenInfo<'ERC-1155'>; token: TokenInfo<'ERC-1155'>;
total: Erc1155TotalPayload; total: Erc1155TotalPayload;
} |
{
token: TokenInfo<'ERC-404'>;
total: Erc404TotalPayload;
} }
) & TokenTransferBase ) & TokenTransferBase
......
...@@ -41,6 +41,13 @@ export interface TxStateChangeTokenErc1155 { ...@@ -41,6 +41,13 @@ export interface TxStateChangeTokenErc1155 {
token_id: string; token_id: string;
} }
export interface TxStateChangeTokenErc404 {
type: 'token';
token: TokenInfo<'ERC-404'>;
change: string;
token_id: string;
}
export type TxStateChanges = { export type TxStateChanges = {
items: Array<TxStateChange>; items: Array<TxStateChange>;
next_page_params: { next_page_params: {
......
...@@ -20,6 +20,7 @@ const API_URL_COUNTERS = buildApiUrl('address_counters', { hash: ADDRESS_HASH }) ...@@ -20,6 +20,7 @@ const API_URL_COUNTERS = buildApiUrl('address_counters', { hash: ADDRESS_HASH })
const API_URL_TOKENS_ERC20 = buildApiUrl('address_tokens', { hash: ADDRESS_HASH }) + '?type=ERC-20'; const API_URL_TOKENS_ERC20 = buildApiUrl('address_tokens', { hash: ADDRESS_HASH }) + '?type=ERC-20';
const API_URL_TOKENS_ERC721 = buildApiUrl('address_tokens', { hash: ADDRESS_HASH }) + '?type=ERC-721'; const API_URL_TOKENS_ERC721 = buildApiUrl('address_tokens', { hash: ADDRESS_HASH }) + '?type=ERC-721';
const API_URL_TOKENS_ER1155 = buildApiUrl('address_tokens', { hash: ADDRESS_HASH }) + '?type=ERC-1155'; const API_URL_TOKENS_ER1155 = buildApiUrl('address_tokens', { hash: ADDRESS_HASH }) + '?type=ERC-1155';
const API_URL_TOKENS_ERC404 = buildApiUrl('address_tokens', { hash: ADDRESS_HASH }) + '?type=ERC-404';
const hooksConfig = { const hooksConfig = {
router: { router: {
query: { hash: ADDRESS_HASH }, query: { hash: ADDRESS_HASH },
...@@ -70,6 +71,10 @@ test('token', async({ mount, page }) => { ...@@ -70,6 +71,10 @@ test('token', async({ mount, page }) => {
status: 200, status: 200,
body: JSON.stringify(tokensMock.erc1155List), body: JSON.stringify(tokensMock.erc1155List),
}), { times: 1 }); }), { times: 1 });
await page.route(API_URL_TOKENS_ERC404, async(route) => route.fulfill({
status: 200,
body: JSON.stringify(tokensMock.erc404List),
}), { times: 1 });
await page.evaluate(() => { await page.evaluate(() => {
window.ethereum = { window.ethereum = {
......
...@@ -37,6 +37,10 @@ const test = base.extend({ ...@@ -37,6 +37,10 @@ const test = base.extend({
items: [ tokensMock.erc1155a, tokensMock.erc1155b ], items: [ tokensMock.erc1155a, tokensMock.erc1155b ],
next_page_params: nextPageParams, next_page_params: nextPageParams,
}; };
const response404 = {
items: [ tokensMock.erc404a, tokensMock.erc404b ],
next_page_params: nextPageParams,
};
await page.route(API_URL_ADDRESS, (route) => route.fulfill({ await page.route(API_URL_ADDRESS, (route) => route.fulfill({
status: 200, status: 200,
...@@ -54,6 +58,10 @@ const test = base.extend({ ...@@ -54,6 +58,10 @@ const test = base.extend({
status: 200, status: 200,
body: JSON.stringify(response1155), body: JSON.stringify(response1155),
})); }));
await page.route(API_URL_TOKENS + '?type=ERC-404', (route) => route.fulfill({
status: 200,
body: JSON.stringify(response404),
}));
await page.route(API_URL_NFT, (route) => route.fulfill({ await page.route(API_URL_NFT, (route) => route.fulfill({
status: 200, status: 200,
body: JSON.stringify(tokensMock.nfts), body: JSON.stringify(tokensMock.nfts),
...@@ -217,6 +225,10 @@ base.describe('update balances via socket', () => { ...@@ -217,6 +225,10 @@ base.describe('update balances via socket', () => {
items: [ tokensMock.erc1155a ], items: [ tokensMock.erc1155a ],
next_page_params: null, next_page_params: null,
}; };
const response404 = {
items: [ tokensMock.erc404a ],
next_page_params: null,
};
await page.route(API_URL_ADDRESS, (route) => route.fulfill({ await page.route(API_URL_ADDRESS, (route) => route.fulfill({
status: 200, status: 200,
...@@ -234,6 +246,10 @@ base.describe('update balances via socket', () => { ...@@ -234,6 +246,10 @@ base.describe('update balances via socket', () => {
status: 200, status: 200,
body: JSON.stringify(response1155), body: JSON.stringify(response1155),
})); }));
await page.route(API_URL_TOKENS + '?type=ERC-404', (route) => route.fulfill({
status: 200,
body: JSON.stringify(response404),
}));
const component = await mount( const component = await mount(
<TestApp withSocket> <TestApp withSocket>
...@@ -248,6 +264,7 @@ base.describe('update balances via socket', () => { ...@@ -248,6 +264,7 @@ base.describe('update balances via socket', () => {
await page.waitForResponse(API_URL_TOKENS + '?type=ERC-20'); await page.waitForResponse(API_URL_TOKENS + '?type=ERC-20');
await page.waitForResponse(API_URL_TOKENS + '?type=ERC-721'); await page.waitForResponse(API_URL_TOKENS + '?type=ERC-721');
await page.waitForResponse(API_URL_TOKENS + '?type=ERC-1155'); await page.waitForResponse(API_URL_TOKENS + '?type=ERC-1155');
await page.waitForResponse(API_URL_TOKENS + '?type=ERC-404');
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
......
...@@ -14,6 +14,7 @@ const ASSET_URL = tokenInfoERC20a.icon_url as string; ...@@ -14,6 +14,7 @@ const ASSET_URL = tokenInfoERC20a.icon_url as string;
const TOKENS_ERC20_API_URL = buildApiUrl('address_tokens', { hash: '1' }) + '?type=ERC-20'; const TOKENS_ERC20_API_URL = buildApiUrl('address_tokens', { hash: '1' }) + '?type=ERC-20';
const TOKENS_ERC721_API_URL = buildApiUrl('address_tokens', { hash: '1' }) + '?type=ERC-721'; const TOKENS_ERC721_API_URL = buildApiUrl('address_tokens', { hash: '1' }) + '?type=ERC-721';
const TOKENS_ER1155_API_URL = buildApiUrl('address_tokens', { hash: '1' }) + '?type=ERC-1155'; const TOKENS_ER1155_API_URL = buildApiUrl('address_tokens', { hash: '1' }) + '?type=ERC-1155';
const TOKENS_ER404_API_URL = buildApiUrl('address_tokens', { hash: '1' }) + '?type=ERC-404';
const ADDRESS_API_URL = buildApiUrl('address', { hash: '1' }); const ADDRESS_API_URL = buildApiUrl('address', { hash: '1' });
const hooksConfig = { const hooksConfig = {
router: { router: {
...@@ -46,6 +47,10 @@ const test = base.extend({ ...@@ -46,6 +47,10 @@ const test = base.extend({
status: 200, status: 200,
body: JSON.stringify(tokensMock.erc1155List), body: JSON.stringify(tokensMock.erc1155List),
}), { times: 1 }); }), { times: 1 });
await page.route(TOKENS_ER404_API_URL, async(route) => route.fulfill({
status: 200,
body: JSON.stringify(tokensMock.erc404List),
}), { times: 1 });
use(page); use(page);
}, },
......
...@@ -45,6 +45,22 @@ const TokenSelectItem = ({ data }: Props) => { ...@@ -45,6 +45,22 @@ const TokenSelectItem = ({ data }: Props) => {
</> </>
); );
} }
case 'ERC-404': {
return (
<>
{ data.token_id !== null && (
<chakra.span textOverflow="ellipsis" overflow="hidden" mr={ 6 }>
#{ data.token_id || 0 }
</chakra.span>
) }
{ data.value !== null && (
<span>
{ BigNumber(data.value).toFormat() }
</span>
) }
</>
);
}
} }
})(); })();
......
...@@ -16,12 +16,13 @@ interface Props { ...@@ -16,12 +16,13 @@ interface Props {
searchTerm: string; searchTerm: string;
erc20sort: Sort; erc20sort: Sort;
erc1155sort: Sort; erc1155sort: Sort;
erc404sort: Sort;
filteredData: FormattedData; filteredData: FormattedData;
onInputChange: (event: ChangeEvent<HTMLInputElement>) => void; onInputChange: (event: ChangeEvent<HTMLInputElement>) => void;
onSortClick: (event: React.SyntheticEvent) => void; onSortClick: (event: React.SyntheticEvent) => void;
} }
const TokenSelectMenu = ({ erc20sort, erc1155sort, filteredData, onInputChange, onSortClick, searchTerm }: Props) => { const TokenSelectMenu = ({ erc20sort, erc1155sort, erc404sort, filteredData, onInputChange, onSortClick, searchTerm }: Props) => {
const searchIconColor = useColorModeValue('blackAlpha.600', 'whiteAlpha.600'); const searchIconColor = useColorModeValue('blackAlpha.600', 'whiteAlpha.600');
const inputBorderColor = useColorModeValue('blackAlpha.100', 'whiteAlpha.200'); const inputBorderColor = useColorModeValue('blackAlpha.100', 'whiteAlpha.200');
...@@ -43,15 +44,17 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, filteredData, onInputChange, ...@@ -43,15 +44,17 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, filteredData, onInputChange,
</InputGroup> </InputGroup>
<Flex flexDir="column" rowGap={ 6 }> <Flex flexDir="column" rowGap={ 6 }>
{ Object.entries(filteredData).sort(sortTokenGroups).map(([ tokenType, tokenInfo ]) => { { Object.entries(filteredData).sort(sortTokenGroups).map(([ tokenType, tokenInfo ]) => {
if (tokenInfo.items.length === 0) { if (tokenInfo.items.length === 0) {
return null; return null;
} }
const type = tokenType as TokenType; const type = tokenType as TokenType;
const arrowTransform = (type === 'ERC-1155' && erc1155sort === 'desc') || (type === 'ERC-20' && erc20sort === 'desc') ? const arrowTransform =
'rotate(90deg)' : (type === 'ERC-1155' && erc1155sort === 'desc') ||
'rotate(-90deg)'; (type === 'ERC-404' && erc404sort === 'desc') ||
(type === 'ERC-20' && erc20sort === 'desc') ?
'rotate(90deg)' :
'rotate(-90deg)';
const sortDirection: Sort = (() => { const sortDirection: Sort = (() => {
switch (type) { switch (type) {
case 'ERC-1155': case 'ERC-1155':
...@@ -62,7 +65,10 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, filteredData, onInputChange, ...@@ -62,7 +65,10 @@ const TokenSelectMenu = ({ erc20sort, erc1155sort, filteredData, onInputChange,
return 'desc'; return 'desc';
} }
})(); })();
const hasSort = type === 'ERC-1155' || (type === 'ERC-20' && tokenInfo.items.some(({ usd }) => usd)); const hasSort =
(type === 'ERC-404' && tokenInfo.items.some(item => item.value)) ||
type === 'ERC-1155' ||
(type === 'ERC-20' && tokenInfo.items.some(({ usd }) => usd));
const numPrefix = tokenInfo.isOverflow ? '>' : ''; const numPrefix = tokenInfo.isOverflow ? '>' : '';
return ( return (
......
...@@ -10,6 +10,7 @@ import { filterTokens } from '../utils/tokenUtils'; ...@@ -10,6 +10,7 @@ import { filterTokens } from '../utils/tokenUtils';
export default function useTokenSelect(data: FormattedData) { export default function useTokenSelect(data: FormattedData) {
const [ searchTerm, setSearchTerm ] = React.useState(''); const [ searchTerm, setSearchTerm ] = React.useState('');
const [ erc1155sort, setErc1155Sort ] = React.useState<Sort>('desc'); const [ erc1155sort, setErc1155Sort ] = React.useState<Sort>('desc');
const [ erc404sort, setErc404Sort ] = React.useState<Sort>('desc');
const [ erc20sort, setErc20Sort ] = React.useState<Sort>('desc'); const [ erc20sort, setErc20Sort ] = React.useState<Sort>('desc');
const onInputChange = React.useCallback((event: ChangeEvent<HTMLInputElement>) => { const onInputChange = React.useCallback((event: ChangeEvent<HTMLInputElement>) => {
...@@ -21,6 +22,9 @@ export default function useTokenSelect(data: FormattedData) { ...@@ -21,6 +22,9 @@ export default function useTokenSelect(data: FormattedData) {
if (tokenType === 'ERC-1155') { if (tokenType === 'ERC-1155') {
setErc1155Sort((prevValue) => prevValue === 'desc' ? 'asc' : 'desc'); setErc1155Sort((prevValue) => prevValue === 'desc' ? 'asc' : 'desc');
} }
if (tokenType === 'ERC-404') {
setErc404Sort((prevValue) => prevValue === 'desc' ? 'asc' : 'desc');
}
if (tokenType === 'ERC-20') { if (tokenType === 'ERC-20') {
setErc20Sort((prevValue) => prevValue === 'desc' ? 'asc' : 'desc'); setErc20Sort((prevValue) => prevValue === 'desc' ? 'asc' : 'desc');
} }
...@@ -37,6 +41,7 @@ export default function useTokenSelect(data: FormattedData) { ...@@ -37,6 +41,7 @@ export default function useTokenSelect(data: FormattedData) {
searchTerm, searchTerm,
erc20sort, erc20sort,
erc1155sort, erc1155sort,
erc404sort,
onInputChange, onInputChange,
onSortClick, onSortClick,
data, data,
......
...@@ -22,13 +22,13 @@ export interface TokenSelectDataItem { ...@@ -22,13 +22,13 @@ export interface TokenSelectDataItem {
type TokenGroup = [string, TokenSelectDataItem]; type TokenGroup = [string, TokenSelectDataItem];
const TOKEN_GROUPS_ORDER: Array<TokenType> = [ 'ERC-20', 'ERC-721', 'ERC-1155' ]; const TOKEN_GROUPS_ORDER: Array<TokenType> = [ 'ERC-20', 'ERC-721', 'ERC-1155', 'ERC-404' ];
export const sortTokenGroups = (groupA: TokenGroup, groupB: TokenGroup) => { export const sortTokenGroups = (groupA: TokenGroup, groupB: TokenGroup) => {
return TOKEN_GROUPS_ORDER.indexOf(groupA[0] as TokenType) > TOKEN_GROUPS_ORDER.indexOf(groupB[0] as TokenType) ? 1 : -1; return TOKEN_GROUPS_ORDER.indexOf(groupA[0] as TokenType) > TOKEN_GROUPS_ORDER.indexOf(groupB[0] as TokenType) ? 1 : -1;
}; };
const sortErc1155Tokens = (sort: Sort) => (dataA: AddressTokenBalance, dataB: AddressTokenBalance) => { const sortErc1155or404Tokens = (sort: Sort) => (dataA: AddressTokenBalance, dataB: AddressTokenBalance) => {
if (dataA.value === dataB.value) { if (dataA.value === dataB.value) {
return 0; return 0;
} }
...@@ -38,6 +38,7 @@ const sortErc1155Tokens = (sort: Sort) => (dataA: AddressTokenBalance, dataB: Ad ...@@ -38,6 +38,7 @@ const sortErc1155Tokens = (sort: Sort) => (dataA: AddressTokenBalance, dataB: Ad
return Number(dataA.value) > Number(dataB.value) ? 1 : -1; return Number(dataA.value) > Number(dataB.value) ? 1 : -1;
}; };
const sortErc20Tokens = (sort: Sort) => (dataA: TokenEnhancedData, dataB: TokenEnhancedData) => { const sortErc20Tokens = (sort: Sort) => (dataA: TokenEnhancedData, dataB: TokenEnhancedData) => {
if (!dataA.usd && !dataB.usd) { if (!dataA.usd && !dataB.usd) {
return 0; return 0;
...@@ -63,7 +64,8 @@ const sortErc721Tokens = () => () => 0; ...@@ -63,7 +64,8 @@ const sortErc721Tokens = () => () => 0;
export const sortingFns = { export const sortingFns = {
'ERC-20': sortErc20Tokens, 'ERC-20': sortErc20Tokens,
'ERC-721': sortErc721Tokens, 'ERC-721': sortErc721Tokens,
'ERC-1155': sortErc1155Tokens, 'ERC-1155': sortErc1155or404Tokens,
'ERC-404': sortErc1155or404Tokens,
}; };
export const filterTokens = (searchTerm: string) => ({ token }: AddressTokenBalance) => { export const filterTokens = (searchTerm: string) => ({ token }: AddressTokenBalance) => {
......
...@@ -36,6 +36,11 @@ export default function useFetchTokens({ hash }: Props) { ...@@ -36,6 +36,11 @@ export default function useFetchTokens({ hash }: Props) {
queryParams: { type: 'ERC-1155' }, queryParams: { type: 'ERC-1155' },
queryOptions: { enabled: Boolean(hash), refetchOnMount: false }, queryOptions: { enabled: Boolean(hash), refetchOnMount: false },
}); });
const erc404query = useApiQuery('address_tokens', {
pathParams: { hash },
queryParams: { type: 'ERC-404' },
queryOptions: { enabled: Boolean(hash), refetchOnMount: false },
});
const queryClient = useQueryClient(); const queryClient = useQueryClient();
...@@ -78,6 +83,10 @@ export default function useFetchTokens({ hash }: Props) { ...@@ -78,6 +83,10 @@ export default function useFetchTokens({ hash }: Props) {
updateTokensData('ERC-1155', payload); updateTokensData('ERC-1155', payload);
}, [ updateTokensData ]); }, [ updateTokensData ]);
const handleTokenBalancesErc404Message: SocketMessage.AddressTokenBalancesErc1155['handler'] = React.useCallback((payload) => {
updateTokensData('ERC-404', payload);
}, [ updateTokensData ]);
const channel = useSocketChannel({ const channel = useSocketChannel({
topic: `addresses:${ hash?.toLowerCase() }`, topic: `addresses:${ hash?.toLowerCase() }`,
isDisabled: Boolean(hash) && (erc20query.isPlaceholderData || erc721query.isPlaceholderData || erc1155query.isPlaceholderData), isDisabled: Boolean(hash) && (erc20query.isPlaceholderData || erc721query.isPlaceholderData || erc1155query.isPlaceholderData),
...@@ -98,6 +107,11 @@ export default function useFetchTokens({ hash }: Props) { ...@@ -98,6 +107,11 @@ export default function useFetchTokens({ hash }: Props) {
event: 'updated_token_balances_erc_1155', event: 'updated_token_balances_erc_1155',
handler: handleTokenBalancesErc1155Message, handler: handleTokenBalancesErc1155Message,
}); });
useSocketMessage({
channel,
event: 'updated_token_balances_erc_404',
handler: handleTokenBalancesErc404Message,
});
const data = React.useMemo(() => { const data = React.useMemo(() => {
return { return {
...@@ -113,12 +127,16 @@ export default function useFetchTokens({ hash }: Props) { ...@@ -113,12 +127,16 @@ export default function useFetchTokens({ hash }: Props) {
items: erc1155query.data?.items.map(calculateUsdValue) || [], items: erc1155query.data?.items.map(calculateUsdValue) || [],
isOverflow: Boolean(erc1155query.data?.next_page_params), isOverflow: Boolean(erc1155query.data?.next_page_params),
}, },
'ERC-404': {
items: erc404query.data?.items.map(calculateUsdValue) || [],
isOverflow: Boolean(erc1155query.data?.next_page_params),
},
}; };
}, [ erc1155query.data, erc20query.data, erc721query.data ]); }, [ erc1155query.data, erc20query.data, erc721query.data, erc404query.data ]);
return { return {
isPending: erc20query.isPending || erc721query.isPending || erc1155query.isPending, isPending: erc20query.isPending || erc721query.isPending || erc1155query.isPending || erc404query.isPending,
isError: erc20query.isError || erc721query.isError || erc1155query.isError, isError: erc20query.isError || erc721query.isError || erc1155query.isError || erc404query.isError,
data, data,
}; };
} }
...@@ -17,8 +17,10 @@ import * as metadata from 'lib/metadata'; ...@@ -17,8 +17,10 @@ import * as metadata from 'lib/metadata';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
import useSocketChannel from 'lib/socket/useSocketChannel'; import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage'; import useSocketMessage from 'lib/socket/useSocketMessage';
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
import * as addressStubs from 'stubs/address'; import * as addressStubs from 'stubs/address';
import * as tokenStubs from 'stubs/token'; import * as tokenStubs from 'stubs/token';
import { getTokenHoldersStub } from 'stubs/token';
import { generateListStub } from 'stubs/utils'; import { generateListStub } from 'stubs/utils';
import AddressContract from 'ui/address/AddressContract'; import AddressContract from 'ui/address/AddressContract';
import AddressQrCode from 'ui/address/details/AddressQrCode'; import AddressQrCode from 'ui/address/details/AddressQrCode';
...@@ -118,7 +120,7 @@ const TokenPageContent = () => { ...@@ -118,7 +120,7 @@ const TokenPageContent = () => {
}, [ tokenQuery.data, tokenQuery.isPlaceholderData ]); }, [ tokenQuery.data, tokenQuery.isPlaceholderData ]);
const hasData = (tokenQuery.data && !tokenQuery.isPlaceholderData) && (contractQuery.data && !contractQuery.isPlaceholderData); const hasData = (tokenQuery.data && !tokenQuery.isPlaceholderData) && (contractQuery.data && !contractQuery.isPlaceholderData);
const hasInventoryTab = tokenQuery.data?.type === 'ERC-1155' || tokenQuery.data?.type === 'ERC-721'; const hasInventoryTab = Boolean(tokenQuery.data?.type) && NFT_TOKEN_TYPE_IDS.includes(tokenQuery.data.type);
const transfersQuery = useQueryWithPages({ const transfersQuery = useQueryWithPages({
resourceName: 'token_transfers', resourceName: 'token_transfers',
...@@ -161,8 +163,7 @@ const TokenPageContent = () => { ...@@ -161,8 +163,7 @@ const TokenPageContent = () => {
scrollRef, scrollRef,
options: { options: {
enabled: Boolean(hashString && tab === 'holders' && hasData), enabled: Boolean(hashString && tab === 'holders' && hasData),
placeholderData: generateListStub<'token_holders'>( placeholderData: getTokenHoldersStub(tokenQuery.data?.type, null),
tokenQuery.data?.type === 'ERC-1155' ? tokenStubs.TOKEN_HOLDER_ERC_1155 : tokenStubs.TOKEN_HOLDER_ERC_20, 50, { next_page_params: null }),
}, },
}); });
...@@ -174,7 +175,7 @@ const TokenPageContent = () => { ...@@ -174,7 +175,7 @@ const TokenPageContent = () => {
const contractTabs = useContractTabs(contractQuery.data); const contractTabs = useContractTabs(contractQuery.data);
const tabs: Array<RoutedTab> = [ const tabs: Array<RoutedTab> = [
(tokenQuery.data?.type === 'ERC-1155' || tokenQuery.data?.type === 'ERC-721') ? { hasInventoryTab ? {
id: 'inventory', id: 'inventory',
title: 'Inventory', title: 'Inventory',
component: <TokenInventory inventoryQuery={ inventoryQuery } tokenQuery={ tokenQuery } ownerFilter={ ownerFilter }/>, component: <TokenInventory inventoryQuery={ inventoryQuery } tokenQuery={ tokenQuery } ownerFilter={ ownerFilter }/>,
...@@ -212,7 +213,7 @@ const TokenPageContent = () => { ...@@ -212,7 +213,7 @@ const TokenPageContent = () => {
} }
// default tab for nfts is token inventory // default tab for nfts is token inventory
if (((tokenQuery.data?.type === 'ERC-1155' || tokenQuery.data?.type === 'ERC-721') && !tab) || tab === 'inventory') { if ((hasInventoryTab && !tab) || tab === 'inventory') {
pagination = inventoryQuery.pagination; pagination = inventoryQuery.pagination;
} }
......
...@@ -11,9 +11,12 @@ import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError'; ...@@ -11,9 +11,12 @@ import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import * as metadata from 'lib/metadata'; import * as metadata from 'lib/metadata';
import * as regexp from 'lib/regexp'; import * as regexp from 'lib/regexp';
import { TOKEN_INSTANCE, TOKEN_INFO_ERC_1155 } from 'stubs/token'; import {
import * as tokenStubs from 'stubs/token'; TOKEN_INSTANCE,
import { generateListStub } from 'stubs/utils'; TOKEN_INFO_ERC_1155,
getTokenInstanceTransfersStub,
getTokenInstanceHoldersStub,
} from 'stubs/token';
import AddressQrCode from 'ui/address/details/AddressQrCode'; import AddressQrCode from 'ui/address/details/AddressQrCode';
import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu'; import AccountActionsMenu from 'ui/shared/AccountActionsMenu/AccountActionsMenu';
import TextAd from 'ui/shared/ad/TextAd'; import TextAd from 'ui/shared/ad/TextAd';
...@@ -66,11 +69,7 @@ const TokenInstanceContent = () => { ...@@ -66,11 +69,7 @@ const TokenInstanceContent = () => {
scrollRef, scrollRef,
options: { options: {
enabled: Boolean(hash && id && (!tab || tab === 'token_transfers') && !tokenInstanceQuery.isPlaceholderData && tokenInstanceQuery.data), enabled: Boolean(hash && id && (!tab || tab === 'token_transfers') && !tokenInstanceQuery.isPlaceholderData && tokenInstanceQuery.data),
placeholderData: generateListStub<'token_instance_transfers'>( placeholderData: getTokenInstanceTransfersStub(tokenQuery.data?.type, null),
tokenQuery.data?.type === 'ERC-1155' ? tokenStubs.TOKEN_TRANSFER_ERC_1155 : tokenStubs.TOKEN_TRANSFER_ERC_721,
10,
{ next_page_params: null },
),
}, },
}); });
...@@ -86,8 +85,7 @@ const TokenInstanceContent = () => { ...@@ -86,8 +85,7 @@ const TokenInstanceContent = () => {
scrollRef, scrollRef,
options: { options: {
enabled: Boolean(hash && tab === 'holders' && shouldFetchHolders), enabled: Boolean(hash && tab === 'holders' && shouldFetchHolders),
placeholderData: generateListStub<'token_instance_holders'>( placeholderData: getTokenInstanceHoldersStub(tokenQuery.data?.type, null),
tokenQuery.data?.type === 'ERC-1155' ? tokenStubs.TOKEN_HOLDER_ERC_1155 : tokenStubs.TOKEN_HOLDER_ERC_20, 10, { next_page_params: null }),
}, },
}); });
......
...@@ -29,7 +29,7 @@ const TokenHoldersListItem = ({ holder, token, isLoading }: Props) => { ...@@ -29,7 +29,7 @@ const TokenHoldersListItem = ({ holder, token, isLoading }: Props) => {
/> />
</ListItemMobileGrid.Value> </ListItemMobileGrid.Value>
{ token.type === 'ERC-1155' && 'token_id' in holder && ( { (token.type === 'ERC-1155' || token.type === 'ERC-404') && 'token_id' in holder && (
<> <>
<ListItemMobileGrid.Label isLoading={ isLoading }>ID#</ListItemMobileGrid.Label> <ListItemMobileGrid.Label isLoading={ isLoading }>ID#</ListItemMobileGrid.Label>
<ListItemMobileGrid.Value> <ListItemMobileGrid.Value>
......
...@@ -19,7 +19,7 @@ const TokenHoldersTable = ({ data, token, top, isLoading }: Props) => { ...@@ -19,7 +19,7 @@ const TokenHoldersTable = ({ data, token, top, isLoading }: Props) => {
<Thead top={ top }> <Thead top={ top }>
<Tr> <Tr>
<Th>Holder</Th> <Th>Holder</Th>
{ token.type === 'ERC-1155' && <Th>ID#</Th> } { (token.type === 'ERC-1155' || token.type === 'ERC-404') && <Th>ID#</Th> }
<Th isNumeric>Quantity</Th> <Th isNumeric>Quantity</Th>
{ token.total_supply && <Th isNumeric width="175px">Percentage</Th> } { token.total_supply && <Th isNumeric width="175px">Percentage</Th> }
</Tr> </Tr>
......
...@@ -26,7 +26,7 @@ const TokenTransferTableItem = ({ holder, token, isLoading }: Props) => { ...@@ -26,7 +26,7 @@ const TokenTransferTableItem = ({ holder, token, isLoading }: Props) => {
fontWeight="700" fontWeight="700"
/> />
</Td> </Td>
{ token.type === 'ERC-1155' && 'token_id' in holder && ( { (token.type === 'ERC-1155' || token.type === 'ERC-404') && 'token_id' in holder && (
<Td verticalAlign="middle"> <Td verticalAlign="middle">
<Skeleton isLoaded={ !isLoading } display="inline-block"> <Skeleton isLoaded={ !isLoading } display="inline-block">
{ 'token_id' in holder && holder.token_id } { 'token_id' in holder && holder.token_id }
......
...@@ -5,6 +5,7 @@ import type { TokenTransfer } from 'types/api/tokenTransfer'; ...@@ -5,6 +5,7 @@ import type { TokenTransfer } from 'types/api/tokenTransfer';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
import AddressFromTo from 'ui/shared/address/AddressFromTo'; import AddressFromTo from 'ui/shared/address/AddressFromTo';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import NftEntity from 'ui/shared/entities/nft/NftEntity'; import NftEntity from 'ui/shared/entities/nft/NftEntity';
...@@ -26,7 +27,7 @@ const TokenTransferListItem = ({ ...@@ -26,7 +27,7 @@ const TokenTransferListItem = ({
isLoading, isLoading,
}: Props) => { }: Props) => {
const timeAgo = useTimeAgoIncrement(timestamp, true); const timeAgo = useTimeAgoIncrement(timestamp, true);
const { usd, valueStr } = 'value' in total ? getCurrencyValue({ const { usd, valueStr } = 'value' in total && total.value !== null ? getCurrencyValue({
value: total.value, value: total.value,
exchangeRate: token.exchange_rate, exchangeRate: token.exchange_rate,
accuracy: 8, accuracy: 8,
...@@ -87,7 +88,7 @@ const TokenTransferListItem = ({ ...@@ -87,7 +88,7 @@ const TokenTransferListItem = ({
) } ) }
</Grid> </Grid>
) } ) }
{ 'token_id' in total && (token.type === 'ERC-721' || token.type === 'ERC-1155') && total.token_id !== null && ( { 'token_id' in total && (NFT_TOKEN_TYPE_IDS.includes(token.type)) && total.token_id !== null && (
<NftEntity <NftEntity
hash={ token.address } hash={ token.address }
id={ total.token_id } id={ total.token_id }
......
...@@ -5,6 +5,7 @@ import type { TokenInfo } from 'types/api/token'; ...@@ -5,6 +5,7 @@ import type { TokenInfo } from 'types/api/token';
import type { TokenTransfer } from 'types/api/tokenTransfer'; import type { TokenTransfer } from 'types/api/tokenTransfer';
import { AddressHighlightProvider } from 'lib/contexts/addressHighlight'; import { AddressHighlightProvider } from 'lib/contexts/addressHighlight';
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice'; import * as SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import { default as Thead } from 'ui/shared/TheadSticky'; import { default as Thead } from 'ui/shared/TheadSticky';
import TruncatedValue from 'ui/shared/TruncatedValue'; import TruncatedValue from 'ui/shared/TruncatedValue';
...@@ -32,11 +33,11 @@ const TokenTransferTable = ({ data, top, showSocketInfo, socketInfoAlert, socket ...@@ -32,11 +33,11 @@ const TokenTransferTable = ({ data, top, showSocketInfo, socketInfoAlert, socket
<Th width="280px">Txn hash</Th> <Th width="280px">Txn hash</Th>
<Th width="200px">Method</Th> <Th width="200px">Method</Th>
<Th width={{ lg: '224px', xl: '420px' }}>From/To</Th> <Th width={{ lg: '224px', xl: '420px' }}>From/To</Th>
{ (tokenType === 'ERC-721' || tokenType === 'ERC-1155') && { (NFT_TOKEN_TYPE_IDS.includes(tokenType)) &&
<Th width={ tokenType === 'ERC-1155' ? '50%' : '100%' }>Token ID</Th> <Th width={ tokenType === 'ERC-1155' ? '50%' : '100%' }>Token ID</Th>
} }
{ (tokenType === 'ERC-20' || tokenType === 'ERC-1155') && ( { (tokenType === 'ERC-20' || tokenType === 'ERC-1155' || tokenType === 'ERC-404') && (
<Th width={ tokenType === 'ERC-1155' ? '50%' : '100%' } isNumeric> <Th width={ tokenType === 'ERC-20' ? '100%' : '50%' } isNumeric>
<TruncatedValue value={ `Value ${ token?.symbol || '' }` } w="100%" verticalAlign="middle"/> <TruncatedValue value={ `Value ${ token?.symbol || '' }` } w="100%" verticalAlign="middle"/>
</Th> </Th>
) } ) }
......
...@@ -5,6 +5,7 @@ import type { TokenTransfer } from 'types/api/tokenTransfer'; ...@@ -5,6 +5,7 @@ import type { TokenTransfer } from 'types/api/tokenTransfer';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement'; import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import { NFT_TOKEN_TYPE_IDS } from 'lib/token/tokenTypes';
import AddressFromTo from 'ui/shared/address/AddressFromTo'; import AddressFromTo from 'ui/shared/address/AddressFromTo';
import Tag from 'ui/shared/chakra/Tag'; import Tag from 'ui/shared/chakra/Tag';
import NftEntity from 'ui/shared/entities/nft/NftEntity'; import NftEntity from 'ui/shared/entities/nft/NftEntity';
...@@ -24,7 +25,7 @@ const TokenTransferTableItem = ({ ...@@ -24,7 +25,7 @@ const TokenTransferTableItem = ({
isLoading, isLoading,
}: Props) => { }: Props) => {
const timeAgo = useTimeAgoIncrement(timestamp, true); const timeAgo = useTimeAgoIncrement(timestamp, true);
const { usd, valueStr } = 'value' in total ? getCurrencyValue({ const { usd, valueStr } = 'value' in total && total.value !== null ? getCurrencyValue({
value: total.value, value: total.value,
exchangeRate: token.exchange_rate, exchangeRate: token.exchange_rate,
accuracy: 8, accuracy: 8,
...@@ -69,7 +70,7 @@ const TokenTransferTableItem = ({ ...@@ -69,7 +70,7 @@ const TokenTransferTableItem = ({
tokenHash={ token.address } tokenHash={ token.address }
/> />
</Td> </Td>
{ (token.type === 'ERC-721' || token.type === 'ERC-1155') && ( { (NFT_TOKEN_TYPE_IDS.includes(token.type)) && (
<Td> <Td>
{ 'token_id' in total && total.token_id !== null ? ( { 'token_id' in total && total.token_id !== null ? (
<NftEntity <NftEntity
...@@ -82,7 +83,7 @@ const TokenTransferTableItem = ({ ...@@ -82,7 +83,7 @@ const TokenTransferTableItem = ({
} }
</Td> </Td>
) } ) }
{ (token.type === 'ERC-20' || token.type === 'ERC-1155') && ( { (token.type === 'ERC-20' || token.type === 'ERC-1155' || token.type === 'ERC-404') && (
<Td isNumeric verticalAlign="top"> <Td isNumeric verticalAlign="top">
{ valueStr && ( { valueStr && (
<Skeleton isLoaded={ !isLoading } display="inline-block" mt="7px" wordBreak="break-all"> <Skeleton isLoaded={ !isLoading } display="inline-block" mt="7px" wordBreak="break-all">
......
import { Flex, chakra } from '@chakra-ui/react'; import { Flex, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { TokenTransfer as TTokenTransfer, Erc20TotalPayload, Erc721TotalPayload, Erc1155TotalPayload } from 'types/api/tokenTransfer'; import type {
TokenTransfer as TTokenTransfer,
Erc20TotalPayload,
Erc721TotalPayload,
Erc1155TotalPayload,
Erc404TotalPayload,
} from 'types/api/tokenTransfer';
import getCurrencyValue from 'lib/getCurrencyValue'; import getCurrencyValue from 'lib/getCurrencyValue';
import AddressFromTo from 'ui/shared/address/AddressFromTo'; import AddressFromTo from 'ui/shared/address/AddressFromTo';
...@@ -62,6 +68,17 @@ const TxDetailsTokenTransfer = ({ data }: Props) => { ...@@ -62,6 +68,17 @@ const TxDetailsTokenTransfer = ({ data }: Props) => {
/> />
); );
} }
case 'ERC-404': {
const total = data.total as Erc404TotalPayload;
return (
<NftTokenTransferSnippet
token={ data.token }
tokenId={ 'token_id' in total ? total.token_id : null }
value={ 'value' in total ? total.value || '1' : '1' }
/>
);
}
} }
})(); })();
......
...@@ -8,7 +8,7 @@ import CheckboxInput from 'ui/shared/CheckboxInput'; ...@@ -8,7 +8,7 @@ import CheckboxInput from 'ui/shared/CheckboxInput';
// does it depend on the network? // does it depend on the network?
const NOTIFICATIONS = [ 'native', 'ERC-20', 'ERC-721' ] as const; const NOTIFICATIONS = [ 'native', 'ERC-20', 'ERC-721' ] as const;
const NOTIFICATIONS_NAMES = [ config.chain.currency.symbol, 'ERC-20', 'ERC-721, ERC-1155 (NFT)' ]; const NOTIFICATIONS_NAMES = [ config.chain.currency.symbol, 'ERC-20', 'ERC-721, ERC-1155, ERC-404 (NFT)' ];
type Props<Inputs extends FieldValues> = { type Props<Inputs extends FieldValues> = {
control: Control<Inputs>; control: Control<Inputs>;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment