Commit 389cbeb4 authored by tom's avatar tom

Merge branch 'main' of github.com:blockscout/frontend into tx-state-api

parents 54cae6f5 fcddd709
......@@ -62,3 +62,4 @@ NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID=__PLACEHOLDER_FOR_NEXT_PUBLIC_GOOGLE_AN
# l2 config
NEXT_PUBLIC_IS_L2_NETWORK=__PLACEHOLDER_FOR_NEXT_PUBLIC_IS_L2_NETWORKL__
NEXT_PUBLIC_L1_BASE_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_L1_BASE_URL__
NEXT_PUBLIC_L2_WITHDRAWAL_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_L2_WITHDRAWAL_URL__
......@@ -52,7 +52,6 @@ jobs:
name: Run unit tests with Jest
needs: [ lint, type_check ]
runs-on: ubuntu-latest
if: ${{ false }} # disable since there are no jest test yet
steps:
- name: Checkout repo
uses: actions/checkout@v3
......
......@@ -139,6 +139,7 @@ The app instance could be customized by passing following variables to NodeJS en
| --- | --- | --- | --- |
| NEXT_PUBLIC_IS_L2_NETWORK | `boolean` *(optional)* | Set to true for L2 solutions (Optimism Bedrock based) | false |
| NEXT_PUBLIC_L1_BASE_URL | `string` *(optional)* | Base Blockscout URL for L1 network | `'http://eth-goerli.blockscout.com'` |
| NEXT_PUBLIC_L2_WITHDRAWAL_URL | `string` *(optional)* | URL for L2 -> L1 withdrawals | `https://app.optimism.io/bridge/withdraw` |
### Marketplace app configuration properties
......
......@@ -108,6 +108,7 @@ const config = Object.freeze({
L2: {
isL2Network: getEnvValue(process.env.NEXT_PUBLIC_IS_L2_NETWORK) === 'true',
L1BaseUrl: getEnvValue(process.env.NEXT_PUBLIC_L1_BASE_URL),
withdrawalUrl: getEnvValue(process.env.NEXT_PUBLIC_L2_WITHDRAWAL_URL) || '',
},
statsApi: {
endpoint: getEnvValue(process.env.NEXT_PUBLIC_STATS_API_HOST),
......
This diff is collapsed.
......@@ -29,5 +29,5 @@ NEXT_PUBLIC_STATS_API_HOST=https://stats-test.aws-k8s.blockscout.com
# l2 config
NEXT_PUBLIC_IS_L2_NETWORK=true
NEXT_PUBLIC_L1_BASE_URL=https://blockscout-main.test.aws-k8s.blockscout.com/
NEXT_PUBLIC_L1_BASE_URL=https://blockscout-main.test.aws-k8s.blockscout.com
NEXT_PUBLIC_L2_WITHDRAWAL_URL=https://app.optimism.io/bridge/withdraw
\ No newline at end of file
......@@ -5,7 +5,7 @@ blockscout:
app: blockscout
enabled: true
image:
_default: &image blockscout/blockscout-optimism-l2-advanced:5.1.0-prerelease-7a8c745e
_default: &image blockscout/blockscout-optimism-l2-advanced:5.1.0-prerelease-303a0afa
replicas:
app: 1
# init container
......@@ -110,33 +110,37 @@ blockscout:
API_V2_ENABLED:
_default: 'true'
FIRST_BLOCK:
_default: '4066066'
_default: '4667000'
TRACE_FIRST_BLOCK:
_default: '4066066'
_default: '4667000'
LAST_BLOCK:
_default: '4076066'
_default: '4677000'
TRACE_LAST_BLOCK:
_default: '4076066'
_default: '4677000'
DISABLE_REALTIME_INDEXER:
_default: 'true'
INDEXER_OPTIMISM_PORTAL_L1:
_default: 'false'
INDEXER_OPTIMISM_L1_RPC:
_default: http://65.108.226.29:8545
INDEXER_OPTIMISM_L1_PORTAL_CONTRACT:
_default: 0x5b47E1A08Ea6d985D6649300584e6722Ec4B1383
INDEXER_OPTIMISM_WITHDRAWALS_START_BLOCK_L1:
INDEXER_OPTIMISM_L1_WITHDRAWALS_START_BLOCK:
_default: '8299683'
INDEXER_OPTIMISM_WITHDRAWALS_START_BLOCK_L2:
INDEXER_OPTIMISM_L2_WITHDRAWALS_START_BLOCK:
_default: '4066066'
INDEXER_OPTIMISM_MESSAGE_PASSER_L2:
INDEXER_OPTIMISM_L2_MESSAGE_PASSER_CONTRACT:
_default: 0x4200000000000000000000000000000000000016
INDEXER_OPTIMISM_OUTPUT_ROOTS_START_BLOCK_L1:
INDEXER_OPTIMISM_L1_OUTPUT_ROOTS_START_BLOCK:
_default: '8299683'
INDEXER_OPTIMISM_OUTPUT_ORACLE_L1:
INDEXER_OPTIMISM_L1_OUTPUT_ORACLE_CONTRACT:
_default: 0xE6Dfba0953616Bacab0c9A8ecb3a9BBa77FC15c0
INDEXER_OPTIMISM_BATCH_START_BLOCK_L1:
INDEXER_OPTIMISM_L1_BATCH_START_BLOCK:
_default: '8381594'
INDEXER_OPTIMISM_BATCH_INBOX:
INDEXER_OPTIMISM_L1_BATCH_INBOX:
_default: 0xff00000000000000000000000000000000000420
INDEXER_OPTIMISM_BATCH_SUBMITTER:
INDEXER_OPTIMISM_L1_BATCH_SUBMITTER:
_default: 0x7431310e026b69bfc676c0013e12a1a11411eec9
INDEXER_OPTIMISM_L1_DEPOSITS_START_BLOCK:
_default: '8381594'
postgres:
enabled: true
......@@ -310,13 +314,16 @@ frontend:
- "/search-results"
- "/token"
- "/tokens"
- "/accounts"
- "/visualize"
- "/api-docs"
- "/csv-export"
- "/verified-contracts"
- "/graphiql"
- "/accounts"
- "/visualize"
- "/api-docs"
- "/output-roots"
- "/txn-batches"
- "/withdrawals"
- "/deposits"
resources:
limits:
memory:
......@@ -396,7 +403,7 @@ frontend:
NEXT_PUBLIC_IS_L2_NETWORK:
_default: "true"
NEXT_PUBLIC_L1_BASE_URL:
_default: https://blockscout-main.test.aws-k8s.blockscout.com
_default: https://eth-goerli.blockscout.com/
NEXT_PUBLIC_L2_WITHDRAWAL_URL:
_default: https://app.optimism.io/bridge/withdraw
NEXT_PUBLIC_GRAPHIQL_TRANSACTION:
......
......@@ -175,12 +175,12 @@ postgres:
resources:
limits:
memory:
_default: "6Gi"
_default: "8Gi"
cpu:
_default: "2"
requests:
memory:
_default: "6Gi"
_default: "8Gi"
cpu:
_default: "2"
# node label
......@@ -303,12 +303,12 @@ frontend:
memory:
_default: "0.1Gi"
cpu:
_default: "0.2"
_default: "0.5"
requests:
memory:
_default: "0.1Gi"
cpu:
_default: "0.2"
_default: "0.5"
environment:
# ui config
NEXT_PUBLIC_FEATURED_NETWORKS:
......
......@@ -40,6 +40,10 @@ frontend:
- "/csv-export"
- "/verified-contracts"
- "/graphiql"
- "/output-roots"
- "/txn-batches"
- "/withdrawals"
- "/deposits"
resources:
limits:
......
......@@ -44,14 +44,14 @@ frontend:
resources:
limits:
memory:
_default: "0.1Gi"
_default: "2Gi"
cpu:
_default: "0.1"
_default: "2"
requests:
memory:
_default: "0.1Gi"
_default: "2Gi"
cpu:
_default: "0.1"
_default: "2"
environment:
NEXT_PUBLIC_BLOCKSCOUT_VERSION:
_default: v4.1.8-beta
......
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<path fill="currentColor" fill-rule="evenodd" d="M14.806 21.313H4.582A.583.583 0 0 1 4 20.731V6.179c0-.322.261-.583.582-.583h2.654V3.27c0-.321.26-.582.582-.582h7.313c.007 0 .013.002.02.004.005.001.01.003.017.003a.558.558 0 0 1 .153.031l.02.006a.575.575 0 0 1 .194.118l4.285 4.11-.002.002a.58.58 0 0 1 .181.419v9.064a1.96 1.96 0 0 1-1.958 1.959h-1.277v.95a1.96 1.96 0 0 1-1.96 1.959ZM18.31 6.798l-2.598-2.506v1.713c0 .437.356.793.793.793h1.805Zm-3.42-3.289H8.058v14.072h10.327a.794.794 0 0 0 .793-.793V7.62h-2.671c-1.08 0-1.616-.535-1.616-1.615V3.509ZM7.236 6.42H4.822v14.07H15.15c.437 0 .793-.7.793-1.136v-.951H7.818a.582.582 0 0 1-.582-.583V6.42Zm9.482 4.532a.39.39 0 1 0 0-.78h-5.12l.502-.504a.39.39 0 0 0-.55-.549l-1.168 1.169a.39.39 0 0 0 .059.599.39.39 0 0 0 .216.065h6.06Zm-.012 1.363h-6.061a.39.39 0 0 0 0 .779h5.12l-.502.504a.39.39 0 1 0 .549.55l1.168-1.17a.39.39 0 0 0-.058-.598.39.39 0 0 0-.216-.065Z" clip-rule="evenodd"/>
<path fill="currentColor" d="M7.236 5.596v.25h.25v-.25h-.25Zm7.915-2.905-.07.24.07-.24Zm.017.003.014-.25-.014.25Zm.153.031.085-.235-.003-.001-.082.236Zm.02.006.072-.239-.072.24Zm.031.012.104-.228h-.001l-.103.228Zm.162.106.173-.18-.173.18Zm4.287 4.111.177.177.18-.18-.184-.177-.173.18Zm-.002.002-.176-.177-.18.18.183.177.173-.18Zm-3.054 11.442v-.25h-.25v.25h.25ZM15.713 4.292l.174-.18-.424-.408v.588h.25Zm2.598 2.506v.25h.62l-.446-.43-.174.18ZM8.058 3.51v-.25h-.25v.25h.25Zm6.833 0h.25v-.25h-.25v.25ZM8.058 17.581h-.25v.25h.25v-.25Zm11.12-9.96h.25v-.25h-.25v.25ZM4.822 6.418v-.25h-.25v.25h.25Zm2.414 0h.25v-.25h-.25v.25ZM4.822 20.49h-.25v.25h.25v-.25Zm11.12-2.087h.25v-.25h-.25v.25Zm1.051-7.567-.177-.177.177.177Zm0-.551-.177.177.177-.177Zm-5.396-.114-.177-.177-.425.427h.602v-.25Zm.503-.505.177.177.007-.007.006-.007-.19-.163Zm.093-.268.25-.01-.25.01Zm-.114-.26.177-.177-.177.177Zm-.26-.114.01-.25-.01.25Zm-.268.093-.163-.19-.007.007-.007.007.177.176Zm-1.169 1.169.177.177-.177-.177Zm-.107.199.245.05-.245-.05Zm.022.225-.232.095.001.001.23-.096Zm.143.175.139-.209-.139.209Zm.217.065v-.25.25Zm6.049 1.363v.25-.25Zm-6.337.114.177.177-.177-.177Zm0 .55.177-.176-.177.177Zm5.396.115.177.176.425-.426h-.602v.25Zm-.502.504.162.19.008-.007.007-.007-.177-.176Zm-.098.126.225.11-.225-.11Zm-.038.155-.25-.01.25.01Zm.026.157.233-.091-.233.09Zm.088.133-.177.177.177-.177Zm.29.114-.01-.25.01.25Zm.154-.039.11.225-.11-.225Zm.127-.097-.177-.177-.007.007-.006.007.19.163Zm1.168-1.168-.176-.178v.001l.176.177Zm.086-.425.23-.095v-.001l-.23.096Zm-.144-.174-.139.208.139-.208Zm-12.34 9.184h10.224v-.5H4.582v.5Zm-.832-.832c0 .46.373.832.832.832v-.5a.333.333 0 0 1-.332-.332h-.5Zm0-14.552V20.73h.5V6.179h-.5Zm.832-.833a.833.833 0 0 0-.832.833h.5c0-.184.149-.333.332-.333v-.5Zm2.654 0H4.582v.5h2.654v-.5Zm-.25-2.077v2.327h.5V3.27h-.5Zm.832-.832a.832.832 0 0 0-.832.832h.5c0-.183.148-.332.332-.332v-.5Zm7.313 0H7.818v.5h7.313v-.5Zm.09.014c-.002 0-.041-.014-.09-.014v.5a.202.202 0 0 1-.042-.004c-.007-.002-.013-.004-.009-.002l.14-.48Zm-.04-.006a.2.2 0 0 1 .034.004l.006.002-.14.48s.034.01.073.013l.027-.5Zm.222.044a.808.808 0 0 0-.22-.044l-.03.499a.307.307 0 0 1 .085.017l.165-.472Zm.01.003a2.077 2.077 0 0 1-.007-.002s-.001 0 0 0l-.17.47.032.01.145-.478Zm.062.022a.443.443 0 0 0-.062-.022l-.145.479a.198.198 0 0 1 .008.002l-.006-.002.205-.457Zm.232.154a.823.823 0 0 0-.231-.153l-.208.455c.041.018.07.038.093.06l.346-.362Zm4.287 4.112-4.287-4.111-.346.36 4.287 4.112.346-.361Zm.002.359.002-.002-.354-.354-.001.002.353.354Zm.254.242a.83.83 0 0 0-.257-.6l-.347.361a.33.33 0 0 1 .104.239h.5Zm0 9.064V7.381h-.5v9.064h.5Zm-2.208 2.209a2.21 2.21 0 0 0 2.208-2.209h-.5a1.71 1.71 0 0 1-1.708 1.709v.5Zm-1.277 0h1.277v-.5h-1.277v.5Zm.25.7v-.95h-.5v.95h.5Zm-2.21 2.209a2.21 2.21 0 0 0 2.21-2.208h-.5a1.71 1.71 0 0 1-1.71 1.708v.5Zm.735-17.09 2.598 2.505.347-.36-2.598-2.506-.348.36Zm.423 1.532V4.292h-.5v1.713h.5Zm.543.543a.544.544 0 0 1-.543-.543h-.5c0 .575.468 1.043 1.043 1.043v-.5Zm1.805 0h-1.805v.5h1.805v-.5ZM8.058 3.76h6.833v-.5H8.058v.5Zm.25 13.822V3.51h-.5v14.072h.5Zm10.077-.25H8.058v.5h10.327v-.5Zm.543-.543c0 .3-.244.543-.543.543v.5c.575 0 1.043-.468 1.043-1.043h-.5Zm0-9.168v9.168h.5V7.62h-.5Zm-2.421.25h2.67v-.5h-2.67v.5ZM14.64 6.005c0 .578.143 1.057.476 1.39.333.332.812.475 1.39.475v-.5c-.502 0-.831-.124-1.037-.33-.205-.205-.33-.533-.33-1.035h-.5Zm0-2.496v2.496h.5V3.509h-.5ZM4.822 6.67h2.414v-.5H4.822v.5Zm.25 13.822V6.419h-.5V20.49h.5Zm10.077-.25H4.822v.5h10.326v-.5Zm.543-.886c0 .162-.07.401-.195.599-.13.21-.264.287-.348.287v.5c.352 0 .616-.272.772-.522.164-.26.27-.59.27-.864h-.5Zm0-.951v.95h.5v-.95h-.5Zm-7.874.25h8.124v-.5H7.818v.5Zm-.832-.833c0 .46.372.833.832.833v-.5a.332.332 0 0 1-.332-.333h-.5Zm0-11.402v11.4h.5V6.42h-.5Zm9.83 4.24a.14.14 0 0 1-.098.042v.5a.64.64 0 0 0 .452-.188l-.354-.353Zm.041-.098a.14.14 0 0 1-.04.099l.353.353a.64.64 0 0 0 .187-.452h-.5Zm-.04-.098a.14.14 0 0 1 .04.098h.5a.64.64 0 0 0-.187-.452l-.354.354Zm-.1-.041a.14.14 0 0 1 .1.04l.353-.353a.64.64 0 0 0-.452-.187v.5Zm-5.12 0h5.12v-.5h-5.12v.5Zm.326-.931-.503.504.355.353.502-.504-.354-.353Zm.02-.082a.14.14 0 0 1-.033.096l.38.325a.64.64 0 0 0 .153-.44l-.5.019Zm-.04-.093a.14.14 0 0 1 .04.093l.5-.02a.64.64 0 0 0-.187-.427l-.353.354Zm-.094-.041a.14.14 0 0 1 .094.04l.353-.353a.64.64 0 0 0-.427-.187l-.02.5Zm-.096.033a.14.14 0 0 1 .096-.033l.02-.5a.64.64 0 0 0-.44.153l.324.38Zm-1.154 1.155 1.168-1.168-.353-.353-1.168 1.168.353.354Zm-.039.072a.139.139 0 0 1 .039-.071l-.353-.355a.64.64 0 0 0-.176.328l.49.098Zm.008.081a.139.139 0 0 1-.008-.08l-.49-.1a.64.64 0 0 0 .036.37l.462-.19Zm.05.061a.14.14 0 0 1-.05-.062l-.462.192c.049.117.13.217.236.287l.277-.417Zm.078.024a.14.14 0 0 1-.077-.024l-.277.417a.64.64 0 0 0 .356.107l-.002-.5Zm6.062 0h-6.061v.5h6.06v-.5Zm-6.073 1.863h6.06v-.5h-6.06v.5Zm-.099.04a.14.14 0 0 1 .099-.04v-.5a.64.64 0 0 0-.452.187l.353.354Zm-.04.1a.14.14 0 0 1 .04-.1l-.353-.353a.639.639 0 0 0-.188.452h.5Zm.04.098a.14.14 0 0 1-.04-.099h-.5c0 .17.067.333.187.452l.353-.353Zm.099.04a.14.14 0 0 1-.099-.04l-.353.353a.64.64 0 0 0 .452.188v-.5Zm5.12 0h-5.12v.5h5.12v-.5Zm-.325.931.502-.504-.354-.353-.502.505.354.352Zm-.05.06a.138.138 0 0 1 .035-.046l-.325-.38a.639.639 0 0 0-.16.207l.45.218Zm-.014.054a.14.14 0 0 1 .014-.055l-.45-.218a.64.64 0 0 0-.063.254l.5.02Zm.01.057a.139.139 0 0 1-.01-.057l-.5-.019a.64.64 0 0 0 .045.258l.465-.182Zm.031.047a.139.139 0 0 1-.03-.047l-.466.182a.64.64 0 0 0 .143.219l.353-.354Zm.048.032a.139.139 0 0 1-.048-.032l-.353.354a.64.64 0 0 0 .219.143l.182-.465Zm.056.01a.139.139 0 0 1-.056-.01l-.182.465a.64.64 0 0 0 .258.044l-.02-.5Zm.056-.015a.138.138 0 0 1-.056.014l.02.5a.64.64 0 0 0 .253-.064l-.217-.45Zm.045-.035a.138.138 0 0 1-.045.035l.217.45a.64.64 0 0 0 .208-.16l-.38-.325Zm1.181-1.182-1.168 1.168.354.354 1.168-1.168-.354-.354Zm.04-.072a.139.139 0 0 1-.04.071l.353.355a.64.64 0 0 0 .176-.327l-.49-.099Zm-.009-.08a.14.14 0 0 1 .008.08l.49.099a.64.64 0 0 0-.035-.37l-.463.19Zm-.05-.062a.14.14 0 0 1 .051.063l.461-.193a.64.64 0 0 0-.236-.286l-.276.416Zm-.078-.023a.14.14 0 0 1 .078.023l.276-.416a.639.639 0 0 0-.355-.107l.001.5Z"/>
</svg>
......@@ -17,10 +17,12 @@ import type { AddressesResponse } from 'types/api/addresses';
import type { BlocksResponse, BlockTransactionsResponse, Block, BlockFilters } from 'types/api/block';
import type { ChartMarketResponse, ChartTransactionResponse } from 'types/api/charts';
import type { SmartContract, SmartContractReadMethod, SmartContractWriteMethod, SmartContractVerificationConfig } from 'types/api/contract';
import type { VerifiedContractsResponse, VerifiedContractsFilters } from 'types/api/contracts';
import type { VerifiedContractsResponse, VerifiedContractsFilters, VerifiedContractsCounters } from 'types/api/contracts';
import type { DepositsResponse } from 'types/api/deposits';
import type { IndexingStatus } from 'types/api/indexingStatus';
import type { InternalTransactionsResponse } from 'types/api/internalTransaction';
import type { LogsResponseTx, LogsResponseAddress } from 'types/api/log';
import type { OutputRootsResponse } from 'types/api/outputRoots';
import type { RawTracesResponse } from 'types/api/rawTrace';
import type { SearchResult, SearchResultFilters } from 'types/api/search';
import type { Counters, StatsCharts, StatsChart, HomeStats } from 'types/api/stats';
......@@ -35,9 +37,11 @@ import type {
import type { TokensResponse, TokensFilters, TokenInstanceTransferResponse } from 'types/api/tokens';
import type { TokenTransferResponse, TokenTransferFilters } from 'types/api/tokenTransfer';
import type { TransactionsResponseValidated, TransactionsResponsePending, Transaction } from 'types/api/transaction';
import type { TxnBatchesResponse } from 'types/api/txnBatches';
import type { TTxsFilters } from 'types/api/txsFilters';
import type { TxStateChanges } from 'types/api/txStateChanges';
import type { VisualizedContract } from 'types/api/visualization';
import type { WithdrawalsResponse } from 'types/api/withdrawals';
import type ArrayElement from 'types/utils/ArrayElement';
import appConfig from 'configs/app/config';
......@@ -269,6 +273,9 @@ export const RESOURCES = {
paginationFields: [ 'items_count' as const, 'smart_contract_id' as const ],
filterFields: [ 'q' as const, 'filter' as const ],
},
verified_contracts_counters: {
path: '/api/v2/smart-contracts/counters',
},
// TOKEN
token: {
......@@ -364,6 +371,47 @@ export const RESOURCES = {
path: '/graphql',
},
// L2
deposits: {
path: '/api/v2/optimism/deposits',
paginationFields: [ 'nonce' as const, 'items_count' as const ],
filterFields: [],
},
deposits_count: {
path: '/api/v2/optimism/deposits/count',
},
withdrawals: {
path: '/api/v2/optimism/withdrawals',
paginationFields: [ 'nonce' as const, 'items_count' as const ],
filterFields: [],
},
withdrawals_count: {
path: '/api/v2/optimism/withdrawals/count',
},
output_roots: {
path: '/api/v2/optimism/output-roots',
paginationFields: [ 'index' as const, 'items_count' as const ],
filterFields: [],
},
output_roots_count: {
path: '/api/v2/optimism/output-roots/count',
},
txn_batches: {
path: '/api/v2/optimism/txn-batches',
paginationFields: [ 'block_number' as const, 'items_count' as const ],
filterFields: [],
},
txn_batches_count: {
path: '/api/v2/optimism/txn-batches/count',
},
// DEPRECATED
old_api: {
path: '/api',
......@@ -422,7 +470,8 @@ export type PaginatedResources = 'blocks' | 'block_txs' |
'address_logs' | 'address_tokens' |
'token_transfers' | 'token_holders' | 'token_inventory' | 'tokens' |
'token_instance_transfers' |
'verified_contracts';
'verified_contracts' |
'output_roots' | 'withdrawals' | 'txn_batches' | 'deposits';
export type PaginatedResponse<Q extends PaginatedResources> = ResourcePayload<Q>;
......@@ -482,8 +531,17 @@ Q extends 'contract_methods_read_proxy' ? Array<SmartContractReadMethod> :
Q extends 'contract_methods_write' ? Array<SmartContractWriteMethod> :
Q extends 'contract_methods_write_proxy' ? Array<SmartContractWriteMethod> :
Q extends 'verified_contracts' ? VerifiedContractsResponse :
Q extends 'verified_contracts_counters' ? VerifiedContractsCounters :
Q extends 'visualize_sol2uml' ? VisualizedContract :
Q extends 'contract_verification_config' ? SmartContractVerificationConfig :
Q extends 'output_roots' ? OutputRootsResponse :
Q extends 'withdrawals' ? WithdrawalsResponse :
Q extends 'deposits' ? DepositsResponse :
Q extends 'txn_batches' ? TxnBatchesResponse :
Q extends 'output_roots_count' ? number :
Q extends 'withdrawals_count' ? number :
Q extends 'deposits_count' ? number :
Q extends 'txn_batches_count' ? number :
never;
/* eslint-enable @typescript-eslint/indent */
......
......@@ -8,6 +8,7 @@ function generateCspPolicy() {
descriptors.googleAnalytics(),
descriptors.googleFonts(),
descriptors.googleReCaptcha(),
descriptors.monaco(),
descriptors.sentry(),
descriptors.walletConnect(),
);
......
......@@ -3,5 +3,6 @@ export { app } from './app';
export { googleAnalytics } from './googleAnalytics';
export { googleFonts } from './googleFonts';
export { googleReCaptcha } from './googleReCaptcha';
export { monaco } from './monaco';
export { sentry } from './sentry';
export { walletConnect } from './walletConnect';
import type CspDev from 'csp-dev';
import { KEY_WORDS } from '../utils';
export function monaco(): CspDev.DirectiveDescriptor {
return {
'script-src': [
KEY_WORDS.BLOB,
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/loader.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/editor/editor.main.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/editor/editor.main.nls.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/basic-languages/solidity/solidity.js',
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/base/worker/workerMain.js',
],
'style-src': [
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/editor/editor.main.css',
],
'font-src': [
'https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/min/vs/base/browser/ui/codicons/codicon/codicon.ttf',
],
};
}
......@@ -6,12 +6,13 @@ import appConfig from 'configs/app/config';
import abiIcon from 'icons/ABI.svg';
import apiKeysIcon from 'icons/API.svg';
import appsIcon from 'icons/apps.svg';
// import withdrawalsIcon from 'icons/arrows/north-east.svg';
import withdrawalsIcon from 'icons/arrows/north-east.svg';
import depositsIcon from 'icons/arrows/south-east.svg';
import blocksIcon from 'icons/block.svg';
import gearIcon from 'icons/gear.svg';
import globeIcon from 'icons/globe-b.svg';
import graphQLIcon from 'icons/graphQL.svg';
// import outputRootsIcon from 'icons/output_roots.svg';
import outputRootsIcon from 'icons/output_roots.svg';
import privateTagIcon from 'icons/privattags.svg';
import profileIcon from 'icons/profile.svg';
import publicTagIcon from 'icons/publictags.svg';
......@@ -21,11 +22,10 @@ import statsIcon from 'icons/stats.svg';
import tokensIcon from 'icons/token.svg';
import topAccountsIcon from 'icons/top-accounts.svg';
import transactionsIcon from 'icons/transactions.svg';
// import depositsIcon from 'icons/arrows/south-east.svg';
// import txnBatchIcon from 'icons/txn_batches.svg';
import txnBatchIcon from 'icons/txn_batches.svg';
import verifiedIcon from 'icons/verified.svg';
import watchlistIcon from 'icons/watchlist.svg';
// import { rightLineArrow } from 'lib/html-entities';
import { rightLineArrow } from 'lib/html-entities';
type NavItemCommon = {
text: string;
......@@ -83,14 +83,15 @@ export default function useNavItems(): ReturnType {
const blocks = {
text: 'Blocks',
nextRoute: { pathname: '/blocks' as const },
icon: blocksIcon, isActive: pathname.startsWith('/block'),
icon: blocksIcon,
isActive: pathname === '/blocks' || pathname === '/block/[height]',
isNewUi: true,
};
const txs = {
text: 'Transactions',
nextRoute: { pathname: '/txs' as const },
icon: transactionsIcon,
isActive: pathname.startsWith('/tx'),
isActive: pathname === '/txs' || pathname === '/tx/[hash]',
isNewUi: true,
};
const verifiedContracts =
......@@ -102,16 +103,16 @@ export default function useNavItems(): ReturnType {
[
txs,
// eslint-disable-next-line max-len
// { text: `Deposits (L1${ rightLineArrow }L2)`, nextRoute: { pathname: '/deposits' as const }, icon: depositsIcon, isActive: pathname === '/deposits', isNewUi: true },
{ text: `Deposits (L1${ rightLineArrow }L2)`, nextRoute: { pathname: '/deposits' as const }, icon: depositsIcon, isActive: pathname === '/deposits', isNewUi: true },
// eslint-disable-next-line max-len
// { text: `Withdrawals (L2${ rightLineArrow }L1)`, nextRoute: { pathname: '/withdrawals' as const }, icon: withdrawalsIcon, isActive: pathname === '/withdrawals', isNewUi: true },
{ text: `Withdrawals (L2${ rightLineArrow }L1)`, nextRoute: { pathname: '/withdrawals' as const }, icon: withdrawalsIcon, isActive: pathname === '/withdrawals', isNewUi: true },
],
[
blocks,
// eslint-disable-next-line max-len
// { text: 'Txn batches', nextRoute: { pathname: '/txn-batches' as const }, icon: txnBatchIcon, isActive: pathname === '/txn-batches', isNewUi: true },
{ text: 'Txn batches', nextRoute: { pathname: '/txn-batches' as const }, icon: txnBatchIcon, isActive: pathname === '/txn-batches', isNewUi: true },
// eslint-disable-next-line max-len
// { text: 'Output roots', nextRoute: { pathname: '/output-roots' as const }, icon: outputRootsIcon, isActive: pathname === '/output-roots', isNewUi: true },
{ text: 'Output roots', nextRoute: { pathname: '/output-roots' as const }, icon: outputRootsIcon, isActive: pathname === '/output-roots', isNewUi: true },
],
[
topAccounts,
......
......@@ -19,3 +19,6 @@ export const minus = String.fromCharCode(8722); // −
export const leftLineArrow = String.fromCharCode(8592); // ←
export const rightLineArrow = String.fromCharCode(8594); // →
export const apos = String.fromCharCode(39); // apostrophe '
export const shift = String.fromCharCode(8679); // upwards white arrow ⇧
export const cmd = String.fromCharCode(8984); // place of interest sign ⌘
export const alt = String.fromCharCode(9095); // alternate key symbol ⎇
export default function isMetaKey(event: React.KeyboardEvent) {
return event.metaKey || event.getModifierState('Meta') || event.getModifierState('OS');
}
const stripLeadingSlash = (str: string) => str[0] === '/' ? str.slice(1) : str;
export default stripLeadingSlash;
import type { VerifiedContractsCounters } from 'types/api/contracts';
export const verifiedContractsCountersMock: VerifiedContractsCounters = {
smart_contracts: '123456789',
new_smart_contracts_24h: '12345',
verified_smart_contracts: '654321',
new_verified_smart_contracts_24h: '0',
};
export const data = {
items: [
{
l1_block_number: 8382841,
l1_block_timestamp: '2022-05-27T01:13:48.000000Z',
l1_tx_hash: '0xaf3e5f4ef03eac22a622b3434c5dc9f4465aa291900a86bcf0ad9fb14429f05e',
l1_tx_origin: '0x6197d1eef304eb5284a0f6720f79403b4e9bf3a5',
l2_tx_gas_limit: '2156928',
l2_tx_hash: '0xb9212c76069b926917816767e4c5a0ef80e519b1ac1c3d3fb5818078f4984667',
},
{
l1_block_number: 8382841,
l1_block_timestamp: '2022-05-27T01:13:48.000000Z',
l1_tx_hash: '0xa280f18cc72f9ad904087eb262c236048e935ad184a85bbd042d544c172c10bf',
l1_tx_origin: '0x6197d1eef304eb5284a0f6720f79403b4e9bf3a5',
l2_tx_gas_limit: '1216064',
l2_tx_hash: '0xaaaeb47a78b5c42d870f8d831a683a7cefe1b031a992170b28b43b82bd08318c',
},
{
l1_block_number: 8382834,
l1_block_timestamp: '2022-06-27T01:11:48.000000Z',
l1_tx_hash: '0xfca8cc5440bffa8b975873c02bba3ff3380dd75fbc3260d10179e282cf72d6d4',
l1_tx_origin: '0x6197d1eef304eb5284a0f6720f79403b4e9bf3a5',
l2_tx_gas_limit: '405824',
l2_tx_hash: '0xa0604ebf2614ad708aeefa83f766fb25928dadb5ffb2f45028f5b4f1fa4d9358',
},
],
next_page_params: {
items_count: 50,
l1_block_number: 8382363,
tx_hash: '0x2012f0ce966ce6573e7826e9235f227edf5a2f8382b8d646c979f85a77e15c05',
},
};
export const outputRootsData = {
items: [
{
l1_block_number: 8456113,
l1_timestamp: '2022-02-08T12:08:48.000000Z',
l1_tx_hash: '0x19455a53758d5de89070164ff09c40d93f1b4447e721090f03aa150f6159265a',
l2_block_number: 5214988,
l2_output_index: 9926,
output_root: '0xa7de9bd3986ce5ca8de9f0ab6c7473f4cebe225fb13b57cc5c8472de84a8bab3',
},
{
l1_block_number: 8456099,
l1_timestamp: '2022-02-08T12:05:24.000000Z',
l1_tx_hash: '0x6aa081e8e33a085e4ec7124fcd8a5f7d36aac0828f176e80d4b70e313a11695b',
l2_block_number: 5214868,
l2_output_index: 9925,
output_root: '0x4ec2822d2f7b4f834d693d88f8a4cf15899882915980a21756d29cfd9f9f3898',
},
{
l1_block_number: 8456078,
l1_timestamp: '2022-02-08T12:00:48.000000Z',
l1_tx_hash: '0x4238988b0959e41a7b09cef67f58698e05e3bcc29b8d2f60e6c77dc68c91f16e',
l2_block_number: 5214748,
l2_output_index: 9924,
output_root: '0x78b2e13c20f4bbfb4a008127edaaf25aa476f933669edd4856305bf4ab64a92b',
},
],
next_page_params: {
index: 9877,
items_count: 50,
},
};
export const txnBatchesData = {
items: [
{
epoch_number: 8547349,
l1_tx_hashes: [
'0x5bc94d02b65743dfaa9e10a2d6e175aff2a05cce2128c8eaf848bd84ab9325c5',
'0x92a51bc623111dbb91f243e3452e60fab6f090710357f9d9b75ac8a0f67dfd9d',
],
l1_timestamp: '2023-02-24T10:16:12.000000Z',
l2_block_number: 5902836,
tx_count: 0,
},
{
epoch_number: 8547348,
l1_tx_hashes: [
'0xc45f846ee28ce9ba116ce2d378d3dd00b55d324b833b3ecd4241c919c572c4aa',
],
l1_timestamp: '2023-02-24T10:16:00.000000Z',
l2_block_number: 5902835,
tx_count: 0,
},
{
epoch_number: 8547348,
l1_tx_hashes: [
'0x48139721f792d3a68c3781b4cf50e66e8fc7dbb38adff778e09066ea5be9adb8',
],
l1_timestamp: '2023-02-24T10:16:00.000000Z',
l2_block_number: 5902834,
tx_count: 0,
},
],
next_page_params: {
block_number: 5902834,
items_count: 50,
},
};
export const data = {
items: [
{
challenge_period_end: null,
from: {
hash: '0x67aab90c548b284be30b05c376001b4db90b87ba',
implementation_name: null,
is_contract: false,
is_verified: false,
name: null,
private_tags: [],
public_tags: [],
watchlist_names: [],
},
l1_tx_hash: '0x1a235bee32ac10cb7efdad98415737484ca66386e491cde9e17d42b136dca684',
l2_timestamp: '2022-02-15T12:50:02.000000Z',
l2_tx_hash: '0x918cd8c5c24c17e06cd02b0379510c4ad56324bf153578fb9caaaa2fe4e7dc35',
msg_nonce: 396,
msg_nonce_raw: '1766847064778384329583297500742918515827483896875618958121606201292620172',
msg_nonce_version: 1,
status: 'Ready to prove',
},
{
challenge_period_end: null,
from: null,
l1_tx_hash: null,
l2_timestamp: null,
l2_tx_hash: '0x2f117bee32ac10cb7efdad98415737484ca66386e491cde9e17d42b136def593',
msg_nonce: 391,
msg_nonce_raw: '1766847064778384329583297500742918515827483896875618958121606201292620167',
msg_nonce_version: 1,
status: 'Ready to prove',
},
{
challenge_period_end: '2022-11-11T12:50:02.000000Z',
from: null,
l1_tx_hash: null,
l2_timestamp: null,
l2_tx_hash: '0xe14b1f46838176702244a5343629bcecf728ca2d9881d47b4ce46e00c387d7e3',
msg_nonce: 390,
msg_nonce_raw: '1766847064778384329583297500742918515827483896875618958121606201292620166',
msg_nonce_version: 1,
status: 'Ready for relay',
},
],
next_page_params: {
items_count: 50,
nonce: '1766847064778384329583297500742918515827483896875618958121606201292620123',
},
};
import type { NextPage } from 'next';
import Head from 'next/head';
import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import Deposits from 'ui/pages/Deposits';
const DepositsPage: NextPage = () => {
const title = getNetworkTitle();
return (
<>
<Head>
<title>{ title }</title>
</Head>
<Deposits/>
</>
);
};
export default DepositsPage;
export { getServerSideProps } from 'lib/next/getServerSidePropsL2';
import type { NextPage } from 'next';
import Head from 'next/head';
import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import OutputRoots from 'ui/pages/OutputRoots';
const OutputRootsPage: NextPage = () => {
const title = getNetworkTitle();
return (
<>
<Head>
<title>{ title }</title>
</Head>
<OutputRoots/>
</>
);
};
export default OutputRootsPage;
export { getServerSideProps } from 'lib/next/getServerSidePropsL2';
import type { NextPage } from 'next';
import Head from 'next/head';
import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import TxnBatches from 'ui/pages/TxnBatches';
const TxnBatchesPage: NextPage = () => {
const title = getNetworkTitle();
return (
<>
<Head>
<title>{ title }</title>
</Head>
<TxnBatches/>
</>
);
};
export default TxnBatchesPage;
export { getServerSideProps } from 'lib/next/getServerSidePropsL2';
import type { NextPage } from 'next';
import Head from 'next/head';
import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import Withdrawals from 'ui/pages/Withdrawals';
const WithdrawalsPage: NextPage = () => {
const title = getNetworkTitle();
return (
<>
<Head>
<title>{ title }</title>
</Head>
<Withdrawals/>
</>
);
};
export default WithdrawalsPage;
export { getServerSideProps } from 'lib/next/getServerSidePropsL2';
......@@ -96,6 +96,7 @@ const baseStyle = definePartsStyle({
borderTopRightRadius: 'base',
overflow: 'unset',
fontVariant: 'normal',
fontVariantLigatures: 'no-contextual',
},
});
......
......@@ -8,6 +8,7 @@ const global = (props: StyleFunctionProps) => ({
bg: mode('white', 'black')(props),
...getDefaultTransitionProps(),
'-webkit-tap-highlight-color': 'transparent',
'font-variant-ligatures': 'no-contextual',
},
mark: {
bgColor: 'yellow.200',
......
......@@ -24,3 +24,10 @@ export interface VerifiedContractsFilters {
q: string | undefined;
filter: 'vyper' | 'solidity' | undefined;
}
export type VerifiedContractsCounters = {
new_smart_contracts_24h: string;
new_verified_smart_contracts_24h: string;
smart_contracts: string;
verified_smart_contracts: string;
}
export type DepositsItem = {
l1_block_number: number;
l1_tx_hash: string;
l1_block_timestamp: string;
l1_tx_origin: string;
l2_tx_gas_limit: string;
l2_tx_hash: string;
}
export type DepositsResponse = {
items: Array<DepositsItem>;
next_page_params: {
items_count: number;
l1_block_number: number;
tx_hash: string;
};
total: number;
}
export type OutputRootsItem = {
l1_block_number: number;
l1_timestamp: string;
l1_tx_hash: string;
l2_block_number: number;
l2_output_index: number;
output_root: string;
}
export type OutputRootsResponse = {
items: Array<OutputRootsItem>;
total: number;
next_page_params: {
index: number;
items_count: number;
};
}
export type TxnBatchesItem = {
epoch_number: number;
l1_tx_hashes: Array<string>;
l1_timestamp: string;
l2_block_number: number;
tx_count: number;
}
export type TxnBatchesResponse = {
items: Array<TxnBatchesItem>;
total: number;
next_page_params: {
index: number;
items_count: number;
};
}
import type { AddressParam } from './addressParams';
export type WithdrawalsItem = {
'challenge_period_end': string | null;
'from': AddressParam | null;
'l1_tx_hash': string | null;
'l2_timestamp': string | null;
'l2_tx_hash': string;
'msg_nonce': number;
'msg_nonce_version': number;
'status': string;
}
export type WithdrawalStatus =
'In challenge period' |
'Ready for relay' |
'Relayed' |
'Waiting for state root' |
'Ready to prove';
export type WithdrawalsResponse = {
items: Array<WithdrawalsItem>;
'next_page_params': {
'items_count': number;
'nonce': string;
};
total: number;
}
......@@ -25,19 +25,23 @@ declare module "nextjs-routes" {
| DynamicRoute<"/block/[height]", { "height": string }>
| StaticRoute<"/blocks">
| StaticRoute<"/csv-export">
| StaticRoute<"/deposits">
| StaticRoute<"/graph">
| StaticRoute<"/graphiql">
| StaticRoute<"/">
| StaticRoute<"/login">
| StaticRoute<"/output-roots">
| StaticRoute<"/search-results">
| StaticRoute<"/stats">
| DynamicRoute<"/token/[hash]", { "hash": string }>
| DynamicRoute<"/token/[hash]/instance/[id]", { "hash": string; "id": string }>
| StaticRoute<"/tokens">
| DynamicRoute<"/tx/[hash]", { "hash": string }>
| StaticRoute<"/txn-batches">
| StaticRoute<"/txs">
| StaticRoute<"/verified-contracts">
| StaticRoute<"/visualize/sol2uml">;
| StaticRoute<"/visualize/sol2uml">
| StaticRoute<"/withdrawals">;
interface StaticRoute<Pathname> {
pathname: Pathname;
......
import { Box, Hide, Show, Table, Tbody, Th, Tr } from '@chakra-ui/react';
import { Hide, Show, Table, Tbody, Th, Tr } from '@chakra-ui/react';
import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import React from 'react';
......@@ -12,10 +12,8 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import SocketAlert from 'ui/shared/SocketAlert';
import { default as Thead } from 'ui/shared/TheadSticky';
......@@ -71,30 +69,9 @@ const AddressBlocksValidated = ({ scrollRef }: Props) => {
handler: handleNewSocketMessage,
});
const content = (() => {
if (query.isLoading) {
return (
<>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '17%', '17%', '16%', '25%', '25%' ] } isLong/>
</Hide>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
</>
);
}
if (query.isError) {
return <DataFetchAlert/>;
}
if (query.data.items.length === 0) {
return 'There is no validated blocks for this address';
}
return (
const content = query.data?.items ? (
<>
{ socketAlert && <SocketAlert mb={ 6 }/> }
<Hide below="lg" ssr={ false }>
<Table variant="simple" size="sm">
<Thead top={ query.isPaginationVisible ? 80 : 0 }>
......@@ -119,19 +96,24 @@ const AddressBlocksValidated = ({ scrollRef }: Props) => {
)) }
</Show>
</>
);
})();
) : null;
return (
<Box>
{ query.isPaginationVisible && (
const actionBar = query.isPaginationVisible ? (
<ActionBar mt={ -6 } showShadow={ query.isLoading }>
<Pagination ml="auto" { ...query.pagination }/>
</ActionBar>
) }
{ socketAlert && <SocketAlert mb={ 6 }/> }
{ content }
</Box>
) : null;
return (
<DataListDisplay
isError={ query.isError }
isLoading={ query.isLoading }
items={ query.data?.items }
skeletonProps={{ isLongSkeleton: true, skeletonDesktopColumns: [ '17%', '17%', '16%', '25%', '25%' ] }}
emptyText="There are no validated blocks for this address."
content={ content }
actionBar={ actionBar }
/>
);
};
......
import { Text, Show, Hide } from '@chakra-ui/react';
import { Show, Hide } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
......@@ -10,12 +10,9 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { apos } from 'lib/html-entities';
import getQueryParamString from 'lib/router/getQueryParamString';
import AddressIntTxsTable from 'ui/address/internals/AddressIntTxsTable';
import EmptySearchResult from 'ui/apps/EmptySearchResult';
import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import AddressCsvExportLink from './AddressCsvExportLink';
import AddressTxsFilter from './AddressTxsFilter';
......@@ -43,33 +40,7 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
onFilterChange({ filter: newVal });
}, [ onFilterChange ]);
const content = (() => {
if (isError) {
return <DataFetchAlert/>;
}
if (isLoading) {
return (
<>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '15%', '15%', '10%', '20%', '20%', '20%' ] } isLong/>
</Hide>
</>
);
}
if (data.items.length === 0 && !filterValue) {
return <Text as="span">There are no internal transactions for this address.</Text>;
}
if (data.items.length === 0) {
return <EmptySearchResult text={ `Couldn${ apos }t find any transaction that matches your query.` }/>;
}
return (
const content = data?.items ? (
<>
<Show below="lg" ssr={ false }>
<AddressIntTxsList data={ data.items } currentAddress={ hash }/>
......@@ -78,11 +49,9 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
<AddressIntTxsTable data={ data.items } currentAddress={ hash }/>
</Hide>
</>
);
})();
) : null ;
return (
<>
const actionBar = (
<ActionBar mt={ -6 } justifyContent="left" showShadow={ isLoading }>
<AddressTxsFilter
defaultFilter={ filterValue }
......@@ -92,8 +61,19 @@ const AddressInternalTxs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivE
<AddressCsvExportLink address={ hash } type="internal-transactions" ml={{ base: 2, lg: 'auto' }}/>
{ isPaginationVisible && <Pagination ml={{ base: 'auto', lg: 8 }} { ...pagination }/> }
</ActionBar>
{ content }
</>
);
return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
skeletonProps={{ isLongSkeleton: true, skeletonDesktopColumns: [ '15%', '15%', '10%', '20%', '20%', '20%' ] }}
filterProps={{ emptyFilteredText: `Couldn${ apos }t find any transaction that matches your query.`, hasActiveFilters: Boolean(filterValue) }}
emptyText="There are no internal transactions for this address."
content={ content }
actionBar={ actionBar }
/>
);
};
......
import { Box } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import getQueryParamString from 'lib/router/getQueryParamString';
import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import LogItem from 'ui/shared/logs/LogItem';
import LogSkeleton from 'ui/shared/logs/LogSkeleton';
import Pagination from 'ui/shared/Pagination';
......@@ -20,35 +19,26 @@ const AddressLogs = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLDivElement>
scrollRef,
});
if (isError) {
return <DataFetchAlert/>;
}
const bar = isPaginationVisible ? (
const actionBar = isPaginationVisible ? (
<ActionBar mt={ -6 } showShadow>
<Pagination ml="auto" { ...pagination }/>
</ActionBar>
) : null;
if (isLoading) {
return (
<Box>
{ bar }
<LogSkeleton/>
<LogSkeleton/>
</Box>
);
}
const content = data?.items ? data.items.map((item, index) => <LogItem key={ index } { ...item } type="address"/>) : null;
if (data.items.length === 0) {
return <span>There are no logs for this address.</span>;
}
const skeleton = <><LogSkeleton/><LogSkeleton/></>;
return (
<>
{ bar }
{ data.items.map((item, index) => <LogItem key={ index } { ...item } type="address"/>) }
</>
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
emptyText="There are no logs for this address."
content={ content }
actionBar={ actionBar }
skeletonProps={{ customSkeleton: skeleton }}
/>
);
};
......
......@@ -13,7 +13,7 @@ const API_URL = buildApiUrl('address_token_transfers', { hash: '0xd789a607CEac2f
const hooksConfig = {
router: {
query: { hash: '0xd789a607CEac2f0E14867de4EB15b15C9FFB5859', token_hash: '0x1189a607CEac2f0E14867de4EB15b15C9FFB5859' },
query: { hash: '0xd789a607CEac2f0E14867de4EB15b15C9FFB5859', token: '0x1189a607CEac2f0E14867de4EB15b15C9FFB5859' },
},
};
......
......@@ -20,13 +20,10 @@ import getQueryParamString from 'lib/router/getQueryParamString';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import TOKEN_TYPE from 'lib/token/tokenTypes';
import EmptySearchResult from 'ui/apps/EmptySearchResult';
import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import HashStringShorten from 'ui/shared/HashStringShorten';
import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import SocketNewItemsNotice from 'ui/shared/SocketNewItemsNotice';
import TokenLogo from 'ui/shared/TokenLogo';
import { flattenTotal } from 'ui/shared/TokenTransfer/helpers';
......@@ -76,7 +73,7 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
const [ socketAlert, setSocketAlert ] = React.useState('');
const [ newItemsCount, setNewItemsCount ] = React.useState(0);
const tokenFilter = getQueryParamString(router.query.token_hash) || undefined;
const tokenFilter = getQueryParamString(router.query.token) || undefined;
const [ filters, setFilters ] = React.useState<Filters>(
{
......@@ -164,34 +161,8 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
const numActiveFilters = (filters.type?.length || 0) + (filters.filter ? 1 : 0);
const isActionBarHidden = !tokenFilter && !numActiveFilters && !data?.items.length && !currentAddress;
const content = (() => {
if (isLoading) {
return (
<>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '44px', '185px', '160px', '25%', '25%', '25%', '25%' ] } isLong/>
</Hide>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
</>
);
}
if (isError) {
return <DataFetchAlert/>;
}
if (!data.items?.length && !numActiveFilters) {
return <Text as="span">There are no token transfers</Text>;
}
if (!data.items?.length) {
return <EmptySearchResult text={ `Couldn${ apos }t find any token transfer that matches your query.` }/>;
}
const items = data.items.reduce(flattenTotal, []);
return (
const items = data?.items?.reduce(flattenTotal, []);
const content = items ? (
<>
<Hide below="lg" ssr={ false }>
<TokenTransferTable
......@@ -223,8 +194,7 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
/>
</Show>
</>
);
})();
) : null;
const tokenFilterComponent = tokenFilter && (
<Flex alignItems="center" flexWrap="wrap" mb={{ base: isActionBarHidden ? 3 : 6, lg: 0 }} mr={ 4 }>
......@@ -249,7 +219,7 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
</Flex>
);
return (
const actionBar = (
<>
{ isMobile && tokenFilterComponent }
{ !isActionBarHidden && (
......@@ -269,9 +239,27 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
{ isPaginationVisible && <Pagination ml={{ base: 'auto', lg: 8 }} { ...pagination }/> }
</ActionBar>
) }
{ content }
</>
);
return (
<DataListDisplay
isError={ isError }
isLoading={ isLoading }
items={ data?.items }
skeletonProps={{
isLongSkeleton: true,
skeletonDesktopColumns: [ '44px', '185px', '160px', '25%', '25%', '25%', '25%' ],
}}
emptyText="There are no token transfers."
filterProps={{
emptyFilteredText: `Couldn${ apos }t find any token transfer that matches your query.`,
hasActiveFilters: Boolean(numActiveFilters),
}}
content={ content }
actionBar={ actionBar }
/>
);
};
export default AddressTokenTransfers;
......@@ -9,7 +9,7 @@ import appConfig from 'configs/app/config';
import getBlockTotalReward from 'lib/block/getBlockTotalReward';
import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobile from 'ui/shared/ListItemMobile';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import Utilization from 'ui/shared/Utilization/Utilization';
type Props = Block & {
......
import { Box, Hide, Show, Table, Tbody, Th, Tr } from '@chakra-ui/react';
import { Hide, Show, Table, Tbody, Th, Tr } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import React from 'react';
......@@ -6,11 +6,9 @@ import type { AddressCoinBalanceHistoryResponse } from 'types/api/address';
import appConfig from 'configs/app/config';
import ActionBar from 'ui/shared/ActionBar';
import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DataListDisplay from 'ui/shared/DataListDisplay';
import type { Props as PaginationProps } from 'ui/shared/Pagination';
import Pagination from 'ui/shared/Pagination';
import SkeletonList from 'ui/shared/skeletons/SkeletonList';
import SkeletonTable from 'ui/shared/skeletons/SkeletonTable';
import { default as Thead } from 'ui/shared/TheadSticky';
import AddressCoinBalanceListItem from './AddressCoinBalanceListItem';
......@@ -25,29 +23,7 @@ interface Props {
const AddressCoinBalanceHistory = ({ query }: Props) => {
const content = (() => {
if (query.isLoading) {
return (
<>
<Hide below="lg" ssr={ false }>
<SkeletonTable columns={ [ '25%', '25%', '25%', '25%', '120px' ] }/>
</Hide>
<Show below="lg" ssr={ false }>
<SkeletonList/>
</Show>
</>
);
}
if (query.isError) {
return <DataFetchAlert/>;
}
if (query.data.items.length === 0 && !query.isPaginationVisible) {
return <span>There is no coin balance history for this address</span>;
}
return (
const content = query.data?.items ? (
<>
<Hide below="lg" ssr={ false }>
<Table variant="simple" size="sm">
......@@ -73,18 +49,25 @@ const AddressCoinBalanceHistory = ({ query }: Props) => {
)) }
</Show>
</>
);
})();
) : null;
return (
<Box mt={ 8 }>
{ query.isPaginationVisible && (
const actionBar = query.isPaginationVisible ? (
<ActionBar mt={ -6 }>
<Pagination ml="auto" { ...query.pagination }/>
</ActionBar>
) }
{ content }
</Box>
) : null;
return (
<DataListDisplay
mt={ 8 }
isError={ query.isError }
isLoading={ query.isLoading }
items={ query.data?.items }
skeletonProps={{ skeletonDesktopColumns: [ '25%', '25%', '25%', '25%', '120px' ] }}
emptyText="There is no coin balance history for this address."
content={ content }
actionBar={ actionBar }
/>
);
};
......
......@@ -11,7 +11,7 @@ import useTimeAgoIncrement from 'lib/hooks/useTimeAgoIncrement';
import Address from 'ui/shared/address/Address';
import AddressLink from 'ui/shared/address/AddressLink';
import LinkInternal from 'ui/shared/LinkInternal';
import ListItemMobile from 'ui/shared/ListItemMobile';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
type Props = AddressCoinBalanceHistoryItem & {
page: number;
......
......@@ -20,6 +20,7 @@ test('verified with changed byte code +@mobile +@dark-mode', async({ mount, page
status: 200,
body: JSON.stringify(contractMock.withChangedByteCode),
}));
await page.route('https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/**', (route) => route.abort());
const component = await mount(
<TestApp>
......@@ -36,6 +37,7 @@ test('verified with multiple sources +@mobile', async({ mount, page }) => {
status: 200,
body: JSON.stringify(contractMock.withMultiplePaths),
}));
await page.route('https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/**', (route) => route.abort());
await mount(
<TestApp>
......@@ -54,6 +56,7 @@ test('verified via sourcify', async({ mount, page }) => {
status: 200,
body: JSON.stringify(contractMock.verifiedViaSourcify),
}));
await page.route('https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/**', (route) => route.abort());
await mount(
<TestApp>
......@@ -70,6 +73,7 @@ test('self destructed', async({ mount, page }) => {
status: 200,
body: JSON.stringify(contractMock.selfDestructed),
}));
await page.route('https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/**', (route) => route.abort());
await mount(
<TestApp>
......@@ -87,6 +91,7 @@ test('with twin address alert +@mobile', async({ mount, page }) => {
status: 200,
body: JSON.stringify(contractMock.withTwinAddress),
}));
await page.route('https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/**', (route) => route.abort());
const component = await mount(
<TestApp>
......@@ -103,6 +108,7 @@ test('with proxy address alert +@mobile', async({ mount, page }) => {
status: 200,
body: JSON.stringify(contractMock.withProxyAddress),
}));
await page.route('https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/**', (route) => route.abort());
const component = await mount(
<TestApp>
......@@ -119,6 +125,7 @@ test('non verified', async({ mount, page }) => {
status: 200,
body: JSON.stringify(contractMock.nonVerified),
}));
await page.route('https://cdn.jsdelivr.net/npm/monaco-editor@0.33.0/**', (route) => route.abort());
const component = await mount(
<TestApp>
......
import { Box, chakra, Flex, Text, Tooltip } from '@chakra-ui/react';
import { Flex, Text, Tooltip } from '@chakra-ui/react';
import { route } from 'nextjs-routes';
import React from 'react';
import type { SmartContract } from 'types/api/contract';
import CodeEditor from 'ui/shared/CodeEditor';
import CopyToClipboard from 'ui/shared/CopyToClipboard';
import LinkInternal from 'ui/shared/LinkInternal';
import CodeEditor from 'ui/shared/monaco/CodeEditor';
import formatFilePath from 'ui/shared/monaco/utils/formatFilePath';
interface Props {
data: string;
......@@ -37,38 +38,25 @@ const ContractSourceCode = ({ data, hasSol2Yml, address, isViper, filePath, addi
</Tooltip>
) : null;
if (!additionalSource?.length) {
return (
<section>
<Flex justifyContent="space-between" alignItems="center" mb={ 3 }>
{ heading }
{ diagramLink }
<CopyToClipboard text={ data }/>
</Flex>
<CodeEditor value={ data } id="source_code"/>
</section>
);
}
const editorData = React.useMemo(() => {
const defaultName = isViper ? '/index.vy' : '/index.sol';
return [
{ file_path: formatFilePath(filePath || defaultName), source_code: data },
...(additionalSource || []).map((source) => ({ ...source, file_path: formatFilePath(source.file_path) })) ];
}, [ additionalSource, data, filePath, isViper ]);
const copyToClipboard = editorData.length === 1 ?
<CopyToClipboard text={ editorData[0].source_code }/> :
null;
return (
<section>
<Flex justifyContent="space-between" alignItems="center" mb={ 3 }>
{ heading }
{ diagramLink }
{ copyToClipboard }
</Flex>
<Flex flexDir="column" rowGap={ 3 }>
{ [ { file_path: filePath, source_code: data }, ...additionalSource ].map((item, index, array) => (
<Box key={ index }>
<Flex justifyContent="space-between" alignItems="flex-end" mb={ 3 }>
<chakra.span fontSize="sm" wordBreak="break-all" lineHeight="20px">
File { index + 1 } of { array.length }: { item.file_path }
</chakra.span>
<CopyToClipboard text={ item.source_code } ml={ 4 }/>
</Flex>
<CodeEditor value={ item.source_code } id={ `source_code_${ index }` }/>
</Box>
)) }
</Flex>
<CodeEditor data={ editorData }/>
</section>
);
};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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