mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
Merge pull request #381 from blockscout/address-page-setup
address page setup
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# ui config
|
||||
NEXT_PUBLIC_FEATURED_NETWORKS=[{'title':'Ethereum','url':'https://blockscout.com/eth/mainnet','group':'mainnets','type':'eth_mainnet'},{'title':'Ethereum Classic','url':'https://blockscout.com/etx/mainnet','group':'mainnets','type':'etc_mainnet'},{'title':'Gnosis Chain','url':'https://blockscout.com/xdai/mainnet','group':'mainnets','type':'xdai_mainnet'},{'title':'Astar (EVM)','url':'https://blockscout.com/astar','group':'mainnets','type':'astar'},{'title':'Shiden (EVM)','url':'https://blockscout.com/shiden','group':'mainnets','type':'astar'},{'title':'Klaytn Mainnet (Cypress)','url':'https://klaytn-mainnet.aws-k8s.blockscout.com/','group':'mainnets','type':'klaytn'},{'title':'Goerli','url':'https://blockscout.com/eth/goerli/','group':'testnets','type':'goerli'},{'title':'Optimism Goerli','url':'https://blockscout.com/optimism/goerli/','group':'testnets','type':'optimism_goerli'},{'title':'Optimism Bedrock Alpha','url':'https://blockscout.com/optimism/bedrock-alpha','group':'testnets','type':'optimism_bedrock_alpha'},{'title':'Gnosis Chiado','url':'https://blockscout.com/gnosis/chiado/','group':'testnets','type':'gnosis_chiado'},{'title':'Shibuya (EVM)','url':'https://blockscout.com/shibuya','group':'testnets','type':'shibuya'},{'title':'Optimism Opcraft','url':'https://blockscout.com/optimism/opcraft','group':'other','type':'optimism_opcraft'},{'title':'Optimism on Gnosis Chain','url':'https://blockscout.com/xdai/optimism','group':'other','type':'optimism_gnosis'},{'title':'ARTIS-Σ1','url':'https://blockscout.com/artis/sigma1','group':'other','type':'artis_sigma1'},{'title':'LUKSO L14','url':'https://blockscout.com/lukso/l14','group':'other','type':'lukso_l14'},{'title':'POA','url':'https://blockscout.com/poa/core','group':'other','type':'poa_core'},{'title':'POA Sokol','url':'https://blockscout.com/poa/sokol','group':'other','type':'poa_sokol'}]
|
||||
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/ethereum/goerli/transaction'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx'}}]
|
||||
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/ethereum/goerli/transaction','address':'/ethereum/ethereum/goerli/address'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address'}}]
|
||||
|
||||
# network config
|
||||
NEXT_PUBLIC_NETWORK_NAME=Ethereum
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
NEXT_PUBLIC_FOOTER_TELEGRAM_LINK=https://t.me/poa_network
|
||||
NEXT_PUBLIC_FOOTER_STAKING_LINK=https://duneanalytics.com/maxaleks/xdai-staking
|
||||
NEXT_PUBLIC_FEATURED_NETWORKS=[{'title':'Gnosis Chain','url':'https://blockscout.com/xdai/mainnet','group':'mainnets','type':'xdai_mainnet'},{'title':'Optimism on Gnosis Chain','url':'https://blockscout.com/xdai/optimism','group':'mainnets','icon':'https://www.fillmurray.com/60/60','type':'xdai_optimism'},{'title':'Arbitrum on xDai','url':'https://blockscout.com/xdai/aox','group':'mainnets'},{'title':'Ethereum','url':'https://blockscout.com/eth/mainnet','group':'mainnets','type':'eth_mainnet'},{'title':'Ethereum Classic','url':'https://blockscout.com/etx/mainnet','group':'mainnets','type':'etc_mainnet'},{'title':'POA','url':'https://blockscout.com/poa/core','group':'mainnets','type':'poa_core'},{'title':'RSK','url':'https://blockscout.com/rsk/mainnet','group':'mainnets','type':'rsk_mainnet'},{'title':'Gnosis Chain Testnet','url':'https://blockscout.com/xdai/testnet','group':'testnets','type':'xdai_testnet'},{'title':'POA Sokol','url':'https://blockscout.com/poa/sokol','group':'testnets','type':'poa_sokol'},{'title':'ARTIS Σ1','url':'https://blockscout.com/artis/sigma1','group':'other','type':'artis_sigma1'},{'title':'LUKSO L14','url':'https://blockscout.com/lukso/l14','group':'other','type':'lukso_l14'},{'title':'Astar','url':'https://blockscout.com/astar','group':'other','type':'astar'}]
|
||||
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction'}}]
|
||||
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}]
|
||||
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cup']
|
||||
NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT=radial-gradient(at 12% 37%, hsla(324,73%,67%,1) 0px, transparent 50%), radial-gradient(at 62% 14%, hsla(256,87%,73%,1) 0px, transparent 50%), radial-gradient(at 84% 80%, hsla(128,75%,73%,1) 0px, transparent 50%), radial-gradient(at 57% 46%, hsla(285,63%,72%,1) 0px, transparent 50%), radial-gradient(at 37% 30%, hsla(174,70%,61%,1) 0px, transparent 50%), radial-gradient(at 15% 86%, hsla(350,65%,70%,1) 0px, transparent 50%), radial-gradient(at 67% 57%, hsla(14,95%,76%,1) 0px, transparent 50%)
|
||||
|
||||
|
||||
@@ -473,7 +473,7 @@ frontend:
|
||||
NEXT_PUBLIC_FEATURED_NETWORKS:
|
||||
_default: "[{'title':'Gnosis Chain','url':'https://blockscout.com/xdai/mainnet','group':'mainnets','type':'xdai_mainnet'},{'title':'Optimism on Gnosis Chain','url':'https://blockscout.com/xdai/optimism','group':'mainnets','icon':'https://www.fillmurray.com/60/60','type':'xdai_optimism'},{'title':'Arbitrum on xDai','url':'https://blockscout.com/xdai/aox','group':'mainnets'},{'title':'Ethereum','url':'https://blockscout.com/eth/mainnet','group':'mainnets','type':'eth_mainnet'},{'title':'Ethereum Classic','url':'https://blockscout.com/etx/mainnet','group':'mainnets','type':'etc_mainnet'},{'title':'POA','url':'https://blockscout.com/poa/core','group':'mainnets','type':'poa_core'},{'title':'RSK','url':'https://blockscout.com/rsk/mainnet','group':'mainnets','type':'rsk_mainnet'},{'title':'Gnosis Chain Testnet','url':'https://blockscout.com/xdai/testnet','group':'testnets','type':'xdai_testnet'},{'title':'POA Sokol','url':'https://blockscout.com/poa/sokol','group':'testnets','type':'poa_sokol'},{'title':'ARTIS Σ1','url':'https://blockscout.com/artis/sigma1','group':'other','type':'artis_sigma1'},{'title':'LUKSO L14','url':'https://blockscout.com/lukso/l14','group':'other','type':'lukso_l14'},{'title':'Astar','url':'https://blockscout.com/astar','group':'other','type':'astar'}]"
|
||||
NEXT_PUBLIC_NETWORK_EXPLORERS:
|
||||
_default: "[{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io','paths':{'tx':'/tx'}}]"
|
||||
_default: "[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/ethereum/goerli/transaction','address':'/ethereum/ethereum/goerli/address'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address'}}]"
|
||||
# network config
|
||||
NEXT_PUBLIC_NETWORK_NAME:
|
||||
_default: Ethereum
|
||||
|
||||
@@ -387,3 +387,5 @@ frontend:
|
||||
NEXT_PUBLIC_APP_HOST:
|
||||
_default: blockscout.com
|
||||
review: blockscout-main.test.aws-k8s.blockscout.com
|
||||
NEXT_PUBLIC_NETWORK_EXPLORERS:
|
||||
_default: [{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}]
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.2 19.4c3.972 0 7.2-3.228 7.2-7.2S16.172 5 12.2 5A7.206 7.206 0 0 0 5 12.2c0 3.972 3.228 7.2 7.2 7.2Zm-5.574-4.332 2.926-.023c.325 1.173.871 2.311 1.614 3.333a6.28 6.28 0 0 1-4.54-3.31Zm3.67-4.842h3.646a9.853 9.853 0 0 1 .023 3.867l-3.67.023a9.544 9.544 0 0 1 0-3.89Zm1.823 7.885a9.323 9.323 0 0 1-1.591-3.066l3.193-.023a9.813 9.813 0 0 1-1.602 3.089Zm.929.302a10.24 10.24 0 0 0 1.637-3.403l3.124-.023a6.286 6.286 0 0 1-4.761 3.426ZM18.47 12.2c0 .65-.105 1.277-.279 1.858l-3.286.023c.232-1.277.22-2.578-.023-3.855h3.263c.209.615.325 1.289.325 1.974Zm-.72-2.903h-3.09a10.675 10.675 0 0 0-1.613-3.31 6.244 6.244 0 0 1 4.703 3.31Zm-4.053 0H10.54a9.593 9.593 0 0 1 1.58-3.008 9.595 9.595 0 0 1 1.58 3.008Zm-2.532-3.275a10.317 10.317 0 0 0-1.59 3.275H6.648a6.249 6.249 0 0 1 4.517-3.275Zm-1.811 4.204a10.685 10.685 0 0 0-.012 3.89l-3.1.023a6.173 6.173 0 0 1 .012-3.914h3.1Z" fill="currentColor"/>
|
||||
<path d="M12.2 19.4c3.972 0 7.2-3.228 7.2-7.2S16.172 5 12.2 5A7.206 7.206 0 0 0 5 12.2c0 3.972 3.228 7.2 7.2 7.2Zm-5.574-4.332 2.926-.023a10.424 10.424 0 0 0 1.614 3.333 6.28 6.28 0 0 1-4.54-3.31Zm3.67-4.842h3.646a9.853 9.853 0 0 1 .023 3.867l-3.67.023a9.544 9.544 0 0 1 0-3.89Zm1.823 7.885a9.323 9.323 0 0 1-1.591-3.066l3.193-.023a9.813 9.813 0 0 1-1.602 3.089Zm.929.302a10.24 10.24 0 0 0 1.637-3.403l3.124-.023a6.286 6.286 0 0 1-4.761 3.426ZM18.47 12.2c0 .65-.105 1.277-.279 1.858l-3.286.023c.232-1.277.22-2.578-.023-3.855h3.263a6.17 6.17 0 0 1 .325 1.974Zm-.72-2.903h-3.09a10.675 10.675 0 0 0-1.613-3.31 6.244 6.244 0 0 1 4.703 3.31Zm-4.053 0H10.54a9.593 9.593 0 0 1 1.58-3.008 9.595 9.595 0 0 1 1.58 3.008Zm-2.532-3.275a10.317 10.317 0 0 0-1.59 3.275H6.648a6.249 6.249 0 0 1 4.517-3.275Zm-1.811 4.204a10.685 10.685 0 0 0-.012 3.89l-3.1.023a6.173 6.173 0 0 1 .012-3.914h3.1Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 986 B After Width: | Height: | Size: 983 B |
@@ -0,0 +1,14 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.004 2.61 13.2 8.432l1.443-3.434 6.36-2.386Z" fill="#E2761B"/>
|
||||
<path d="m2.988 2.61 7.741 5.876-1.372-3.489-6.369-2.386Zm15.208 13.492L16.117 19.3l4.447 1.229 1.279-4.356-3.647-.07Zm-16.032.071 1.271 4.356L7.882 19.3l-2.078-3.198-3.64.071Z" fill="#E4761B"/>
|
||||
<path d="m7.631 10.7-1.24 1.882 4.417.197-.157-4.765L7.63 10.7Zm8.73 0L13.3 7.959l-.101 4.82 4.408-.197-1.248-1.883Zm-8.479 8.6 2.651-1.3-2.29-1.795-.36 3.095ZM13.46 18l2.658 1.3-.368-3.095L13.459 18Z" fill="#E4761B"/>
|
||||
<path d="M16.117 19.3 13.458 18l.212 1.741-.023.733 2.47-1.174Zm-8.235 0 2.47 1.174-.015-.733.196-1.74-2.65 1.299Z" fill="#D7C1B3"/>
|
||||
<path d="M10.392 15.055 8.18 14.4l1.561-.717.65 1.37Zm3.208 0 .65-1.37 1.57.716-2.22.654Z" fill="#233447"/>
|
||||
<path d="m7.882 19.3.377-3.198-2.455.071L7.882 19.3Zm7.859-3.198.376 3.198 2.079-3.127-2.455-.07Zm1.867-3.52-4.408.197.408 2.276.65-1.37 1.57.716 1.78-1.82Zm-9.428 1.82 1.569-.718.643 1.37.416-2.275-4.416-.197 1.788 1.82Z" fill="#CD6116"/>
|
||||
<path d="m6.392 12.582 1.85 3.623L8.18 14.4l-1.788-1.82Zm9.435 1.82-.078 1.803 1.859-3.623-1.78 1.82Zm-5.02-1.623-.415 2.276.518 2.686.117-3.537-.22-1.425Zm2.393 0-.212 1.417.094 3.545.526-2.686-.408-2.276Z" fill="#E4751F"/>
|
||||
<path d="m13.608 15.055-.526 2.686.377.26 2.29-1.796.078-1.804-2.22.654ZM8.18 14.4l.063 1.804L10.533 18l.377-.26-.518-2.685L8.18 14.4Z" fill="#F6851B"/>
|
||||
<path d="m13.647 20.474.023-.733-.196-.173h-2.957l-.18.173.016.733-2.47-1.174.862.709 1.749 1.22h3.004l1.757-1.22.862-.709-2.47 1.174Z" fill="#C0AD9E"/>
|
||||
<path d="m13.459 18-.377-.26H10.91l-.377.26-.196 1.741.18-.173h2.957l.196.173-.211-1.74Z" fill="#161616"/>
|
||||
<path d="M21.333 8.81 22 5.595l-.996-2.985-7.545 5.623L16.36 10.7l4.102 1.206.91-1.064-.392-.283.628-.575-.487-.378.628-.48-.416-.316ZM2 5.595l.666 3.213-.423.315.627.48-.478.379.627.575-.392.283.902 1.064 4.102-1.206 2.902-2.465L2.988 2.61 2 5.596Z" fill="#763D16"/>
|
||||
<path d="M20.462 11.904 16.361 10.7l1.247 1.883-1.86 3.623 2.448-.032h3.647l-1.38-4.269ZM7.632 10.7l-4.103 1.205-1.365 4.27h3.64l2.439.03-1.851-3.622 1.24-1.883Zm5.568 2.08.259-4.545 1.192-3.237H9.357l1.176 3.237.275 4.545.094 1.433.008 3.529h2.172l.016-3.529.102-1.433Z" fill="#F6851B"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 20 20" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.938 13.125h-2.5a.312.312 0 0 0-.313.313v2.5c0 .172.14.312.313.312h2.5c.172 0 .312-.14.312-.313v-2.5a.312.312 0 0 0-.313-.312Zm-3.125-2.5h-1.876a.312.312 0 0 0-.312.313v1.874c0 .173.14.313.313.313h1.874c.173 0 .313-.14.313-.313v-1.874a.312.312 0 0 0-.313-.313Zm5.625 5.625h-1.875a.312.312 0 0 0-.313.313v1.875c0 .172.14.312.313.312h1.875c.172 0 .312-.14.312-.313v-1.875a.312.312 0 0 0-.313-.312Zm0-5.625h-1.25a.312.312 0 0 0-.313.313v1.25c0 .172.14.312.313.312h1.25c.172 0 .312-.14.312-.313v-1.25a.312.312 0 0 0-.313-.312Zm-6.25 6.25h-1.25a.312.312 0 0 0-.313.313v1.25c0 .172.14.312.313.312h1.25c.172 0 .312-.14.312-.313v-1.25a.312.312 0 0 0-.313-.312ZM17.5 1.25h-5.625a1.25 1.25 0 0 0-1.25 1.25v5.625a1.25 1.25 0 0 0 1.25 1.25H17.5a1.25 1.25 0 0 0 1.25-1.25V2.5a1.25 1.25 0 0 0-1.25-1.25Zm-1.25 5.313a.312.312 0 0 1-.313.312h-2.5a.313.313 0 0 1-.312-.313v-2.5a.312.312 0 0 1 .313-.312h2.5a.313.313 0 0 1 .312.313v2.5ZM8.125 1.25H2.5A1.25 1.25 0 0 0 1.25 2.5v5.625a1.25 1.25 0 0 0 1.25 1.25h5.625a1.25 1.25 0 0 0 1.25-1.25V2.5a1.25 1.25 0 0 0-1.25-1.25Zm-1.25 5.313a.312.312 0 0 1-.313.312h-2.5a.312.312 0 0 1-.312-.313v-2.5a.312.312 0 0 1 .313-.312h2.5a.312.312 0 0 1 .312.313v2.5Zm1.25 4.062H2.5a1.25 1.25 0 0 0-1.25 1.25V17.5a1.25 1.25 0 0 0 1.25 1.25h5.625a1.25 1.25 0 0 0 1.25-1.25v-5.625a1.25 1.25 0 0 0-1.25-1.25Zm-1.25 5.313a.313.313 0 0 1-.313.312h-2.5a.312.312 0 0 1-.312-.313v-2.5a.313.313 0 0 1 .313-.312h2.5a.312.312 0 0 1 .312.313v2.5Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -12,6 +12,7 @@ import appConfig from 'configs/app/config';
|
||||
// baseUrl: 'https://explorer.anyblock.tools',
|
||||
// paths: {
|
||||
// tx: '/ethereum/ethereum/goerli/transaction',
|
||||
// address: '/ethereum/ethereum/goerli/address'
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
@@ -19,6 +20,7 @@ import appConfig from 'configs/app/config';
|
||||
// baseUrl: 'https://goerli.etherscan.io/',
|
||||
// paths: {
|
||||
// tx: '/tx',
|
||||
// address: '/address',
|
||||
// },
|
||||
// },
|
||||
// ]).replaceAll('"', '\'');
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { PageParams } from './types';
|
||||
|
||||
import getNetworkTitle from 'lib/networks/getNetworkTitle';
|
||||
|
||||
export default function getSeo(params: PageParams) {
|
||||
const networkTitle = getNetworkTitle();
|
||||
|
||||
return {
|
||||
title: params ? `${ params.id } - ${ networkTitle }` : '',
|
||||
description: params ?
|
||||
`View the account balance, transactions, and other data for ${ params.id } on the ${ networkTitle }` :
|
||||
'',
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export type PageParams = {
|
||||
id: string;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { NextPage } from 'next';
|
||||
import Head from 'next/head';
|
||||
import React from 'react';
|
||||
|
||||
import type { PageParams } from 'lib/next/address/types';
|
||||
|
||||
import getSeo from 'lib/next/address/getSeo';
|
||||
import Address from 'ui/pages/Address';
|
||||
|
||||
const AddressPage: NextPage<PageParams> = ({ id }: PageParams) => {
|
||||
const { title, description } = getSeo({ id });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{ title }</title>
|
||||
<meta name="description" content={ description }/>
|
||||
</Head>
|
||||
<Address/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddressPage;
|
||||
|
||||
export { getServerSideProps } from 'lib/next/getServerSideProps';
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
|
||||
import handler from 'lib/api/handler';
|
||||
|
||||
const getUrl = (req: NextApiRequest) => {
|
||||
return `/v2/addresses/${ req.query.id }/counters`;
|
||||
};
|
||||
|
||||
const requestHandler = handler(getUrl, [ 'GET' ]);
|
||||
|
||||
export default requestHandler;
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
|
||||
import handler from 'lib/api/handler';
|
||||
|
||||
const getUrl = (req: NextApiRequest) => {
|
||||
return `/v2/addresses/${ req.query.id }`;
|
||||
};
|
||||
|
||||
const requestHandler = handler(getUrl, [ 'GET' ]);
|
||||
|
||||
export default requestHandler;
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
|
||||
import handler from 'lib/api/handler';
|
||||
|
||||
const getUrl = (req: NextApiRequest) => {
|
||||
return `/v2/addresses/${ req.query.id }/token-balances`;
|
||||
};
|
||||
|
||||
const requestHandler = handler(getUrl, [ 'GET' ]);
|
||||
|
||||
export default requestHandler;
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { AddressTag, WatchlistName } from './addressParams';
|
||||
import type { TokenInfo } from './tokenInfo';
|
||||
|
||||
export interface Address {
|
||||
block_number_balance_updated_at: number | null;
|
||||
coin_balance: string | null;
|
||||
creator_address_hash: string | null;
|
||||
creation_tx_hash: string | null;
|
||||
exchange_rate: string | null;
|
||||
hash: string;
|
||||
implementation_address: string | null;
|
||||
implementation_name: string | null;
|
||||
is_contract: boolean;
|
||||
is_verified: boolean;
|
||||
name: string | null;
|
||||
private_tags: Array<AddressTag> | null;
|
||||
public_tags: Array<AddressTag> | null;
|
||||
tokenInfo: TokenInfo | null;
|
||||
watchlist_names: Array<WatchlistName> | null;
|
||||
}
|
||||
|
||||
export interface AddressCounters {
|
||||
transaction_count: string;
|
||||
token_transfer_count: string;
|
||||
gas_usage_count: string;
|
||||
validation_count: string | null;
|
||||
}
|
||||
|
||||
export interface AddressTokenBalance {
|
||||
token: TokenInfo;
|
||||
token_id: string | null;
|
||||
value: string;
|
||||
}
|
||||
@@ -17,5 +17,8 @@ export enum QueryKeys {
|
||||
chartsMarket = 'charts-market',
|
||||
indexBlocks='indexBlocks',
|
||||
indexTxs='indexTxs',
|
||||
jsonRpcUrl='json-rpc-url'
|
||||
jsonRpcUrl='json-rpc-url',
|
||||
address='address',
|
||||
addressCounters='address-counters',
|
||||
addressTokenBalances='address-token-balances',
|
||||
}
|
||||
|
||||
+2
-1
@@ -17,7 +17,8 @@ export interface NetworkExplorer {
|
||||
title: string;
|
||||
baseUrl: string;
|
||||
paths: {
|
||||
tx: string;
|
||||
tx?: string;
|
||||
address?: string;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
import { Box, Flex, Text, Icon, Button, Grid, Select } from '@chakra-ui/react';
|
||||
import type { UseQueryResult } from '@tanstack/react-query';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
|
||||
import type { Address as TAddress, AddressCounters, AddressTokenBalance } from 'types/api/address';
|
||||
import { QueryKeys } from 'types/client/queries';
|
||||
|
||||
import appConfig from 'configs/app/config';
|
||||
import metamaskIcon from 'icons/metamask.svg';
|
||||
import qrCodeIcon from 'icons/qr_code.svg';
|
||||
import starOutlineIcon from 'icons/star_outline.svg';
|
||||
import walletIcon from 'icons/wallet.svg';
|
||||
import useFetch from 'lib/hooks/useFetch';
|
||||
import useIsMobile from 'lib/hooks/useIsMobile';
|
||||
import AddressIcon from 'ui/shared/address/AddressIcon';
|
||||
import CopyToClipboard from 'ui/shared/CopyToClipboard';
|
||||
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
|
||||
import ExternalLink from 'ui/shared/ExternalLink';
|
||||
import HashStringShorten from 'ui/shared/HashStringShorten';
|
||||
|
||||
interface Props {
|
||||
addressQuery: UseQueryResult<TAddress>;
|
||||
}
|
||||
|
||||
const AddressDetails = ({ addressQuery }: Props) => {
|
||||
const router = useRouter();
|
||||
const fetch = useFetch();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const countersQuery = useQuery<unknown, unknown, AddressCounters>(
|
||||
[ QueryKeys.addressCounters, router.query.id ],
|
||||
async() => await fetch(`/node-api/addresses/${ router.query.id }/counters`),
|
||||
{
|
||||
enabled: Boolean(router.query.id) && Boolean(addressQuery.data),
|
||||
},
|
||||
);
|
||||
|
||||
const tokenBalancesQuery = useQuery<unknown, unknown, Array<AddressTokenBalance>>(
|
||||
[ QueryKeys.addressTokenBalances, router.query.id ],
|
||||
async() => await fetch(`/node-api/addresses/${ router.query.id }/token-balances`),
|
||||
{
|
||||
enabled: Boolean(router.query.id) && Boolean(addressQuery.data),
|
||||
},
|
||||
);
|
||||
|
||||
if (countersQuery.isLoading || addressQuery.isLoading || tokenBalancesQuery.isLoading) {
|
||||
return <Box>loading</Box>;
|
||||
}
|
||||
|
||||
if (countersQuery.isError || addressQuery.isError || tokenBalancesQuery.isError) {
|
||||
return <Box>error</Box>;
|
||||
}
|
||||
|
||||
const explorers = appConfig.network.explorers.filter(({ paths }) => paths.address);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Flex alignItems="center">
|
||||
<AddressIcon hash={ addressQuery.data.hash }/>
|
||||
<Text ml={ 2 } fontFamily="heading" fontWeight={ 500 }>
|
||||
{ isMobile ? <HashStringShorten hash={ addressQuery.data.hash }/> : addressQuery.data.hash }
|
||||
</Text>
|
||||
<CopyToClipboard text={ addressQuery.data.hash }/>
|
||||
<Icon as={ metamaskIcon } boxSize={ 6 } ml={ 2 }/>
|
||||
<Button variant="outline" size="sm" ml={ 3 }>
|
||||
<Icon as={ starOutlineIcon } boxSize={ 5 }/>
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" ml={ 2 }>
|
||||
<Icon as={ qrCodeIcon } boxSize={ 5 }/>
|
||||
</Button>
|
||||
</Flex>
|
||||
{ explorers.length > 0 && (
|
||||
<Flex mt={ 8 } columnGap={ 4 } flexWrap="wrap">
|
||||
<Text>Verify with other explorers</Text>
|
||||
{ explorers.map((explorer) => {
|
||||
const url = new URL(explorer.paths.tx + '/' + router.query.id, explorer.baseUrl);
|
||||
return <ExternalLink key={ explorer.baseUrl } title={ explorer.title } href={ url.toString() }/>;
|
||||
}) }
|
||||
</Flex>
|
||||
) }
|
||||
<Grid
|
||||
mt={ 8 }
|
||||
columnGap={ 8 }
|
||||
rowGap={{ base: 3, lg: 3 }}
|
||||
templateColumns={{ base: 'minmax(0, 1fr)', lg: 'auto minmax(0, 1fr)' }} overflow="hidden"
|
||||
>
|
||||
<DetailsInfoItem
|
||||
title="Tokens"
|
||||
hint="All tokens in the account and total value."
|
||||
alignSelf="center"
|
||||
>
|
||||
{ tokenBalancesQuery.data.length > 0 ? (
|
||||
<>
|
||||
{ /* TODO will be fixed later when we implement select with custom menu */ }
|
||||
<Select
|
||||
size="sm"
|
||||
borderRadius="base"
|
||||
focusBorderColor="none"
|
||||
display="inline-block"
|
||||
w="auto"
|
||||
>
|
||||
{ tokenBalancesQuery.data.map((token) =>
|
||||
<option key={ token.token.address } value={ token.token.address }>{ token.token.symbol }</option>) }
|
||||
</Select>
|
||||
<Button variant="outline" size="sm" ml={ 3 }>
|
||||
<Icon as={ walletIcon } boxSize={ 5 }/>
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
'-'
|
||||
) }
|
||||
</DetailsInfoItem>
|
||||
<DetailsInfoItem
|
||||
title="Transactions"
|
||||
hint="Number of transactions related to this address."
|
||||
>
|
||||
{ Number(countersQuery.data.transaction_count).toLocaleString() }
|
||||
</DetailsInfoItem>
|
||||
<DetailsInfoItem
|
||||
title="Transfers"
|
||||
hint="Number of transfers to/from this address."
|
||||
>
|
||||
{ Number(countersQuery.data.token_transfer_count).toLocaleString() }
|
||||
</DetailsInfoItem>
|
||||
<DetailsInfoItem
|
||||
title="Gas used"
|
||||
hint="Gas used by the address."
|
||||
>
|
||||
{ BigNumber(countersQuery.data.gas_usage_count).toFormat() }
|
||||
</DetailsInfoItem>
|
||||
{ countersQuery.data.validation_count && (
|
||||
<DetailsInfoItem
|
||||
title="Blocks validated"
|
||||
hint="Number of blocks validated by this validator."
|
||||
>
|
||||
{ Number(countersQuery.data.validation_count).toLocaleString() }
|
||||
</DetailsInfoItem>
|
||||
) }
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(AddressDetails);
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Flex, Tag } from '@chakra-ui/react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
|
||||
import type { Address } from 'types/api/address';
|
||||
import { QueryKeys } from 'types/client/queries';
|
||||
|
||||
import useFetch from 'lib/hooks/useFetch';
|
||||
import AddressDetails from 'ui/address/AddressDetails';
|
||||
import Page from 'ui/shared/Page/Page';
|
||||
import PageTitle from 'ui/shared/Page/PageTitle';
|
||||
|
||||
const AddressPageContent = () => {
|
||||
const router = useRouter();
|
||||
const fetch = useFetch();
|
||||
|
||||
const addressQuery = useQuery<unknown, unknown, Address>(
|
||||
[ QueryKeys.address, router.query.id ],
|
||||
async() => await fetch(`/node-api/addresses/${ router.query.id }`),
|
||||
{
|
||||
enabled: Boolean(router.query.id),
|
||||
},
|
||||
);
|
||||
|
||||
const tags = [
|
||||
...(addressQuery.data?.private_tags || []),
|
||||
...(addressQuery.data?.public_tags || []),
|
||||
...(addressQuery.data?.watchlist_names || []),
|
||||
].map((tag) => <Tag key={ tag.label }>{ tag.display_name }</Tag>);
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<Flex alignItems="center" columnGap={ 3 }>
|
||||
<PageTitle text={ `${ addressQuery.data?.is_contract ? 'Contract' : 'Address' } details` }/>
|
||||
{ tags.length > 0 && (
|
||||
<Flex mb={ 6 } columnGap={ 2 }>
|
||||
{ tags }
|
||||
</Flex>
|
||||
) }
|
||||
</Flex>
|
||||
<AddressDetails addressQuery={ addressQuery }/>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddressPageContent;
|
||||
Reference in New Issue
Block a user