mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
API resource refactoring (#2699)
* add prefix to API resources * fix pw tests * refactor config * remove unnecessary prefixes in resource names * fixes * update screenshots
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
import { stripTrailingSlash } from 'toolkit/utils/url';
|
||||
|
||||
import { getEnvValue } from './utils';
|
||||
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_API_HOST');
|
||||
const apiSchema = getEnvValue('NEXT_PUBLIC_API_PROTOCOL') || 'https';
|
||||
const apiPort = getEnvValue('NEXT_PUBLIC_API_PORT');
|
||||
const apiEndpoint = [
|
||||
apiSchema || 'https',
|
||||
'://',
|
||||
apiHost,
|
||||
apiPort && ':' + apiPort,
|
||||
].filter(Boolean).join('');
|
||||
|
||||
const socketSchema = getEnvValue('NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL') || 'wss';
|
||||
const socketEndpoint = [
|
||||
socketSchema,
|
||||
'://',
|
||||
apiHost,
|
||||
apiPort && ':' + apiPort,
|
||||
].filter(Boolean).join('');
|
||||
|
||||
const api = Object.freeze({
|
||||
host: apiHost,
|
||||
protocol: apiSchema,
|
||||
port: apiPort,
|
||||
endpoint: apiEndpoint,
|
||||
socket: socketEndpoint,
|
||||
basePath: stripTrailingSlash(getEnvValue('NEXT_PUBLIC_API_BASE_PATH') || ''),
|
||||
});
|
||||
|
||||
export default api;
|
||||
@@ -0,0 +1,142 @@
|
||||
import type { ApiName } from 'lib/api/types';
|
||||
|
||||
import { stripTrailingSlash } from 'toolkit/utils/url';
|
||||
|
||||
import { getEnvValue } from './utils';
|
||||
|
||||
interface ApiPropsBase {
|
||||
endpoint: string;
|
||||
basePath?: string;
|
||||
}
|
||||
|
||||
interface ApiPropsFull extends ApiPropsBase {
|
||||
host: string;
|
||||
protocol: string;
|
||||
port?: string;
|
||||
socketEndpoint: string;
|
||||
}
|
||||
|
||||
const generalApi = (() => {
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_API_HOST');
|
||||
const apiSchema = getEnvValue('NEXT_PUBLIC_API_PROTOCOL') || 'https';
|
||||
const apiPort = getEnvValue('NEXT_PUBLIC_API_PORT');
|
||||
const apiEndpoint = [
|
||||
apiSchema || 'https',
|
||||
'://',
|
||||
apiHost,
|
||||
apiPort && ':' + apiPort,
|
||||
].filter(Boolean).join('');
|
||||
|
||||
const socketSchema = getEnvValue('NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL') || 'wss';
|
||||
const socketEndpoint = [
|
||||
socketSchema,
|
||||
'://',
|
||||
apiHost,
|
||||
apiPort && ':' + apiPort,
|
||||
].filter(Boolean).join('');
|
||||
|
||||
return Object.freeze({
|
||||
endpoint: apiEndpoint,
|
||||
basePath: stripTrailingSlash(getEnvValue('NEXT_PUBLIC_API_BASE_PATH') || ''),
|
||||
socketEndpoint: socketEndpoint,
|
||||
host: apiHost ?? '',
|
||||
protocol: apiSchema ?? 'https',
|
||||
port: apiPort,
|
||||
});
|
||||
})();
|
||||
|
||||
const adminApi = (() => {
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_ADMIN_SERVICE_API_HOST');
|
||||
if (!apiHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
endpoint: apiHost,
|
||||
});
|
||||
})();
|
||||
|
||||
const bensApi = (() => {
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_NAME_SERVICE_API_HOST');
|
||||
if (!apiHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
endpoint: apiHost,
|
||||
});
|
||||
})();
|
||||
|
||||
const contractInfoApi = (() => {
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_CONTRACT_INFO_API_HOST');
|
||||
if (!apiHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
endpoint: apiHost,
|
||||
});
|
||||
})();
|
||||
|
||||
const metadataApi = (() => {
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_METADATA_SERVICE_API_HOST');
|
||||
if (!apiHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
endpoint: apiHost,
|
||||
});
|
||||
})();
|
||||
|
||||
const rewardsApi = (() => {
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_REWARDS_SERVICE_API_HOST');
|
||||
if (!apiHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
endpoint: apiHost,
|
||||
});
|
||||
})();
|
||||
|
||||
const statsApi = (() => {
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_STATS_API_HOST');
|
||||
if (!apiHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
endpoint: apiHost,
|
||||
basePath: stripTrailingSlash(getEnvValue('NEXT_PUBLIC_STATS_API_BASE_PATH') || ''),
|
||||
});
|
||||
})();
|
||||
|
||||
const visualizeApi = (() => {
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_VISUALIZE_API_HOST');
|
||||
if (!apiHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
endpoint: apiHost,
|
||||
basePath: stripTrailingSlash(getEnvValue('NEXT_PUBLIC_VISUALIZE_API_BASE_PATH') || ''),
|
||||
});
|
||||
})();
|
||||
|
||||
type Apis = {
|
||||
general: ApiPropsFull;
|
||||
} & Partial<Record<Exclude<ApiName, 'general'>, ApiPropsBase>>;
|
||||
|
||||
const apis: Apis = Object.freeze({
|
||||
general: generalApi,
|
||||
admin: adminApi,
|
||||
bens: bensApi,
|
||||
contractInfo: contractInfoApi,
|
||||
metadata: metadataApi,
|
||||
rewards: rewardsApi,
|
||||
stats: statsApi,
|
||||
visualize: visualizeApi,
|
||||
});
|
||||
|
||||
export default apis;
|
||||
@@ -1,20 +1,14 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_METADATA_SERVICE_API_HOST');
|
||||
import apis from '../apis';
|
||||
|
||||
const title = 'Address metadata';
|
||||
|
||||
const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
|
||||
if (apiHost) {
|
||||
const config: Feature<{}> = (() => {
|
||||
if (apis.metadata) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: apiHost,
|
||||
basePath: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
import apis from '../apis';
|
||||
import account from './account';
|
||||
import verifiedTokens from './verifiedTokens';
|
||||
|
||||
const adminServiceApiHost = getEnvValue('NEXT_PUBLIC_ADMIN_SERVICE_API_HOST');
|
||||
|
||||
const title = 'Address verification in "My account"';
|
||||
|
||||
const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
|
||||
if (account.isEnabled && verifiedTokens.isEnabled && adminServiceApiHost) {
|
||||
const config: Feature<{}> = (() => {
|
||||
if (account.isEnabled && verifiedTokens.isEnabled && apis.admin) {
|
||||
return Object.freeze({
|
||||
title: 'Address verification in "My account"',
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: adminServiceApiHost,
|
||||
basePath: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import apis from '../apis';
|
||||
import chain from '../chain';
|
||||
import { getEnvValue, getExternalAssetFilePath } from '../utils';
|
||||
|
||||
@@ -9,7 +10,6 @@ const configUrl = getExternalAssetFilePath('NEXT_PUBLIC_MARKETPLACE_CONFIG_URL')
|
||||
const submitFormUrl = getEnvValue('NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM');
|
||||
const suggestIdeasFormUrl = getEnvValue('NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM');
|
||||
const categoriesUrl = getExternalAssetFilePath('NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL');
|
||||
const adminServiceApiHost = getEnvValue('NEXT_PUBLIC_ADMIN_SERVICE_API_HOST');
|
||||
const securityReportsUrl = getExternalAssetFilePath('NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL');
|
||||
const featuredApp = getEnvValue('NEXT_PUBLIC_MARKETPLACE_FEATURED_APP');
|
||||
const bannerContentUrl = getExternalAssetFilePath('NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL');
|
||||
@@ -22,7 +22,7 @@ const title = 'Marketplace';
|
||||
|
||||
const config: Feature<(
|
||||
{ configUrl: string } |
|
||||
{ api: { endpoint: string; basePath: string } }
|
||||
{ api: { endpoint: string; basePath?: string } }
|
||||
) & {
|
||||
submitFormUrl: string;
|
||||
categoriesUrl: string | undefined;
|
||||
@@ -58,14 +58,11 @@ const config: Feature<(
|
||||
configUrl,
|
||||
...props,
|
||||
});
|
||||
} else if (adminServiceApiHost) {
|
||||
} else if (apis.admin) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: adminServiceApiHost,
|
||||
basePath: '',
|
||||
},
|
||||
api: apis.admin,
|
||||
...props,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_NAME_SERVICE_API_HOST');
|
||||
import apis from '../apis';
|
||||
|
||||
const title = 'Name service integration';
|
||||
|
||||
const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
|
||||
if (apiHost) {
|
||||
const config: Feature<{}> = (() => {
|
||||
if (apis.bens) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: apiHost,
|
||||
basePath: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import apis from '../apis';
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const contractInfoApiHost = getEnvValue('NEXT_PUBLIC_CONTRACT_INFO_API_HOST');
|
||||
const dexPoolsEnabled = getEnvValue('NEXT_PUBLIC_DEX_POOLS_ENABLED') === 'true';
|
||||
|
||||
const title = 'DEX Pools';
|
||||
|
||||
const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
|
||||
if (contractInfoApiHost && dexPoolsEnabled) {
|
||||
const config: Feature<{ }> = (() => {
|
||||
if (apis.contractInfo && dexPoolsEnabled) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: contractInfoApiHost,
|
||||
basePath: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import apis from '../apis';
|
||||
import services from '../services';
|
||||
import { getEnvValue } from '../utils';
|
||||
import addressMetadata from './addressMetadata';
|
||||
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_ADMIN_SERVICE_API_HOST');
|
||||
|
||||
const title = 'Public tag submission';
|
||||
|
||||
const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
|
||||
if (services.reCaptchaV2.siteKey && addressMetadata.isEnabled && apiHost) {
|
||||
const config: Feature<{}> = (() => {
|
||||
if (services.reCaptchaV2.siteKey && addressMetadata.isEnabled && apis.admin) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: apiHost,
|
||||
basePath: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
import apis from '../apis';
|
||||
import account from './account';
|
||||
import blockchainInteraction from './blockchainInteraction';
|
||||
|
||||
const apiHost = getEnvValue('NEXT_PUBLIC_REWARDS_SERVICE_API_HOST');
|
||||
|
||||
const title = 'Rewards service integration';
|
||||
|
||||
const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
|
||||
if (apiHost && account.isEnabled && blockchainInteraction.isEnabled) {
|
||||
const config: Feature<{}> = (() => {
|
||||
if (apis.rewards && account.isEnabled && blockchainInteraction.isEnabled) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: apiHost,
|
||||
basePath: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import { stripTrailingSlash } from 'toolkit/utils/url';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const apiEndpoint = getEnvValue('NEXT_PUBLIC_VISUALIZE_API_HOST');
|
||||
import apis from '../apis';
|
||||
|
||||
const title = 'Solidity to UML diagrams';
|
||||
|
||||
const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
|
||||
if (apiEndpoint) {
|
||||
const config: Feature<{}> = (() => {
|
||||
if (apis.visualize) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: apiEndpoint,
|
||||
basePath: stripTrailingSlash(getEnvValue('NEXT_PUBLIC_VISUALIZE_API_BASE_PATH') || ''),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import { stripTrailingSlash } from 'toolkit/utils/url';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const apiEndpoint = getEnvValue('NEXT_PUBLIC_STATS_API_HOST');
|
||||
import apis from '../apis';
|
||||
|
||||
const title = 'Blockchain statistics';
|
||||
|
||||
const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
|
||||
if (apiEndpoint) {
|
||||
const config: Feature<{}> = (() => {
|
||||
if (apis.stats) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: apiEndpoint,
|
||||
basePath: stripTrailingSlash(getEnvValue('NEXT_PUBLIC_STATS_API_BASE_PATH') || ''),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import type { Feature } from './types';
|
||||
|
||||
import { getEnvValue } from '../utils';
|
||||
|
||||
const contractInfoApiHost = getEnvValue('NEXT_PUBLIC_CONTRACT_INFO_API_HOST');
|
||||
import apis from '../apis';
|
||||
|
||||
const title = 'Verified tokens info';
|
||||
|
||||
const config: Feature<{ api: { endpoint: string; basePath: string } }> = (() => {
|
||||
if (contractInfoApiHost) {
|
||||
const config: Feature<{}> = (() => {
|
||||
if (apis.contractInfo) {
|
||||
return Object.freeze({
|
||||
title,
|
||||
isEnabled: true,
|
||||
api: {
|
||||
endpoint: contractInfoApiHost,
|
||||
basePath: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import api from './api';
|
||||
import apis from './apis';
|
||||
import app from './app';
|
||||
import chain from './chain';
|
||||
import * as features from './features';
|
||||
@@ -9,7 +9,7 @@ import UI from './ui';
|
||||
const config = Object.freeze({
|
||||
app,
|
||||
chain,
|
||||
api,
|
||||
apis,
|
||||
UI,
|
||||
features,
|
||||
services,
|
||||
|
||||
+18
-14
@@ -7,15 +7,9 @@ NEXT_PUBLIC_APP_PROTOCOL=http
|
||||
NEXT_PUBLIC_APP_HOST=localhost
|
||||
NEXT_PUBLIC_APP_PORT=3000
|
||||
NEXT_PUBLIC_APP_ENV=development
|
||||
NEXT_PUBLIC_APP_INSTANCE=rubber_duck
|
||||
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
|
||||
|
||||
NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED=true
|
||||
|
||||
# Instance ENVs
|
||||
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "632019", "width": "728", "height": "90" }
|
||||
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "632018", "width": "320", "height": "100" }
|
||||
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER=adbutler
|
||||
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_API_BASE_PATH=/
|
||||
NEXT_PUBLIC_API_HOST=eth-sepolia.k8s-dev.blockscout.com
|
||||
@@ -23,28 +17,33 @@ NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout
|
||||
NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}]
|
||||
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED=true
|
||||
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'uniswap'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
|
||||
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swapscout','icon':'swap','dappId':'swapscout'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'},{'text':'Get gas','icon':'gas','dappId':'smol-refuel'}]
|
||||
NEXT_PUBLIC_DEX_POOLS_ENABLED=true
|
||||
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-sepolia.json
|
||||
NEXT_PUBLIC_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/sepolia.json
|
||||
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xbf69c7abc4fee283b59a9633dadfdaedde5c5ee0fba3e80a08b5b8a3acbd4363
|
||||
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/sherblockHolmesBadge
|
||||
NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}', 'dapp_id': 'smol-refuel', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'}
|
||||
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x93e00d4d48cf0dc229f5102e18277fa1bb6130d5b319697a87698a35cf67f706
|
||||
NEXT_PUBLIC_HAS_BEACON_CHAIN=true
|
||||
NEXT_PUBLIC_HAS_USER_OPS=true
|
||||
NEXT_PUBLIC_HELIA_VERIFIED_FETCH_ENABLED=false
|
||||
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
|
||||
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=rgba(51, 53, 67, 1)
|
||||
NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=rgba(165, 252, 122, 1)
|
||||
NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['rgba(51, 53, 67, 1)'],'text_color':['rgba(165, 252, 122, 1)']}
|
||||
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
|
||||
NEXT_PUBLIC_IS_TESTNET=true
|
||||
NEXT_PUBLIC_LOGOUT_URL=https://blockscout-goerli.us.auth0.com/v2/logout
|
||||
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
|
||||
NEXT_PUBLIC_MARKETPLACE_ENABLED=true
|
||||
NEXT_PUBLIC_MARKETPLACE_GRAPH_LINKS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/refs/heads/marketplace-graph-test/test-configs/marketplace-graph-links.json
|
||||
NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs
|
||||
NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/test-configs/marketplace-security-report-mock.json
|
||||
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL
|
||||
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM=https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
|
||||
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_METASUITES_ENABLED=true
|
||||
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'}]
|
||||
NEXT_PUBLIC_MULTICHAIN_BALANCE_PROVIDER_CONFIG=[{'name': 'zerion', 'url_template': 'https://app.zerion.io/{address}/overview?utm_source=blockscout&utm_medium=address', 'logo': 'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-logos/zerion.svg'},{'name': 'zapper', 'url_template': 'https://zapper.xyz/account/{address}?utm_source=blockscout&utm_medium=address', 'logo': 'https://blockscout-content.s3.amazonaws.com/zapper-icon.png'}]
|
||||
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens-rs-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/blocks','/apps']
|
||||
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/pools']
|
||||
NEXT_PUBLIC_NAVIGATION_LAYOUT=horizontal
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
|
||||
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
|
||||
@@ -64,8 +63,13 @@ NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-c
|
||||
NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://sepolia.drpc.org?ref=559183','text':'Public RPC'}]
|
||||
NEXT_PUBLIC_REWARDS_SERVICE_API_HOST=https://points.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-sepolia.safe.global
|
||||
NEXT_PUBLIC_SAVE_ON_GAS_ENABLED=true
|
||||
NEXT_PUBLIC_SEO_ENHANCED_DATA_ENABLED=true
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://stats-sepolia.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service
|
||||
NEXT_PUBLIC_STATS_API_HOST=https://eth-sepolia.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
|
||||
NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE=nouns
|
||||
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
|
||||
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED=true
|
||||
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer-test.k8s-dev.blockscout.com
|
||||
NEXT_PUBLIC_XSTAR_SCORE_URL=https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address
|
||||
@@ -52,6 +52,7 @@ NEXT_PUBLIC_CONTRACT_INFO_API_HOST=http://localhost:3005
|
||||
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=http://localhost:3006
|
||||
NEXT_PUBLIC_METADATA_SERVICE_API_HOST=http://localhost:3007
|
||||
NEXT_PUBLIC_NAME_SERVICE_API_HOST=http://localhost:3008
|
||||
NEXT_PUBLIC_REWARDS_SERVICE_API_HOST=http://localhost:3009
|
||||
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx
|
||||
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID=xxx
|
||||
NEXT_PUBLIC_VIEWS_ADDRESS_FORMAT=['base16','bech32']
|
||||
|
||||
@@ -7,7 +7,7 @@ import parseMetaPayload from './parseMetaPayload';
|
||||
|
||||
export default function useAddressMetadataInfoQuery(addresses: Array<string>, isEnabled = true) {
|
||||
|
||||
const resource = 'address_metadata_info';
|
||||
const resource = 'metadata:info';
|
||||
|
||||
return useApiQuery<typeof resource, unknown, AddressMetadataInfoFormatted>(resource, {
|
||||
queryParams: {
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import buildUrl from './buildUrl';
|
||||
|
||||
test('builds URL for resource without path params', () => {
|
||||
const url = buildUrl('config_backend_version');
|
||||
const url = buildUrl('general:config_backend_version');
|
||||
expect(url).toBe('https://localhost:3003/api/v2/config/backend-version');
|
||||
});
|
||||
|
||||
test('builds URL for resource with path params', () => {
|
||||
const url = buildUrl('block', { height_or_hash: '42' });
|
||||
const url = buildUrl('general:block', { height_or_hash: '42' });
|
||||
expect(url).toBe('https://localhost:3003/api/v2/blocks/42');
|
||||
});
|
||||
|
||||
describe('falsy query parameters', () => {
|
||||
test('leaves "false" as query parameter', () => {
|
||||
const url = buildUrl('block', { height_or_hash: '42' }, { includeTx: false });
|
||||
const url = buildUrl('general:block', { height_or_hash: '42' }, { includeTx: false });
|
||||
expect(url).toBe('https://localhost:3003/api/v2/blocks/42?includeTx=false');
|
||||
});
|
||||
|
||||
test('leaves "null" as query parameter', () => {
|
||||
const url = buildUrl('block', { height_or_hash: '42' }, { includeTx: null });
|
||||
const url = buildUrl('general:block', { height_or_hash: '42' }, { includeTx: null });
|
||||
expect(url).toBe('https://localhost:3003/api/v2/blocks/42?includeTx=null');
|
||||
});
|
||||
|
||||
test('strips out empty string as query parameter', () => {
|
||||
const url = buildUrl('block', { height_or_hash: '42' }, { includeTx: null, sort: '' });
|
||||
const url = buildUrl('general:block', { height_or_hash: '42' }, { includeTx: null, sort: '' });
|
||||
expect(url).toBe('https://localhost:3003/api/v2/blocks/42?includeTx=null');
|
||||
});
|
||||
|
||||
test('strips out "undefined" as query parameter', () => {
|
||||
const url = buildUrl('block', { height_or_hash: '42' }, { includeTx: null, sort: undefined });
|
||||
const url = buildUrl('general:block', { height_or_hash: '42' }, { includeTx: null, sort: undefined });
|
||||
expect(url).toBe('https://localhost:3003/api/v2/blocks/42?includeTx=null');
|
||||
});
|
||||
});
|
||||
|
||||
test('builds URL with array-like query parameters', () => {
|
||||
const url = buildUrl('block', { height_or_hash: '42' }, { includeTx: [ '0x11', '0x22' ], sort: 'asc' });
|
||||
const url = buildUrl('general:block', { height_or_hash: '42' }, { includeTx: [ '0x11', '0x22' ], sort: 'asc' });
|
||||
expect(url).toBe('https://localhost:3003/api/v2/blocks/42?includeTx=0x11%2C0x22&sort=asc');
|
||||
});
|
||||
|
||||
test('builds URL for resource with custom API endpoint', () => {
|
||||
const url = buildUrl('token_verified_info', { chainId: '42', hash: '0x11' });
|
||||
const url = buildUrl('contractInfo:token_verified_info', { chainId: '42', hash: '0x11' });
|
||||
expect(url).toBe('https://localhost:3005/api/v1/chains/42/token-infos/0x11');
|
||||
});
|
||||
|
||||
+6
-6
@@ -2,19 +2,19 @@ import { compile } from 'path-to-regexp';
|
||||
|
||||
import config from 'configs/app';
|
||||
|
||||
import getResourceParams from './getResourceParams';
|
||||
import isNeedProxy from './isNeedProxy';
|
||||
import { RESOURCES } from './resources';
|
||||
import type { ApiResource, ResourceName, ResourcePathParams } from './resources';
|
||||
import type { ResourceName, ResourcePathParams } from './resources';
|
||||
|
||||
export default function buildUrl<R extends ResourceName>(
|
||||
resourceName: R,
|
||||
resourceFullName: R,
|
||||
pathParams?: ResourcePathParams<R>,
|
||||
queryParams?: Record<string, string | Array<string> | number | boolean | null | undefined>,
|
||||
noProxy?: boolean,
|
||||
): string {
|
||||
const resource: ApiResource = RESOURCES[resourceName];
|
||||
const baseUrl = !noProxy && isNeedProxy() ? config.app.baseUrl : (resource.endpoint || config.api.endpoint);
|
||||
const basePath = resource.basePath !== undefined ? resource.basePath : config.api.basePath;
|
||||
const { api, resource } = getResourceParams(resourceFullName);
|
||||
const baseUrl = !noProxy && isNeedProxy() ? config.app.baseUrl : api.endpoint;
|
||||
const basePath = api.basePath ?? '';
|
||||
const path = !noProxy && isNeedProxy() ? '/node-api/proxy' + basePath + resource.path : basePath + resource.path;
|
||||
const url = new URL(compile(path)(pathParams), baseUrl);
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { ApiName, ApiResource } from './types';
|
||||
|
||||
import config from 'configs/app';
|
||||
|
||||
import type { ResourceName } from './resources';
|
||||
import { RESOURCES } from './resources';
|
||||
|
||||
export default function getResourceParams(resourceFullName: ResourceName) {
|
||||
const [ apiName, resourceName ] = resourceFullName.split(':') as [ ApiName, string ];
|
||||
const apiConfig = config.apis[apiName];
|
||||
|
||||
if (!apiConfig) {
|
||||
throw new Error(`API config for ${ apiName } not found`);
|
||||
}
|
||||
|
||||
return {
|
||||
api: apiConfig,
|
||||
apiName,
|
||||
resource: RESOURCES[apiName][resourceName as keyof typeof RESOURCES[ApiName]] as ApiResource,
|
||||
};
|
||||
}
|
||||
@@ -9,5 +9,5 @@ export default function isNeedProxy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
return config.app.host === 'localhost' && config.app.host !== config.api.host;
|
||||
return config.app.host === 'localhost' && config.app.host !== config.apis.general.host;
|
||||
}
|
||||
|
||||
+96
-1586
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
import type { ApiResource } from '../types';
|
||||
import type { TokenInfoApplicationConfig, TokenInfoApplications } from 'types/api/account';
|
||||
import type { MarketplaceAppOverview } from 'types/client/marketplace';
|
||||
|
||||
export const ADMIN_API_RESOURCES = {
|
||||
public_tag_application: {
|
||||
path: '/api/v1/chains/:chainId/metadata-submissions/tag',
|
||||
pathParams: [ 'chainId' as const ],
|
||||
},
|
||||
token_info_applications_config: {
|
||||
path: '/api/v1/chains/:chainId/token-info-submissions/selectors',
|
||||
pathParams: [ 'chainId' as const ],
|
||||
},
|
||||
token_info_applications: {
|
||||
path: '/api/v1/chains/:chainId/token-info-submissions{/:id}',
|
||||
pathParams: [ 'chainId' as const, 'id' as const ],
|
||||
},
|
||||
marketplace_dapps: {
|
||||
path: '/api/v1/chains/:chainId/marketplace/dapps',
|
||||
pathParams: [ 'chainId' as const ],
|
||||
},
|
||||
marketplace_dapp: {
|
||||
path: '/api/v1/chains/:chainId/marketplace/dapps/:dappId',
|
||||
pathParams: [ 'chainId' as const, 'dappId' as const ],
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type AdminApiResourceName = `admin:${ keyof typeof ADMIN_API_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type AdminApiResourcePayload<R extends AdminApiResourceName> =
|
||||
R extends 'admin:token_info_applications_config' ? TokenInfoApplicationConfig :
|
||||
R extends 'admin:token_info_applications' ? TokenInfoApplications :
|
||||
R extends 'admin:marketplace_dapps' ? Array<MarketplaceAppOverview> :
|
||||
R extends 'admin:marketplace_dapp' ? MarketplaceAppOverview :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,61 @@
|
||||
import type { ApiResource } from '../types';
|
||||
import type * as bens from '@blockscout/bens-types';
|
||||
import type { EnsAddressLookupFilters, EnsDomainLookupFilters, EnsLookupSorting } from 'types/api/ens';
|
||||
|
||||
export const BENS_API_RESOURCES = {
|
||||
addresses_lookup: {
|
||||
path: '/api/v1/:chainId/addresses\\:lookup',
|
||||
pathParams: [ 'chainId' as const ],
|
||||
filterFields: [ 'address' as const, 'resolved_to' as const, 'owned_by' as const, 'only_active' as const, 'protocols' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
address_domain: {
|
||||
path: '/api/v1/:chainId/addresses/:address',
|
||||
pathParams: [ 'chainId' as const, 'address' as const ],
|
||||
},
|
||||
domain_info: {
|
||||
path: '/api/v1/:chainId/domains/:name',
|
||||
pathParams: [ 'chainId' as const, 'name' as const ],
|
||||
},
|
||||
domain_events: {
|
||||
path: '/api/v1/:chainId/domains/:name/events',
|
||||
pathParams: [ 'chainId' as const, 'name' as const ],
|
||||
},
|
||||
domains_lookup: {
|
||||
path: '/api/v1/:chainId/domains\\:lookup',
|
||||
pathParams: [ 'chainId' as const ],
|
||||
filterFields: [ 'name' as const, 'only_active' as const, 'protocols' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
domain_protocols: {
|
||||
path: '/api/v1/:chainId/protocols',
|
||||
pathParams: [ 'chainId' as const ],
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type BensApiResourceName = `bens:${ keyof typeof BENS_API_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type BensApiResourcePayload<R extends BensApiResourceName> =
|
||||
R extends 'bens:addresses_lookup' ? bens.LookupAddressResponse :
|
||||
R extends 'bens:address_domain' ? bens.GetAddressResponse :
|
||||
R extends 'bens:domain_info' ? bens.DetailedDomain :
|
||||
R extends 'bens:domain_events' ? bens.ListDomainEventsResponse :
|
||||
R extends 'bens:domains_lookup' ? bens.LookupDomainNameResponse :
|
||||
R extends 'bens:domain_protocols' ? bens.GetProtocolsResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type BensApiPaginationFilters<R extends BensApiResourceName> =
|
||||
R extends 'bens:addresses_lookup' ? EnsAddressLookupFilters :
|
||||
R extends 'bens:domains_lookup' ? EnsDomainLookupFilters :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type BensApiPaginationSorting<R extends BensApiResourceName> =
|
||||
R extends 'bens:addresses_lookup' ? EnsLookupSorting :
|
||||
R extends 'bens:domains_lookup' ? EnsLookupSorting :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,46 @@
|
||||
import type { ApiResource } from '../types';
|
||||
import type { VerifiedAddressResponse } from 'types/api/account';
|
||||
import type { Pool, PoolsResponse } from 'types/api/pools';
|
||||
import type { TokenVerifiedInfo } from 'types/api/token';
|
||||
|
||||
export const CONTRACT_INFO_API_RESOURCES = {
|
||||
address_verification: {
|
||||
path: '/api/v1/chains/:chainId/verified-addresses:type',
|
||||
pathParams: [ 'chainId' as const, 'type' as const ],
|
||||
},
|
||||
verified_addresses: {
|
||||
path: '/api/v1/chains/:chainId/verified-addresses',
|
||||
pathParams: [ 'chainId' as const ],
|
||||
},
|
||||
token_verified_info: {
|
||||
path: '/api/v1/chains/:chainId/token-infos/:hash',
|
||||
pathParams: [ 'chainId' as const, 'hash' as const ],
|
||||
},
|
||||
pools: {
|
||||
path: '/api/v1/chains/:chainId/pools',
|
||||
pathParams: [ 'chainId' as const ],
|
||||
filterFields: [ 'query' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
pool: {
|
||||
path: '/api/v1/chains/:chainId/pools/:hash',
|
||||
pathParams: [ 'chainId' as const, 'hash' as const ],
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type ContractInfoApiResourceName = `contractInfo:${ keyof typeof CONTRACT_INFO_API_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type ContractInfoApiResourcePayload<R extends ContractInfoApiResourceName> =
|
||||
R extends 'contractInfo:verified_addresses' ? VerifiedAddressResponse :
|
||||
R extends 'contractInfo:token_verified_info' ? TokenVerifiedInfo :
|
||||
R extends 'contractInfo:pools' ? PoolsResponse :
|
||||
R extends 'contractInfo:pool' ? Pool :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type ContractInfoApiPaginationFilters<R extends ContractInfoApiResourceName> =
|
||||
R extends 'contractInfo:pools' ? { query: string } :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,74 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
import type { AddressTagsResponse, ApiKeys, CustomAbis, TransactionTagsResponse, UserInfo, WatchlistResponse } from 'types/api/account';
|
||||
|
||||
export const GENERAL_API_ACCOUNT_RESOURCES = {
|
||||
// ACCOUNT
|
||||
csrf: {
|
||||
path: '/api/account/v2/get_csrf',
|
||||
},
|
||||
user_info: {
|
||||
path: '/api/account/v2/user/info',
|
||||
},
|
||||
custom_abi: {
|
||||
path: '/api/account/v2/user/custom_abis{/:id}',
|
||||
pathParams: [ 'id' as const ],
|
||||
},
|
||||
watchlist: {
|
||||
path: '/api/account/v2/user/watchlist{/:id}',
|
||||
pathParams: [ 'id' as const ],
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
private_tags_address: {
|
||||
path: '/api/account/v2/user/tags/address{/:id}',
|
||||
pathParams: [ 'id' as const ],
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
private_tags_tx: {
|
||||
path: '/api/account/v2/user/tags/transaction{/:id}',
|
||||
pathParams: [ 'id' as const ],
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
api_keys: {
|
||||
path: '/api/account/v2/user/api_keys{/:id}',
|
||||
pathParams: [ 'id' as const ],
|
||||
},
|
||||
|
||||
// AUTH
|
||||
auth_send_otp: {
|
||||
path: '/api/account/v2/send_otp',
|
||||
},
|
||||
auth_confirm_otp: {
|
||||
path: '/api/account/v2/confirm_otp',
|
||||
},
|
||||
auth_siwe_message: {
|
||||
path: '/api/account/v2/siwe_message',
|
||||
},
|
||||
auth_siwe_verify: {
|
||||
path: '/api/account/v2/authenticate_via_wallet',
|
||||
},
|
||||
auth_link_email: {
|
||||
path: '/api/account/v2/email/link',
|
||||
},
|
||||
auth_link_address: {
|
||||
path: '/api/account/v2/address/link',
|
||||
},
|
||||
auth_logout: {
|
||||
path: '/api/account/auth/logout',
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiAccountResourceName = `general:${ keyof typeof GENERAL_API_ACCOUNT_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiAccountResourcePayload<R extends GeneralApiAccountResourceName> =
|
||||
R extends 'general:user_info' ? UserInfo :
|
||||
R extends 'general:custom_abi' ? CustomAbis :
|
||||
R extends 'general:private_tags_address' ? AddressTagsResponse :
|
||||
R extends 'general:private_tags_tx' ? TransactionTagsResponse :
|
||||
R extends 'general:api_keys' ? ApiKeys :
|
||||
R extends 'general:watchlist' ? WatchlistResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,170 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
import type {
|
||||
AddressCounters,
|
||||
AddressBlocksValidatedResponse,
|
||||
AddressTokensResponse,
|
||||
AddressCollectionsResponse,
|
||||
AddressEpochRewardsResponse,
|
||||
AddressNFTsResponse,
|
||||
AddressWithdrawalsResponse,
|
||||
AddressXStarResponse,
|
||||
AddressCoinBalanceHistoryChart,
|
||||
AddressCoinBalanceHistoryResponse,
|
||||
AddressTokenTransferResponse,
|
||||
AddressInternalTxsResponse,
|
||||
AddressTransactionsResponse,
|
||||
AddressTabsCounters,
|
||||
Address,
|
||||
AddressTxsFilters,
|
||||
AddressTokenTransferFilters,
|
||||
AddressTokensFilter,
|
||||
AddressNFTTokensFilter,
|
||||
} from 'types/api/address';
|
||||
import type { AddressesMetadataSearchFilters, AddressesMetadataSearchResult, AddressesResponse } from 'types/api/addresses';
|
||||
import type { LogsResponseAddress } from 'types/api/log';
|
||||
import type { TransactionsSorting } from 'types/api/transaction';
|
||||
|
||||
export const GENERAL_API_ADDRESS_RESOURCES = {
|
||||
// ADDRESSES
|
||||
addresses: {
|
||||
path: '/api/v2/addresses/',
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
addresses_metadata_search: {
|
||||
path: '/api/v2/proxy/metadata/addresses',
|
||||
filterFields: [ 'slug' as const, 'tag_type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
|
||||
// ADDRESS INFO
|
||||
address: {
|
||||
path: '/api/v2/addresses/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
address_counters: {
|
||||
path: '/api/v2/addresses/:hash/counters',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
address_tabs_counters: {
|
||||
path: '/api/v2/addresses/:hash/tabs-counters',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
address_txs: {
|
||||
path: '/api/v2/addresses/:hash/transactions',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ 'filter' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
address_internal_txs: {
|
||||
path: '/api/v2/addresses/:hash/internal-transactions',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ 'filter' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
address_token_transfers: {
|
||||
path: '/api/v2/addresses/:hash/token-transfers',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ 'filter' as const, 'type' as const, 'token' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
address_blocks_validated: {
|
||||
path: '/api/v2/addresses/:hash/blocks-validated',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
address_coin_balance: {
|
||||
path: '/api/v2/addresses/:hash/coin-balance-history',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
address_coin_balance_chart: {
|
||||
path: '/api/v2/addresses/:hash/coin-balance-history-by-day',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ ],
|
||||
},
|
||||
address_logs: {
|
||||
path: '/api/v2/addresses/:hash/logs',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
address_tokens: {
|
||||
path: '/api/v2/addresses/:hash/tokens',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ 'type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
address_nfts: {
|
||||
path: '/api/v2/addresses/:hash/nft',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ 'type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
address_collections: {
|
||||
path: '/api/v2/addresses/:hash/nft/collections',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ 'type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
address_withdrawals: {
|
||||
path: '/api/v2/addresses/:hash/withdrawals',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
address_epoch_rewards: {
|
||||
path: '/api/v2/addresses/:hash/election-rewards',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
address_xstar_score: {
|
||||
path: '/api/v2/proxy/3dparty/xname/addresses/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiAddressResourceName = `general:${ keyof typeof GENERAL_API_ADDRESS_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiAddressResourcePayload<R extends GeneralApiAddressResourceName> =
|
||||
R extends 'general:addresses' ? AddressesResponse :
|
||||
R extends 'general:addresses_metadata_search' ? AddressesMetadataSearchResult :
|
||||
R extends 'general:address' ? Address :
|
||||
R extends 'general:address_counters' ? AddressCounters :
|
||||
R extends 'general:address_tabs_counters' ? AddressTabsCounters :
|
||||
R extends 'general:address_txs' ? AddressTransactionsResponse :
|
||||
R extends 'general:address_internal_txs' ? AddressInternalTxsResponse :
|
||||
R extends 'general:address_token_transfers' ? AddressTokenTransferResponse :
|
||||
R extends 'general:address_blocks_validated' ? AddressBlocksValidatedResponse :
|
||||
R extends 'general:address_coin_balance' ? AddressCoinBalanceHistoryResponse :
|
||||
R extends 'general:address_coin_balance_chart' ? AddressCoinBalanceHistoryChart :
|
||||
R extends 'general:address_logs' ? LogsResponseAddress :
|
||||
R extends 'general:address_tokens' ? AddressTokensResponse :
|
||||
R extends 'general:address_nfts' ? AddressNFTsResponse :
|
||||
R extends 'general:address_collections' ? AddressCollectionsResponse :
|
||||
R extends 'general:address_withdrawals' ? AddressWithdrawalsResponse :
|
||||
R extends 'general:address_epoch_rewards' ? AddressEpochRewardsResponse :
|
||||
R extends 'general:address_xstar_score' ? AddressXStarResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiAddressPaginationFilters<R extends GeneralApiAddressResourceName> =
|
||||
R extends 'general:addresses_metadata_search' ? AddressesMetadataSearchFilters :
|
||||
R extends 'general:address_txs' | 'general:address_internal_txs' ? AddressTxsFilters :
|
||||
R extends 'general:address_token_transfers' ? AddressTokenTransferFilters :
|
||||
R extends 'general:address_tokens' ? AddressTokensFilter :
|
||||
R extends 'general:address_nfts' ? AddressNFTTokensFilter :
|
||||
R extends 'general:address_collections' ? AddressNFTTokensFilter :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiAddressPaginationSorting<R extends GeneralApiAddressResourceName> =
|
||||
R extends 'general:address_txs' ? TransactionsSorting :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,68 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
import type {
|
||||
BlocksResponse,
|
||||
BlockTransactionsResponse,
|
||||
Block,
|
||||
BlockFilters,
|
||||
BlockWithdrawalsResponse,
|
||||
BlockCountdownResponse,
|
||||
BlockEpoch,
|
||||
BlockEpochElectionRewardDetailsResponse,
|
||||
} from 'types/api/block';
|
||||
import type { TTxsWithBlobsFilters } from 'types/api/txsFilters';
|
||||
|
||||
export const GENERAL_API_BLOCK_RESOURCES = {
|
||||
blocks: {
|
||||
path: '/api/v2/blocks',
|
||||
filterFields: [ 'type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
block: {
|
||||
path: '/api/v2/blocks/:height_or_hash',
|
||||
pathParams: [ 'height_or_hash' as const ],
|
||||
},
|
||||
block_txs: {
|
||||
path: '/api/v2/blocks/:height_or_hash/transactions',
|
||||
pathParams: [ 'height_or_hash' as const ],
|
||||
filterFields: [ 'type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
block_withdrawals: {
|
||||
path: '/api/v2/blocks/:height_or_hash/withdrawals',
|
||||
pathParams: [ 'height_or_hash' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
block_epoch: {
|
||||
path: '/api/v2/blocks/:height_or_hash/epoch',
|
||||
pathParams: [ 'height_or_hash' as const ],
|
||||
filterFields: [],
|
||||
},
|
||||
block_election_rewards: {
|
||||
path: '/api/v2/blocks/:height_or_hash/election-rewards/:reward_type',
|
||||
pathParams: [ 'height_or_hash' as const, 'reward_type' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiBlockResourceName = `general:${ keyof typeof GENERAL_API_BLOCK_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiBlockResourcePayload<R extends GeneralApiBlockResourceName> =
|
||||
R extends 'general:blocks' ? BlocksResponse :
|
||||
R extends 'general:block' ? Block :
|
||||
R extends 'general:block_countdown' ? BlockCountdownResponse :
|
||||
R extends 'general:block_txs' ? BlockTransactionsResponse :
|
||||
R extends 'general:block_withdrawals' ? BlockWithdrawalsResponse :
|
||||
R extends 'general:block_epoch' ? BlockEpoch :
|
||||
R extends 'general:block_election_rewards' ? BlockEpochElectionRewardDetailsResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiBlockPaginationFilters<R extends GeneralApiBlockResourceName> =
|
||||
R extends 'general:blocks' ? BlockFilters :
|
||||
R extends 'general:block_txs' ? TTxsWithBlobsFilters :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,63 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
import type {
|
||||
SmartContract,
|
||||
SmartContractSecurityAudits,
|
||||
SmartContractVerificationConfigRaw,
|
||||
} from 'types/api/contract';
|
||||
import type { VerifiedContractsResponse, VerifiedContractsCounters, VerifiedContractsFilters } from 'types/api/contracts';
|
||||
import type { VerifiedContractsSorting } from 'types/api/verifiedContracts';
|
||||
|
||||
export const GENERAL_API_CONTRACT_RESOURCES = {
|
||||
contract: {
|
||||
path: '/api/v2/smart-contracts/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
contract_verification_config: {
|
||||
path: '/api/v2/smart-contracts/verification/config',
|
||||
},
|
||||
contract_verification_via: {
|
||||
path: '/api/v2/smart-contracts/:hash/verification/via/:method',
|
||||
pathParams: [ 'hash' as const, 'method' as const ],
|
||||
},
|
||||
contract_solidity_scan_report: {
|
||||
path: '/api/v2/proxy/3dparty/solidityscan/smart-contracts/:hash/report',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
contract_security_audits: {
|
||||
path: '/api/v2/smart-contracts/:hash/audit-reports',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
verified_contracts: {
|
||||
path: '/api/v2/smart-contracts',
|
||||
filterFields: [ 'q' as const, 'filter' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
verified_contracts_counters: {
|
||||
path: '/api/v2/smart-contracts/counters',
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiContractResourceName = `general:${ keyof typeof GENERAL_API_CONTRACT_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiContractResourcePayload<R extends GeneralApiContractResourceName> =
|
||||
R extends 'general:contract' ? SmartContract :
|
||||
R extends 'general:contract_solidity_scan_report' ? unknown :
|
||||
R extends 'general:verified_contracts' ? VerifiedContractsResponse :
|
||||
R extends 'general:verified_contracts_counters' ? VerifiedContractsCounters :
|
||||
R extends 'general:contract_verification_config' ? SmartContractVerificationConfigRaw :
|
||||
R extends 'general:contract_security_audits' ? SmartContractSecurityAudits :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiContractPaginationFilters<R extends GeneralApiContractResourceName> =
|
||||
R extends 'general:verified_contracts' ? VerifiedContractsFilters :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiContractPaginationSorting<R extends GeneralApiContractResourceName> =
|
||||
R extends 'general:verified_contracts' ? VerifiedContractsSorting :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,97 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
|
||||
import type { GeneralApiAccountResourceName, GeneralApiAccountResourcePayload } from './account';
|
||||
import { GENERAL_API_ACCOUNT_RESOURCES } from './account';
|
||||
import type {
|
||||
GeneralApiAddressPaginationFilters,
|
||||
GeneralApiAddressPaginationSorting,
|
||||
GeneralApiAddressResourceName,
|
||||
GeneralApiAddressResourcePayload,
|
||||
} from './address';
|
||||
import { GENERAL_API_ADDRESS_RESOURCES } from './address';
|
||||
import type {
|
||||
GeneralApiBlockPaginationFilters,
|
||||
GeneralApiBlockResourceName, GeneralApiBlockResourcePayload } from './block';
|
||||
import { GENERAL_API_BLOCK_RESOURCES } from './block';
|
||||
import { GENERAL_API_CONTRACT_RESOURCES } from './contract';
|
||||
import type {
|
||||
GeneralApiContractPaginationFilters,
|
||||
GeneralApiContractPaginationSorting,
|
||||
GeneralApiContractResourceName,
|
||||
GeneralApiContractResourcePayload,
|
||||
} from './contract';
|
||||
import type {
|
||||
GeneralApiMiscPaginationFilters,
|
||||
GeneralApiMiscPaginationSorting,
|
||||
GeneralApiMiscResourceName,
|
||||
GeneralApiMiscResourcePayload,
|
||||
} from './misc';
|
||||
import { GENERAL_API_MISC_RESOURCES } from './misc';
|
||||
import type {
|
||||
GeneralApiRollupPaginationFilters,
|
||||
GeneralApiRollupPaginationSorting,
|
||||
GeneralApiRollupResourceName,
|
||||
GeneralApiRollupResourcePayload,
|
||||
} from './rollup';
|
||||
import { GENERAL_API_ROLLUP_RESOURCES } from './rollup';
|
||||
import type {
|
||||
GeneralApiTokenPaginationFilters,
|
||||
GeneralApiTokenPaginationSorting,
|
||||
GeneralApiTokenResourceName,
|
||||
GeneralApiTokenResourcePayload,
|
||||
} from './token';
|
||||
import { GENERAL_API_TOKEN_RESOURCES } from './token';
|
||||
import type { GeneralApiTxResourceName, GeneralApiTxResourcePayload, GeneralApiTxPaginationFilters } from './tx';
|
||||
import { GENERAL_API_TX_RESOURCES } from './tx';
|
||||
import type { GeneralApiV1ResourceName, GeneralApiV1ResourcePayload } from './v1';
|
||||
import { GENERAL_API_V1_RESOURCES } from './v1';
|
||||
|
||||
export const GENERAL_API_RESOURCES = {
|
||||
...GENERAL_API_ACCOUNT_RESOURCES,
|
||||
...GENERAL_API_ADDRESS_RESOURCES,
|
||||
...GENERAL_API_BLOCK_RESOURCES,
|
||||
...GENERAL_API_CONTRACT_RESOURCES,
|
||||
...GENERAL_API_MISC_RESOURCES,
|
||||
...GENERAL_API_ROLLUP_RESOURCES,
|
||||
...GENERAL_API_TOKEN_RESOURCES,
|
||||
...GENERAL_API_TX_RESOURCES,
|
||||
...GENERAL_API_V1_RESOURCES,
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiResourceName = `general:${ keyof typeof GENERAL_API_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiResourcePayload<R extends GeneralApiResourceName> =
|
||||
R extends GeneralApiAccountResourceName ? GeneralApiAccountResourcePayload<R> :
|
||||
R extends GeneralApiAddressResourceName ? GeneralApiAddressResourcePayload<R> :
|
||||
R extends GeneralApiBlockResourceName ? GeneralApiBlockResourcePayload<R> :
|
||||
R extends GeneralApiContractResourceName ? GeneralApiContractResourcePayload<R> :
|
||||
R extends GeneralApiMiscResourceName ? GeneralApiMiscResourcePayload<R> :
|
||||
R extends GeneralApiRollupResourceName ? GeneralApiRollupResourcePayload<R> :
|
||||
R extends GeneralApiTokenResourceName ? GeneralApiTokenResourcePayload<R> :
|
||||
R extends GeneralApiTxResourceName ? GeneralApiTxResourcePayload<R> :
|
||||
R extends GeneralApiV1ResourceName ? GeneralApiV1ResourcePayload<R> :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiPaginationFilters<R extends GeneralApiResourceName> =
|
||||
R extends GeneralApiAddressResourceName ? GeneralApiAddressPaginationFilters<R> :
|
||||
R extends GeneralApiBlockResourceName ? GeneralApiBlockPaginationFilters<R> :
|
||||
R extends GeneralApiContractResourceName ? GeneralApiContractPaginationFilters<R> :
|
||||
R extends GeneralApiMiscResourceName ? GeneralApiMiscPaginationFilters<R> :
|
||||
R extends GeneralApiRollupResourceName ? GeneralApiRollupPaginationFilters<R> :
|
||||
R extends GeneralApiTokenResourceName ? GeneralApiTokenPaginationFilters<R> :
|
||||
R extends GeneralApiTxResourceName ? GeneralApiTxPaginationFilters<R> :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiPaginationSorting<R extends GeneralApiResourceName> =
|
||||
R extends GeneralApiAddressResourceName ? GeneralApiAddressPaginationSorting<R> :
|
||||
R extends GeneralApiContractResourceName ? GeneralApiContractPaginationSorting<R> :
|
||||
R extends GeneralApiMiscResourceName ? GeneralApiMiscPaginationSorting<R> :
|
||||
R extends GeneralApiRollupResourceName ? GeneralApiRollupPaginationSorting<R> :
|
||||
R extends GeneralApiTokenResourceName ? GeneralApiTokenPaginationSorting<R> :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,299 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
import type { AdvancedFilterParams, AdvancedFilterResponse, AdvancedFilterMethodsResponse } from 'types/api/advancedFilter';
|
||||
import type {
|
||||
ArbitrumL2TxnBatchesItem,
|
||||
ArbitrumLatestDepositsResponse,
|
||||
} from 'types/api/arbitrumL2';
|
||||
import type { Blob } from 'types/api/blobs';
|
||||
import type { Block } from 'types/api/block';
|
||||
import type { ChartMarketResponse, ChartSecondaryCoinPriceResponse, ChartTransactionResponse } from 'types/api/charts';
|
||||
import type { BackendVersionConfig, CsvExportConfig } from 'types/api/configs';
|
||||
import type { IndexingStatus } from 'types/api/indexingStatus';
|
||||
import type { NovesAccountHistoryResponse, NovesDescribeTxsResponse, NovesResponseData } from 'types/api/noves';
|
||||
import type {
|
||||
OptimisticL2DepositsItem,
|
||||
} from 'types/api/optimisticL2';
|
||||
import type { SearchRedirectResult, SearchResult, SearchResultFilters, SearchResultItem } from 'types/api/search';
|
||||
import type { HomeStats } from 'types/api/stats';
|
||||
import type {
|
||||
Transaction,
|
||||
} from 'types/api/transaction';
|
||||
import type { TxInterpretationResponse } from 'types/api/txInterpretation';
|
||||
import type { UserOpsResponse, UserOp, UserOpsFilters, UserOpsAccount } from 'types/api/userOps';
|
||||
import type {
|
||||
ValidatorsStabilityCountersResponse,
|
||||
ValidatorsStabilityFilters,
|
||||
ValidatorsStabilityResponse,
|
||||
ValidatorsStabilitySorting,
|
||||
ValidatorsBlackfortCountersResponse,
|
||||
ValidatorsBlackfortResponse,
|
||||
ValidatorsBlackfortSorting,
|
||||
ValidatorsZilliqaResponse,
|
||||
ValidatorZilliqa,
|
||||
} from 'types/api/validators';
|
||||
import type { WithdrawalsResponse, WithdrawalsCounters } from 'types/api/withdrawals';
|
||||
import type {
|
||||
ZkEvmL2TxnBatchesItem,
|
||||
} from 'types/api/zkEvmL2';
|
||||
|
||||
export const GENERAL_API_MISC_RESOURCES = {
|
||||
// WITHDRAWALS
|
||||
withdrawals: {
|
||||
path: '/api/v2/withdrawals',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
withdrawals_counters: {
|
||||
path: '/api/v2/withdrawals/counters',
|
||||
},
|
||||
|
||||
// APP STATS
|
||||
stats: {
|
||||
path: '/api/v2/stats',
|
||||
headers: {
|
||||
'updated-gas-oracle': 'true',
|
||||
},
|
||||
},
|
||||
stats_charts_txs: {
|
||||
path: '/api/v2/stats/charts/transactions',
|
||||
},
|
||||
stats_charts_market: {
|
||||
path: '/api/v2/stats/charts/market',
|
||||
},
|
||||
stats_charts_secondary_coin_price: {
|
||||
path: '/api/v2/stats/charts/secondary-coin-market',
|
||||
},
|
||||
|
||||
// HOMEPAGE
|
||||
homepage_blocks: {
|
||||
path: '/api/v2/main-page/blocks',
|
||||
},
|
||||
homepage_optimistic_deposits: {
|
||||
path: '/api/v2/main-page/optimism-deposits',
|
||||
},
|
||||
homepage_arbitrum_deposits: {
|
||||
path: '/api/v2/main-page/arbitrum/messages/to-rollup',
|
||||
},
|
||||
homepage_txs: {
|
||||
path: '/api/v2/main-page/transactions',
|
||||
},
|
||||
homepage_zkevm_l2_batches: {
|
||||
path: '/api/v2/main-page/zkevm/batches/confirmed',
|
||||
},
|
||||
homepage_arbitrum_l2_batches: {
|
||||
path: '/api/v2/main-page/arbitrum/batches/committed',
|
||||
},
|
||||
homepage_txs_watchlist: {
|
||||
path: '/api/v2/main-page/transactions/watchlist',
|
||||
},
|
||||
homepage_indexing_status: {
|
||||
path: '/api/v2/main-page/indexing-status',
|
||||
},
|
||||
homepage_zkevm_latest_batch: {
|
||||
path: '/api/v2/main-page/zkevm/batches/latest-number',
|
||||
},
|
||||
homepage_zksync_latest_batch: {
|
||||
path: '/api/v2/main-page/zksync/batches/latest-number',
|
||||
},
|
||||
homepage_arbitrum_latest_batch: {
|
||||
path: '/api/v2/main-page/arbitrum/batches/latest-number',
|
||||
},
|
||||
|
||||
// SEARCH
|
||||
quick_search: {
|
||||
path: '/api/v2/search/quick',
|
||||
filterFields: [ 'q' ],
|
||||
},
|
||||
search: {
|
||||
path: '/api/v2/search',
|
||||
filterFields: [ 'q' ],
|
||||
paginated: true,
|
||||
},
|
||||
search_check_redirect: {
|
||||
path: '/api/v2/search/check-redirect',
|
||||
},
|
||||
|
||||
// NOVES-FI
|
||||
noves_transaction: {
|
||||
path: '/api/v2/proxy/3dparty/noves-fi/transactions/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
noves_address_history: {
|
||||
path: '/api/v2/proxy/3dparty/noves-fi/addresses/:address/transactions',
|
||||
pathParams: [ 'address' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
noves_describe_txs: {
|
||||
path: '/api/v2/proxy/3dparty/noves-fi/transaction-descriptions',
|
||||
},
|
||||
|
||||
// USER OPS
|
||||
user_ops: {
|
||||
path: '/api/v2/proxy/account-abstraction/operations',
|
||||
filterFields: [ 'transaction_hash' as const, 'sender' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
user_op: {
|
||||
path: '/api/v2/proxy/account-abstraction/operations/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
user_ops_account: {
|
||||
path: '/api/v2/proxy/account-abstraction/accounts/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
user_op_interpretation: {
|
||||
path: '/api/v2/proxy/account-abstraction/operations/:hash/summary',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
|
||||
// VALIDATORS
|
||||
validators_stability: {
|
||||
path: '/api/v2/validators/stability',
|
||||
filterFields: [ 'address_hash' as const, 'state_filter' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
validators_stability_counters: {
|
||||
path: '/api/v2/validators/stability/counters',
|
||||
},
|
||||
validators_blackfort: {
|
||||
path: '/api/v2/validators/blackfort',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
validators_blackfort_counters: {
|
||||
path: '/api/v2/validators/blackfort/counters',
|
||||
},
|
||||
validators_zilliqa: {
|
||||
path: '/api/v2/validators/zilliqa',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
validator_zilliqa: {
|
||||
path: '/api/v2/validators/zilliqa/:bls_public_key',
|
||||
pathParams: [ 'bls_public_key' as const ],
|
||||
filterFields: [],
|
||||
},
|
||||
|
||||
// BLOBS
|
||||
blob: {
|
||||
path: '/api/v2/blobs/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
|
||||
// ADVANCED FILTER
|
||||
advanced_filter: {
|
||||
path: '/api/v2/advanced-filters',
|
||||
filterFields: [
|
||||
'transaction_types' as const,
|
||||
'methods' as const,
|
||||
'methods_names' as const /* frontend only */,
|
||||
'age_from' as const,
|
||||
'age_to' as const,
|
||||
'age' as const /* frontend only */,
|
||||
'from_address_hashes_to_include' as const,
|
||||
'from_address_hashes_to_exclude' as const,
|
||||
'to_address_hashes_to_include' as const,
|
||||
'to_address_hashes_to_exclude' as const,
|
||||
'address_relation' as const,
|
||||
'amount_from' as const,
|
||||
'amount_to' as const,
|
||||
'token_contract_address_hashes_to_include' as const,
|
||||
'token_contract_symbols_to_include' as const /* frontend only */,
|
||||
'token_contract_address_hashes_to_exclude' as const,
|
||||
'token_contract_symbols_to_exclude' as const /* frontend only */,
|
||||
'block_number' as const,
|
||||
'transaction_index' as const,
|
||||
'internal_transaction_index' as const,
|
||||
'token_transfer_index' as const,
|
||||
],
|
||||
paginated: true,
|
||||
},
|
||||
advanced_filter_methods: {
|
||||
path: '/api/v2/advanced-filters/methods',
|
||||
filterFields: [ 'q' as const ],
|
||||
},
|
||||
advanced_filter_csv: {
|
||||
path: '/api/v2/advanced-filters/csv',
|
||||
},
|
||||
|
||||
// CONFIGS
|
||||
config_backend_version: {
|
||||
path: '/api/v2/config/backend-version',
|
||||
},
|
||||
config_csv_export: {
|
||||
path: '/api/v2/config/csv-export',
|
||||
},
|
||||
|
||||
// CSV EXPORT
|
||||
csv_export_token_holders: {
|
||||
path: '/api/v2/tokens/:hash/holders/csv',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
|
||||
// OTHER
|
||||
api_v2_key: {
|
||||
path: '/api/v2/key',
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiMiscResourceName = `general:${ keyof typeof GENERAL_API_MISC_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiMiscResourcePayload<R extends GeneralApiMiscResourceName> =
|
||||
R extends 'general:stats' ? HomeStats :
|
||||
R extends 'general:stats_charts_txs' ? ChartTransactionResponse :
|
||||
R extends 'general:stats_charts_market' ? ChartMarketResponse :
|
||||
R extends 'general:stats_charts_secondary_coin_price' ? ChartSecondaryCoinPriceResponse :
|
||||
R extends 'general:homepage_blocks' ? Array<Block> :
|
||||
R extends 'general:homepage_txs' ? Array<Transaction> :
|
||||
R extends 'general:homepage_txs_watchlist' ? Array<Transaction> :
|
||||
R extends 'general:homepage_optimistic_deposits' ? Array<OptimisticL2DepositsItem> :
|
||||
R extends 'general:homepage_arbitrum_deposits' ? ArbitrumLatestDepositsResponse :
|
||||
R extends 'general:homepage_zkevm_l2_batches' ? { items: Array<ZkEvmL2TxnBatchesItem> } :
|
||||
R extends 'general:homepage_arbitrum_l2_batches' ? { items: Array<ArbitrumL2TxnBatchesItem> } :
|
||||
R extends 'general:homepage_indexing_status' ? IndexingStatus :
|
||||
R extends 'general:homepage_zkevm_latest_batch' ? number :
|
||||
R extends 'general:homepage_zksync_latest_batch' ? number :
|
||||
R extends 'general:homepage_arbitrum_latest_batch' ? number :
|
||||
R extends 'general:quick_search' ? Array<SearchResultItem> :
|
||||
R extends 'general:search' ? SearchResult :
|
||||
R extends 'general:search_check_redirect' ? SearchRedirectResult :
|
||||
R extends 'general:config_backend_version' ? BackendVersionConfig :
|
||||
R extends 'general:config_csv_export' ? CsvExportConfig :
|
||||
R extends 'general:blob' ? Blob :
|
||||
R extends 'general:validators_stability' ? ValidatorsStabilityResponse :
|
||||
R extends 'general:validators_stability_counters' ? ValidatorsStabilityCountersResponse :
|
||||
R extends 'general:validators_blackfort' ? ValidatorsBlackfortResponse :
|
||||
R extends 'general:validators_blackfort_counters' ? ValidatorsBlackfortCountersResponse :
|
||||
R extends 'general:validators_zilliqa' ? ValidatorsZilliqaResponse :
|
||||
R extends 'general:validator_zilliqa' ? ValidatorZilliqa :
|
||||
R extends 'general:user_ops' ? UserOpsResponse :
|
||||
R extends 'general:user_op' ? UserOp :
|
||||
R extends 'general:user_ops_account' ? UserOpsAccount :
|
||||
R extends 'general:user_op_interpretation' ? TxInterpretationResponse :
|
||||
R extends 'general:noves_transaction' ? NovesResponseData :
|
||||
R extends 'general:noves_address_history' ? NovesAccountHistoryResponse :
|
||||
R extends 'general:noves_describe_txs' ? NovesDescribeTxsResponse :
|
||||
R extends 'general:withdrawals' ? WithdrawalsResponse :
|
||||
R extends 'general:withdrawals_counters' ? WithdrawalsCounters :
|
||||
R extends 'general:advanced_filter' ? AdvancedFilterResponse :
|
||||
R extends 'general:advanced_filter_methods' ? AdvancedFilterMethodsResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiMiscPaginationFilters<R extends GeneralApiMiscResourceName> =
|
||||
R extends 'general:search' ? SearchResultFilters :
|
||||
R extends 'general:user_ops' ? UserOpsFilters :
|
||||
R extends 'general:validators_stability' ? ValidatorsStabilityFilters :
|
||||
R extends 'general:advanced_filter' ? AdvancedFilterParams :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiMiscPaginationSorting<R extends GeneralApiMiscResourceName> =
|
||||
R extends 'general:validators_stability' ? ValidatorsStabilitySorting :
|
||||
R extends 'general:validators_blackfort' ? ValidatorsBlackfortSorting :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,403 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
import type {
|
||||
AddressMudTables,
|
||||
AddressMudTablesFilter,
|
||||
AddressMudRecords,
|
||||
AddressMudRecordsFilter,
|
||||
AddressMudRecordsSorting,
|
||||
AddressMudRecord,
|
||||
} from 'types/api/address';
|
||||
import type {
|
||||
ArbitrumL2MessagesResponse,
|
||||
ArbitrumL2TxnBatch,
|
||||
ArbitrumL2TxnBatchesResponse,
|
||||
ArbitrumL2BatchTxs,
|
||||
ArbitrumL2BatchBlocks,
|
||||
ArbitrumL2TxnWithdrawalsResponse,
|
||||
ArbitrumL2MessageClaimResponse,
|
||||
} from 'types/api/arbitrumL2';
|
||||
import type {
|
||||
SmartContractMudSystemsResponse,
|
||||
SmartContractMudSystemInfo,
|
||||
} from 'types/api/contract';
|
||||
import type { InteropMessageListResponse } from 'types/api/interop';
|
||||
import type { MudWorldsResponse } from 'types/api/mudWorlds';
|
||||
import type {
|
||||
OptimisticL2DepositsResponse,
|
||||
OptimisticL2OutputRootsResponse,
|
||||
OptimisticL2TxnBatchesResponse,
|
||||
OptimisticL2WithdrawalsResponse,
|
||||
OptimisticL2DisputeGamesResponse,
|
||||
OptimismL2TxnBatch,
|
||||
OptimismL2BatchTxs,
|
||||
OptimismL2BatchBlocks,
|
||||
} from 'types/api/optimisticL2';
|
||||
import type {
|
||||
ScrollL2BatchesResponse,
|
||||
ScrollL2TxnBatch,
|
||||
ScrollL2TxnBatchTxs,
|
||||
ScrollL2TxnBatchBlocks,
|
||||
ScrollL2MessagesResponse,
|
||||
} from 'types/api/scrollL2';
|
||||
import type { ShibariumWithdrawalsResponse, ShibariumDepositsResponse } from 'types/api/shibarium';
|
||||
import type {
|
||||
ZkEvmL2DepositsResponse,
|
||||
ZkEvmL2TxnBatch,
|
||||
ZkEvmL2TxnBatchesResponse,
|
||||
ZkEvmL2TxnBatchTxs,
|
||||
ZkEvmL2WithdrawalsResponse,
|
||||
} from 'types/api/zkEvmL2';
|
||||
import type { ZkSyncBatch, ZkSyncBatchesResponse, ZkSyncBatchTxs } from 'types/api/zkSyncL2';
|
||||
|
||||
export const GENERAL_API_ROLLUP_RESOURCES = {
|
||||
// OPTIMISTIC
|
||||
optimistic_l2_deposits: {
|
||||
path: '/api/v2/optimism/deposits',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
optimistic_l2_deposits_count: {
|
||||
path: '/api/v2/optimism/deposits/count',
|
||||
},
|
||||
optimistic_l2_withdrawals: {
|
||||
path: '/api/v2/optimism/withdrawals',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
optimistic_l2_withdrawals_count: {
|
||||
path: '/api/v2/optimism/withdrawals/count',
|
||||
},
|
||||
optimistic_l2_output_roots: {
|
||||
path: '/api/v2/optimism/output-roots',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
optimistic_l2_output_roots_count: {
|
||||
path: '/api/v2/optimism/output-roots/count',
|
||||
},
|
||||
optimistic_l2_txn_batches: {
|
||||
path: '/api/v2/optimism/batches',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
optimistic_l2_txn_batches_count: {
|
||||
path: '/api/v2/optimism/batches/count',
|
||||
},
|
||||
optimistic_l2_txn_batch: {
|
||||
path: '/api/v2/optimism/batches/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
},
|
||||
optimistic_l2_txn_batch_celestia: {
|
||||
path: '/api/v2/optimism/batches/da/celestia/:height/:commitment',
|
||||
pathParams: [ 'height' as const, 'commitment' as const ],
|
||||
},
|
||||
optimistic_l2_txn_batch_txs: {
|
||||
path: '/api/v2/transactions/optimism-batch/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
optimistic_l2_txn_batch_blocks: {
|
||||
path: '/api/v2/blocks/optimism-batch/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
optimistic_l2_dispute_games: {
|
||||
path: '/api/v2/optimism/games',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
optimistic_l2_dispute_games_count: {
|
||||
path: '/api/v2/optimism/games/count',
|
||||
},
|
||||
|
||||
// OPTIMISTIC INTEROP
|
||||
optimistic_l2_interop_messages: {
|
||||
path: '/api/v2/optimism/interop/messages',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
optimistic_l2_interop_messages_count: {
|
||||
path: '/api/v2/optimism/interop/messages/count',
|
||||
},
|
||||
|
||||
// MUD
|
||||
mud_worlds: {
|
||||
path: '/api/v2/mud/worlds',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
mud_tables: {
|
||||
path: '/api/v2/mud/worlds/:hash/tables',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ 'q' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
mud_tables_count: {
|
||||
path: '/api/v2/mud/worlds/:hash/tables/count',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
mud_records: {
|
||||
path: '/api/v2/mud/worlds/:hash/tables/:table_id/records',
|
||||
pathParams: [ 'hash' as const, 'table_id' as const ],
|
||||
filterFields: [ 'filter_key0' as const, 'filter_key1' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
mud_record: {
|
||||
path: '/api/v2/mud/worlds/:hash/tables/:table_id/records/:record_id',
|
||||
pathParams: [ 'hash' as const, 'table_id' as const, 'record_id' as const ],
|
||||
},
|
||||
mud_systems: {
|
||||
path: '/api/v2/mud/worlds/:hash/systems',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
mud_system_info: {
|
||||
path: '/api/v2/mud/worlds/:hash/systems/:system_address',
|
||||
pathParams: [ 'hash' as const, 'system_address' as const ],
|
||||
},
|
||||
|
||||
// ARBITRUM
|
||||
arbitrum_l2_messages: {
|
||||
path: '/api/v2/arbitrum/messages/:direction',
|
||||
pathParams: [ 'direction' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
arbitrum_l2_messages_count: {
|
||||
path: '/api/v2/arbitrum/messages/:direction/count',
|
||||
pathParams: [ 'direction' as const ],
|
||||
},
|
||||
arbitrum_l2_txn_batches: {
|
||||
path: '/api/v2/arbitrum/batches',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
arbitrum_l2_txn_batches_count: {
|
||||
path: '/api/v2/arbitrum/batches/count',
|
||||
},
|
||||
arbitrum_l2_txn_batch: {
|
||||
path: '/api/v2/arbitrum/batches/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
},
|
||||
arbitrum_l2_txn_batch_celestia: {
|
||||
path: '/api/v2/arbitrum/batches/da/celestia/:height/:commitment',
|
||||
pathParams: [ 'height' as const, 'commitment' as const ],
|
||||
},
|
||||
arbitrum_l2_txn_batch_txs: {
|
||||
path: '/api/v2/transactions/arbitrum-batch/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
arbitrum_l2_txn_batch_blocks: {
|
||||
path: '/api/v2/blocks/arbitrum-batch/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
arbitrum_l2_txn_withdrawals: {
|
||||
path: '/api/v2/arbitrum/messages/withdrawals/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [],
|
||||
},
|
||||
arbitrum_l2_message_claim: {
|
||||
path: '/api/v2/arbitrum/messages/claim/:id',
|
||||
pathParams: [ 'id' as const ],
|
||||
filterFields: [],
|
||||
},
|
||||
|
||||
// zkSync
|
||||
zksync_l2_txn_batches: {
|
||||
path: '/api/v2/zksync/batches',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
zksync_l2_txn_batches_count: {
|
||||
path: '/api/v2/zksync/batches/count',
|
||||
},
|
||||
zksync_l2_txn_batch: {
|
||||
path: '/api/v2/zksync/batches/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
},
|
||||
zksync_l2_txn_batch_txs: {
|
||||
path: '/api/v2/transactions/zksync-batch/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
|
||||
// zkEvm
|
||||
zkevm_l2_deposits: {
|
||||
path: '/api/v2/zkevm/deposits',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
zkevm_l2_deposits_count: {
|
||||
path: '/api/v2/zkevm/deposits/count',
|
||||
},
|
||||
zkevm_l2_withdrawals: {
|
||||
path: '/api/v2/zkevm/withdrawals',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
zkevm_l2_withdrawals_count: {
|
||||
path: '/api/v2/zkevm/withdrawals/count',
|
||||
},
|
||||
zkevm_l2_txn_batches: {
|
||||
path: '/api/v2/zkevm/batches',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
zkevm_l2_txn_batches_count: {
|
||||
path: '/api/v2/zkevm/batches/count',
|
||||
},
|
||||
zkevm_l2_txn_batch: {
|
||||
path: '/api/v2/zkevm/batches/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
},
|
||||
zkevm_l2_txn_batch_txs: {
|
||||
path: '/api/v2/transactions/zkevm-batch/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
|
||||
// SHIBARIUM
|
||||
shibarium_deposits: {
|
||||
path: '/api/v2/shibarium/deposits',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
shibarium_deposits_count: {
|
||||
path: '/api/v2/shibarium/deposits/count',
|
||||
},
|
||||
shibarium_withdrawals: {
|
||||
path: '/api/v2/shibarium/withdrawals',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
shibarium_withdrawals_count: {
|
||||
path: '/api/v2/shibarium/withdrawals/count',
|
||||
},
|
||||
|
||||
// SCROLL
|
||||
scroll_l2_deposits: {
|
||||
path: '/api/v2/scroll/deposits',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
scroll_l2_deposits_count: {
|
||||
path: '/api/v2/scroll/deposits/count',
|
||||
},
|
||||
scroll_l2_withdrawals: {
|
||||
path: '/api/v2/scroll/withdrawals',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
scroll_l2_withdrawals_count: {
|
||||
path: '/api/v2/scroll/withdrawals/count',
|
||||
},
|
||||
scroll_l2_txn_batches: {
|
||||
path: '/api/v2/scroll/batches',
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
scroll_l2_txn_batches_count: {
|
||||
path: '/api/v2/scroll/batches/count',
|
||||
},
|
||||
scroll_l2_txn_batch: {
|
||||
path: '/api/v2/scroll/batches/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
},
|
||||
scroll_l2_txn_batch_txs: {
|
||||
path: '/api/v2/transactions/scroll-batch/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
scroll_l2_txn_batch_blocks: {
|
||||
path: '/api/v2/blocks/scroll-batch/:number',
|
||||
pathParams: [ 'number' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiRollupResourceName = `general:${ keyof typeof GENERAL_API_ROLLUP_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiRollupResourcePayload<R extends GeneralApiRollupResourceName> =
|
||||
R extends 'general:optimistic_l2_output_roots' ? OptimisticL2OutputRootsResponse :
|
||||
R extends 'general:optimistic_l2_withdrawals' ? OptimisticL2WithdrawalsResponse :
|
||||
R extends 'general:optimistic_l2_deposits' ? OptimisticL2DepositsResponse :
|
||||
R extends 'general:optimistic_l2_txn_batches' ? OptimisticL2TxnBatchesResponse :
|
||||
R extends 'general:optimistic_l2_txn_batches_count' ? number :
|
||||
R extends 'general:optimistic_l2_txn_batch' ? OptimismL2TxnBatch :
|
||||
R extends 'general:optimistic_l2_txn_batch_celestia' ? OptimismL2TxnBatch :
|
||||
R extends 'general:optimistic_l2_txn_batch_txs' ? OptimismL2BatchTxs :
|
||||
R extends 'general:optimistic_l2_txn_batch_blocks' ? OptimismL2BatchBlocks :
|
||||
R extends 'general:optimistic_l2_dispute_games' ? OptimisticL2DisputeGamesResponse :
|
||||
R extends 'general:optimistic_l2_output_roots_count' ? number :
|
||||
R extends 'general:optimistic_l2_withdrawals_count' ? number :
|
||||
R extends 'general:optimistic_l2_deposits_count' ? number :
|
||||
R extends 'general:optimistic_l2_dispute_games_count' ? number :
|
||||
R extends 'general:optimistic_l2_interop_messages' ? InteropMessageListResponse :
|
||||
R extends 'general:optimistic_l2_interop_messages_count' ? number :
|
||||
R extends 'general:shibarium_withdrawals' ? ShibariumWithdrawalsResponse :
|
||||
R extends 'general:shibarium_deposits' ? ShibariumDepositsResponse :
|
||||
R extends 'general:shibarium_withdrawals_count' ? number :
|
||||
R extends 'general:shibarium_deposits_count' ? number :
|
||||
R extends 'general:arbitrum_l2_messages' ? ArbitrumL2MessagesResponse :
|
||||
R extends 'general:arbitrum_l2_messages_count' ? number :
|
||||
R extends 'general:arbitrum_l2_txn_batches' ? ArbitrumL2TxnBatchesResponse :
|
||||
R extends 'general:arbitrum_l2_txn_batches_count' ? number :
|
||||
R extends 'general:arbitrum_l2_txn_batch' ? ArbitrumL2TxnBatch :
|
||||
R extends 'general:arbitrum_l2_txn_batch_celestia' ? ArbitrumL2TxnBatch :
|
||||
R extends 'general:arbitrum_l2_txn_batch_txs' ? ArbitrumL2BatchTxs :
|
||||
R extends 'general:arbitrum_l2_txn_batch_blocks' ? ArbitrumL2BatchBlocks :
|
||||
R extends 'general:arbitrum_l2_txn_withdrawals' ? ArbitrumL2TxnWithdrawalsResponse :
|
||||
R extends 'general:arbitrum_l2_message_claim' ? ArbitrumL2MessageClaimResponse :
|
||||
R extends 'general:zkevm_l2_deposits' ? ZkEvmL2DepositsResponse :
|
||||
R extends 'general:zkevm_l2_deposits_count' ? number :
|
||||
R extends 'general:zkevm_l2_withdrawals' ? ZkEvmL2WithdrawalsResponse :
|
||||
R extends 'general:zkevm_l2_withdrawals_count' ? number :
|
||||
R extends 'general:zkevm_l2_txn_batches' ? ZkEvmL2TxnBatchesResponse :
|
||||
R extends 'general:zkevm_l2_txn_batches_count' ? number :
|
||||
R extends 'general:zkevm_l2_txn_batch' ? ZkEvmL2TxnBatch :
|
||||
R extends 'general:zkevm_l2_txn_batch_txs' ? ZkEvmL2TxnBatchTxs :
|
||||
R extends 'general:zksync_l2_txn_batches' ? ZkSyncBatchesResponse :
|
||||
R extends 'general:zksync_l2_txn_batches_count' ? number :
|
||||
R extends 'general:zksync_l2_txn_batch' ? ZkSyncBatch :
|
||||
R extends 'general:zksync_l2_txn_batch_txs' ? ZkSyncBatchTxs :
|
||||
R extends 'general:scroll_l2_txn_batch_txs' ? ScrollL2TxnBatchTxs :
|
||||
R extends 'general:scroll_l2_txn_batch_blocks' ? ScrollL2TxnBatchBlocks :
|
||||
R extends 'general:scroll_l2_txn_batches' ? ScrollL2BatchesResponse :
|
||||
R extends 'general:scroll_l2_txn_batches_count' ? number :
|
||||
R extends 'general:scroll_l2_txn_batch' ? ScrollL2TxnBatch :
|
||||
R extends 'general:scroll_l2_deposits' ? ScrollL2MessagesResponse :
|
||||
R extends 'general:scroll_l2_deposits_count' ? number :
|
||||
R extends 'general:scroll_l2_withdrawals' ? ScrollL2MessagesResponse :
|
||||
R extends 'general:scroll_l2_withdrawals_count' ? number :
|
||||
R extends 'general:mud_worlds' ? MudWorldsResponse :
|
||||
R extends 'general:mud_tables' ? AddressMudTables :
|
||||
R extends 'general:mud_tables_count' ? number :
|
||||
R extends 'general:mud_records' ? AddressMudRecords :
|
||||
R extends 'general:mud_record' ? AddressMudRecord :
|
||||
R extends 'general:mud_systems' ? SmartContractMudSystemsResponse :
|
||||
R extends 'general:mud_system_info' ? SmartContractMudSystemInfo :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiRollupPaginationFilters<R extends GeneralApiRollupResourceName> =
|
||||
R extends 'general:mud_tables' ? AddressMudTablesFilter :
|
||||
R extends 'general:mud_records' ? AddressMudRecordsFilter :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiRollupPaginationSorting<R extends GeneralApiRollupResourceName> =
|
||||
R extends 'general:mud_records' ? AddressMudRecordsSorting :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,122 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
import type {
|
||||
TokenCounters,
|
||||
TokenInfo,
|
||||
TokenHolders,
|
||||
TokenInventoryResponse,
|
||||
TokenInstance,
|
||||
TokenInstanceTransfersCount,
|
||||
TokenInventoryFilters,
|
||||
} from 'types/api/token';
|
||||
import type { TokensResponse, TokensFilters, TokensSorting, TokenInstanceTransferResponse, TokensBridgedFilters } from 'types/api/tokens';
|
||||
import type { TokenTransferResponse, TokenTransferFilters } from 'types/api/tokenTransfer';
|
||||
|
||||
export const GENERAL_API_TOKEN_RESOURCES = {
|
||||
// TOKEN
|
||||
token: {
|
||||
path: '/api/v2/tokens/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
token_counters: {
|
||||
path: '/api/v2/tokens/:hash/counters',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
token_holders: {
|
||||
path: '/api/v2/tokens/:hash/holders',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
token_transfers: {
|
||||
path: '/api/v2/tokens/:hash/transfers',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
token_inventory: {
|
||||
path: '/api/v2/tokens/:hash/instances',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ 'holder_address_hash' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
tokens: {
|
||||
path: '/api/v2/tokens',
|
||||
filterFields: [ 'q' as const, 'type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
tokens_bridged: {
|
||||
path: '/api/v2/tokens/bridged',
|
||||
filterFields: [ 'q' as const, 'chain_ids' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
|
||||
// TOKEN INSTANCE
|
||||
token_instance: {
|
||||
path: '/api/v2/tokens/:hash/instances/:id',
|
||||
pathParams: [ 'hash' as const, 'id' as const ],
|
||||
},
|
||||
token_instance_transfers_count: {
|
||||
path: '/api/v2/tokens/:hash/instances/:id/transfers-count',
|
||||
pathParams: [ 'hash' as const, 'id' as const ],
|
||||
},
|
||||
token_instance_transfers: {
|
||||
path: '/api/v2/tokens/:hash/instances/:id/transfers',
|
||||
pathParams: [ 'hash' as const, 'id' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
token_instance_holders: {
|
||||
path: '/api/v2/tokens/:hash/instances/:id/holders',
|
||||
pathParams: [ 'hash' as const, 'id' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
token_instance_refresh_metadata: {
|
||||
path: '/api/v2/tokens/:hash/instances/:id/refetch-metadata',
|
||||
pathParams: [ 'hash' as const, 'id' as const ],
|
||||
filterFields: [],
|
||||
},
|
||||
|
||||
// TOKEN TRANSFERS
|
||||
token_transfers_all: {
|
||||
path: '/api/v2/token-transfers',
|
||||
filterFields: [ 'type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiTokenResourceName = `general:${ keyof typeof GENERAL_API_TOKEN_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiTokenResourcePayload<R extends GeneralApiTokenResourceName> =
|
||||
R extends 'general:token' ? TokenInfo :
|
||||
R extends 'general:token_counters' ? TokenCounters :
|
||||
R extends 'general:token_transfers' ? TokenTransferResponse :
|
||||
R extends 'general:token_holders' ? TokenHolders :
|
||||
R extends 'general:token_instance' ? TokenInstance :
|
||||
R extends 'general:token_instance_transfers_count' ? TokenInstanceTransfersCount :
|
||||
R extends 'general:token_instance_transfers' ? TokenInstanceTransferResponse :
|
||||
R extends 'general:token_instance_holders' ? TokenHolders :
|
||||
R extends 'general:token_inventory' ? TokenInventoryResponse :
|
||||
R extends 'general:tokens' ? TokensResponse :
|
||||
R extends 'general:tokens_bridged' ? TokensResponse :
|
||||
R extends 'general:token_transfers_all' ? TokenTransferResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiTokenPaginationFilters<R extends GeneralApiTokenResourceName> =
|
||||
R extends 'general:token_transfers' ? TokenTransferFilters :
|
||||
R extends 'general:token_inventory' ? TokenInventoryFilters :
|
||||
R extends 'general:tokens' ? TokensFilters :
|
||||
R extends 'general:tokens_bridged' ? TokensBridgedFilters :
|
||||
R extends 'general:token_transfers_all' ? TokenTransferFilters :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiTokenPaginationSorting<R extends GeneralApiTokenResourceName> =
|
||||
R extends 'general:tokens' ? TokensSorting :
|
||||
R extends 'general:tokens_bridged' ? TokensSorting :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,129 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
import type { TxBlobs } from 'types/api/blobs';
|
||||
import type { InternalTransactionsResponse } from 'types/api/internalTransaction';
|
||||
import type { LogsResponseTx } from 'types/api/log';
|
||||
import type { RawTracesResponse } from 'types/api/rawTrace';
|
||||
import type { TokenTransferResponse, TokenTransferFilters } from 'types/api/tokenTransfer';
|
||||
import type {
|
||||
TransactionsResponseValidated,
|
||||
TransactionsResponsePending,
|
||||
Transaction,
|
||||
TransactionsResponseWatchlist,
|
||||
TransactionsResponseWithBlobs,
|
||||
TransactionsStats,
|
||||
} from 'types/api/transaction';
|
||||
import type { TxInterpretationResponse } from 'types/api/txInterpretation';
|
||||
import type { TTxsFilters, TTxsWithBlobsFilters } from 'types/api/txsFilters';
|
||||
import type { TxStateChanges } from 'types/api/txStateChanges';
|
||||
|
||||
export const GENERAL_API_TX_RESOURCES = {
|
||||
txs_stats: {
|
||||
path: '/api/v2/transactions/stats',
|
||||
},
|
||||
txs_validated: {
|
||||
path: '/api/v2/transactions',
|
||||
filterFields: [ 'filter' as const, 'type' as const, 'method' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
txs_pending: {
|
||||
path: '/api/v2/transactions',
|
||||
filterFields: [ 'filter' as const, 'type' as const, 'method' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
txs_with_blobs: {
|
||||
path: '/api/v2/transactions',
|
||||
filterFields: [ 'type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
txs_watchlist: {
|
||||
path: '/api/v2/transactions/watchlist',
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
txs_execution_node: {
|
||||
path: '/api/v2/transactions/execution-node/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
tx: {
|
||||
path: '/api/v2/transactions/:hash',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
tx_internal_txs: {
|
||||
path: '/api/v2/transactions/:hash/internal-transactions',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
tx_logs: {
|
||||
path: '/api/v2/transactions/:hash/logs',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ ],
|
||||
paginated: true,
|
||||
},
|
||||
tx_token_transfers: {
|
||||
path: '/api/v2/transactions/:hash/token-transfers',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [ 'type' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
tx_raw_trace: {
|
||||
path: '/api/v2/transactions/:hash/raw-trace',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
tx_state_changes: {
|
||||
path: '/api/v2/transactions/:hash/state-changes',
|
||||
pathParams: [ 'hash' as const ],
|
||||
filterFields: [],
|
||||
paginated: true,
|
||||
},
|
||||
tx_blobs: {
|
||||
path: '/api/v2/transactions/:hash/blobs',
|
||||
pathParams: [ 'hash' as const ],
|
||||
paginated: true,
|
||||
},
|
||||
tx_interpretation: {
|
||||
path: '/api/v2/transactions/:hash/summary',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
tx_external_transactions: {
|
||||
path: '/api/v2/transactions/:hash/external-transactions',
|
||||
pathParams: [ 'hash' as const ],
|
||||
},
|
||||
internal_txs: {
|
||||
path: '/api/v2/internal-transactions',
|
||||
paginated: true,
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiTxResourceName = `general:${ keyof typeof GENERAL_API_TX_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiTxResourcePayload<R extends GeneralApiTxResourceName> =
|
||||
R extends 'general:txs_stats' ? TransactionsStats :
|
||||
R extends 'general:txs_validated' ? TransactionsResponseValidated :
|
||||
R extends 'general:txs_pending' ? TransactionsResponsePending :
|
||||
R extends 'general:txs_with_blobs' ? TransactionsResponseWithBlobs :
|
||||
R extends 'general:txs_watchlist' ? TransactionsResponseWatchlist :
|
||||
R extends 'general:txs_execution_node' ? TransactionsResponseValidated :
|
||||
R extends 'general:tx_internal_txs' ? InternalTransactionsResponse :
|
||||
R extends 'general:tx' ? Transaction :
|
||||
R extends 'general:tx_logs' ? LogsResponseTx :
|
||||
R extends 'general:tx_token_transfers' ? TokenTransferResponse :
|
||||
R extends 'general:tx_raw_trace' ? RawTracesResponse :
|
||||
R extends 'general:tx_state_changes' ? TxStateChanges :
|
||||
R extends 'general:tx_blobs' ? TxBlobs :
|
||||
R extends 'general:tx_interpretation' ? TxInterpretationResponse :
|
||||
R extends 'general:tx_external_transactions' ? Array<string> :
|
||||
R extends 'general:internal_txs' ? InternalTransactionsResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiTxPaginationFilters<R extends GeneralApiTxResourceName> =
|
||||
R extends 'general:txs_validated' | 'general:txs_pending' ? TTxsFilters :
|
||||
R extends 'general:txs_with_blobs' ? TTxsWithBlobsFilters :
|
||||
R extends 'general:tx_token_transfers' ? TokenTransferFilters :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { ApiResource } from '../../types';
|
||||
import type { BlockCountdownResponse } from 'types/api/block';
|
||||
|
||||
export const GENERAL_API_V1_RESOURCES = {
|
||||
csv_export_txs: {
|
||||
path: '/api/v1/transactions-csv',
|
||||
},
|
||||
csv_export_internal_txs: {
|
||||
path: '/api/v1/internal-transactions-csv',
|
||||
},
|
||||
csv_export_token_transfers: {
|
||||
path: '/api/v1/token-transfers-csv',
|
||||
},
|
||||
csv_export_logs: {
|
||||
path: '/api/v1/logs-csv',
|
||||
},
|
||||
csv_export_epoch_rewards: {
|
||||
path: '/api/v1/celo-election-rewards-csv',
|
||||
},
|
||||
graphql: {
|
||||
path: '/api/v1/graphql',
|
||||
},
|
||||
block_countdown: {
|
||||
path: '/api',
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type GeneralApiV1ResourceName = `general:${ keyof typeof GENERAL_API_V1_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type GeneralApiV1ResourcePayload<R extends GeneralApiV1ResourceName> =
|
||||
R extends 'general:block_countdown' ? BlockCountdownResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { ApiResource } from '../types';
|
||||
import type { AddressMetadataInfo, PublicTagTypesResponse } from 'types/api/addressMetadata';
|
||||
|
||||
export const METADATA_API_RESOURCES = {
|
||||
info: {
|
||||
path: '/api/v1/metadata',
|
||||
},
|
||||
tags_search: {
|
||||
path: '/api/v1/tags:search',
|
||||
},
|
||||
public_tag_types: {
|
||||
path: '/api/v1/public-tag-types',
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type MetadataApiResourceName = `metadata:${ keyof typeof METADATA_API_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type MetadataApiResourcePayload<R extends MetadataApiResourceName> =
|
||||
R extends 'metadata:info' ? AddressMetadataInfo :
|
||||
R extends 'metadata:public_tag_types' ? PublicTagTypesResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,83 @@
|
||||
import type { ApiResource } from '../types';
|
||||
import type * as rewards from '@blockscout/points-types';
|
||||
|
||||
export const REWARDS_API_RESOURCES = {
|
||||
config: {
|
||||
path: '/api/v1/config',
|
||||
},
|
||||
check_ref_code: {
|
||||
path: '/api/v1/auth/code/:code',
|
||||
pathParams: [ 'code' as const ],
|
||||
},
|
||||
nonce: {
|
||||
path: '/api/v1/auth/nonce',
|
||||
},
|
||||
check_user: {
|
||||
path: '/api/v1/auth/user/:address',
|
||||
pathParams: [ 'address' as const ],
|
||||
},
|
||||
login: {
|
||||
path: '/api/v1/auth/login',
|
||||
},
|
||||
logout: {
|
||||
path: '/api/v1/auth/logout',
|
||||
},
|
||||
user_balances: {
|
||||
path: '/api/v1/user/balances',
|
||||
},
|
||||
user_daily_check: {
|
||||
path: '/api/v1/user/daily/check',
|
||||
},
|
||||
user_daily_claim: {
|
||||
path: '/api/v1/user/daily/claim',
|
||||
},
|
||||
user_referrals: {
|
||||
path: '/api/v1/user/referrals',
|
||||
},
|
||||
user_check_activity_pass: {
|
||||
path: '/api/v1/activity/check-pass',
|
||||
filterFields: [ 'address' as const ],
|
||||
},
|
||||
user_activity: {
|
||||
path: '/api/v1/user/activity/rewards',
|
||||
},
|
||||
user_activity_track_tx: {
|
||||
path: '/api/v1/user/activity/track/transaction',
|
||||
},
|
||||
user_activity_track_tx_confirm: {
|
||||
path: '/api/v1/activity/track/transaction/confirm',
|
||||
},
|
||||
user_activity_track_contract: {
|
||||
path: '/api/v1/user/activity/track/contract',
|
||||
},
|
||||
user_activity_track_contract_confirm: {
|
||||
path: '/api/v1/activity/track/contract/confirm',
|
||||
},
|
||||
user_activity_track_usage: {
|
||||
path: '/api/v1/user/activity/track/usage',
|
||||
},
|
||||
instances: {
|
||||
path: '/api/v1/instances',
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type RewardsApiResourceName = `rewards:${ keyof typeof REWARDS_API_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type RewardsApiResourcePayload<R extends RewardsApiResourceName> =
|
||||
R extends 'rewards:config' ? rewards.GetConfigResponse :
|
||||
R extends 'rewards:check_ref_code' ? rewards.AuthCodeResponse :
|
||||
R extends 'rewards:nonce' ? rewards.AuthNonceResponse :
|
||||
R extends 'rewards:check_user' ? rewards.AuthUserResponse :
|
||||
R extends 'rewards:login' ? rewards.AuthLoginResponse :
|
||||
R extends 'rewards:user_balances' ? rewards.GetUserBalancesResponse :
|
||||
R extends 'rewards:user_daily_check' ? rewards.DailyRewardCheckResponse :
|
||||
R extends 'rewards:user_daily_claim' ? rewards.DailyRewardClaimResponse :
|
||||
R extends 'rewards:user_referrals' ? rewards.GetReferralDataResponse :
|
||||
R extends 'rewards:user_check_activity_pass' ? rewards.CheckActivityPassResponse :
|
||||
R extends 'rewards:user_activity' ? rewards.GetActivityRewardsResponse :
|
||||
R extends 'rewards:user_activity_track_tx' ? rewards.PreSubmitTransactionResponse :
|
||||
R extends 'rewards:user_activity_track_contract' ? rewards.PreVerifyContractResponse :
|
||||
R extends 'rewards:instances' ? rewards.GetInstancesResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { ApiResource } from '../types';
|
||||
import type * as stats from '@blockscout/stats-types';
|
||||
|
||||
export const STATS_API_RESOURCES = {
|
||||
counters: {
|
||||
path: '/api/v1/counters',
|
||||
},
|
||||
lines: {
|
||||
path: '/api/v1/lines',
|
||||
},
|
||||
line: {
|
||||
path: '/api/v1/lines/:id',
|
||||
pathParams: [ 'id' as const ],
|
||||
},
|
||||
pages_main: {
|
||||
path: '/api/v1/pages/main',
|
||||
},
|
||||
pages_transactions: {
|
||||
path: '/api/v1/pages/transactions',
|
||||
},
|
||||
pages_contracts: {
|
||||
path: '/api/v1/pages/contracts',
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type StatsApiResourceName = `stats:${ keyof typeof STATS_API_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type StatsApiResourcePayload<R extends StatsApiResourceName> =
|
||||
R extends 'stats:counters' ? stats.Counters :
|
||||
R extends 'stats:lines' ? stats.LineCharts :
|
||||
R extends 'stats:line' ? stats.LineChart :
|
||||
R extends 'stats:pages_main' ? stats.MainPageStats :
|
||||
R extends 'stats:pages_transactions' ? stats.TransactionsPageStats :
|
||||
R extends 'stats:pages_contracts' ? stats.ContractsPageStats :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,3 @@
|
||||
import type { ApiResource } from '../types';
|
||||
|
||||
export type IsPaginated<R extends ApiResource> = R extends { paginated: true } ? true : false;
|
||||
@@ -0,0 +1,16 @@
|
||||
import type { ApiResource } from '../types';
|
||||
import type * as visualizer from '@blockscout/visualizer-types';
|
||||
|
||||
export const VISUALIZE_API_RESOURCES = {
|
||||
solidity_contract: {
|
||||
path: '/api/v1/solidity\\:visualize-contracts',
|
||||
},
|
||||
} satisfies Record<string, ApiResource>;
|
||||
|
||||
export type VisualizeApiResourceName = `visualize:${ keyof typeof VISUALIZE_API_RESOURCES }`;
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
export type VisualizeApiResourcePayload<R extends VisualizeApiResourceName> =
|
||||
R extends 'visualize:solidity_contract' ? visualizer.VisualizeResponse :
|
||||
never;
|
||||
/* eslint-enable @stylistic/indent */
|
||||
@@ -0,0 +1,9 @@
|
||||
export type ApiName = 'general' | 'admin' | 'bens' | 'contractInfo' | 'metadata' | 'rewards' | 'stats' | 'visualize';
|
||||
|
||||
export interface ApiResource {
|
||||
path: string;
|
||||
pathParams?: Array<string>;
|
||||
filterFields?: Array<string>;
|
||||
paginated?: boolean;
|
||||
headers?: RequestInit['headers'];
|
||||
}
|
||||
@@ -13,8 +13,8 @@ import type { Params as FetchParams } from 'lib/hooks/useFetch';
|
||||
import useFetch from 'lib/hooks/useFetch';
|
||||
|
||||
import buildUrl from './buildUrl';
|
||||
import { RESOURCES } from './resources';
|
||||
import type { ApiResource, ResourceName, ResourcePathParams } from './resources';
|
||||
import getResourceParams from './getResourceParams';
|
||||
import type { ResourceName, ResourcePathParams } from './resources';
|
||||
|
||||
export interface Params<R extends ResourceName> {
|
||||
pathParams?: ResourcePathParams<R>;
|
||||
@@ -26,7 +26,7 @@ export interface Params<R extends ResourceName> {
|
||||
export default function useApiFetch() {
|
||||
const fetch = useFetch();
|
||||
const queryClient = useQueryClient();
|
||||
const { token: csrfToken } = queryClient.getQueryData<CsrfData>(getResourceKey('csrf')) || {};
|
||||
const { token: csrfToken } = queryClient.getQueryData<CsrfData>(getResourceKey('general:csrf')) || {};
|
||||
|
||||
return React.useCallback(<R extends ResourceName, SuccessType = unknown, ErrorType = unknown>(
|
||||
resourceName: R,
|
||||
@@ -34,12 +34,12 @@ export default function useApiFetch() {
|
||||
) => {
|
||||
const apiToken = cookies.get(cookies.NAMES.API_TOKEN);
|
||||
|
||||
const resource: ApiResource = RESOURCES[resourceName];
|
||||
const { api, apiName, resource } = getResourceParams(resourceName);
|
||||
const url = buildUrl(resourceName, pathParams, queryParams);
|
||||
const withBody = isBodyAllowed(fetchParams?.method);
|
||||
const headers = pickBy({
|
||||
'x-endpoint': resource.endpoint && isNeedProxy() ? resource.endpoint : undefined,
|
||||
Authorization: resource.endpoint && resource.needAuth ? apiToken : undefined,
|
||||
'x-endpoint': api.endpoint && apiName !== 'general' && isNeedProxy() ? api.endpoint : undefined,
|
||||
Authorization: [ 'admin', 'contractInfo' ].includes(apiName) ? apiToken : undefined,
|
||||
'x-csrf-token': withBody && csrfToken ? csrfToken : undefined,
|
||||
...resource.headers,
|
||||
...fetchParams?.headers,
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
import type { InfiniteData, QueryKey, UseInfiniteQueryResult, UseInfiniteQueryOptions } from '@tanstack/react-query';
|
||||
import { useInfiniteQuery } from '@tanstack/react-query';
|
||||
|
||||
import type { PaginatedResources, ResourceError, ResourcePayload } from 'lib/api/resources';
|
||||
import useApiFetch from 'lib/api/useApiFetch';
|
||||
import type { Params as ApiFetchParams } from 'lib/api/useApiFetch';
|
||||
|
||||
import type { PaginatedResourceName, ResourceError, ResourcePayload } from './resources';
|
||||
import useApiFetch from './useApiFetch';
|
||||
import type { Params as ApiFetchParams } from './useApiFetch';
|
||||
import { getResourceKey } from './useApiQuery';
|
||||
|
||||
type TQueryData<R extends PaginatedResources> = ResourcePayload<R>;
|
||||
type TQueryData<R extends PaginatedResourceName> = ResourcePayload<R>;
|
||||
type TError = ResourceError<unknown>;
|
||||
type TPageParam<R extends PaginatedResources> = ApiFetchParams<R>['queryParams'] | null;
|
||||
type TPageParam<R extends PaginatedResourceName> = ApiFetchParams<R>['queryParams'] | null;
|
||||
|
||||
export interface Params<R extends PaginatedResources> {
|
||||
export interface Params<R extends PaginatedResourceName> {
|
||||
resourceName: R;
|
||||
// eslint-disable-next-line max-len
|
||||
queryOptions?: Omit<UseInfiniteQueryOptions<TQueryData<R>, TError, InfiniteData<TQueryData<R>>, TQueryData<R>, QueryKey, TPageParam<R>>, 'queryKey' | 'queryFn' | 'getNextPageParam' | 'initialPageParam'>;
|
||||
pathParams?: ApiFetchParams<R>['pathParams'];
|
||||
}
|
||||
|
||||
type ReturnType<Resource extends PaginatedResources> = UseInfiniteQueryResult<InfiniteData<ResourcePayload<Resource>>, ResourceError<unknown>>;
|
||||
type ReturnType<Resource extends PaginatedResourceName> = UseInfiniteQueryResult<InfiniteData<ResourcePayload<Resource>>, ResourceError<unknown>>;
|
||||
|
||||
export default function useApiInfiniteQuery<R extends PaginatedResources>({
|
||||
export default function useApiInfiniteQuery<R extends PaginatedResourceName>({
|
||||
resourceName,
|
||||
queryOptions,
|
||||
pathParams,
|
||||
|
||||
@@ -4,6 +4,8 @@ import React from 'react';
|
||||
import getErrorObjPayload from 'lib/errors/getErrorObjPayload';
|
||||
import getErrorObjStatusCode from 'lib/errors/getErrorObjStatusCode';
|
||||
|
||||
import type { ResourceName } from './resources';
|
||||
|
||||
export const retry = (failureCount: number, error: unknown) => {
|
||||
const errorPayload = getErrorObjPayload<{ status: number }>(error);
|
||||
const status = errorPayload?.status || getErrorObjStatusCode(error);
|
||||
@@ -28,13 +30,14 @@ export default function useQueryClientConfig() {
|
||||
return false;
|
||||
}
|
||||
|
||||
const EXTERNAL_API_RESOURCES = [
|
||||
const EXTERNAL_API_RESOURCES: Array<ResourceName | 'safe_transaction_api' | 'gas_hawk_saving_potential'> = [
|
||||
'general:contract_solidity_scan_report',
|
||||
'general:address_xstar_score',
|
||||
'general:noves_transaction',
|
||||
'general:noves_address_history',
|
||||
'general:noves_describe_txs',
|
||||
// these resources are not proxied by the backend
|
||||
'safe_transaction_api',
|
||||
'contract_solidity_scan_report',
|
||||
'address_xstar_score',
|
||||
'noves_transaction',
|
||||
'noves_address_history',
|
||||
'noves_describe_txs',
|
||||
'gas_hawk_saving_potential',
|
||||
];
|
||||
const isExternalApiResource = EXTERNAL_API_RESOURCES.some((resource) => query.queryKey[0] === resource);
|
||||
|
||||
+14
-14
@@ -77,8 +77,8 @@ function getMessageToSign(address: string, nonce: string, isLogin?: boolean, ref
|
||||
const referralText = refCode ? ` Referral code: ${ refCode }` : '';
|
||||
const body = isLogin ? signInText : signUpText + referralText;
|
||||
|
||||
const urlObj = window.location.hostname === 'localhost' && feature.isEnabled ?
|
||||
new URL(feature.api.endpoint) :
|
||||
const urlObj = window.location.hostname === 'localhost' && config.apis.rewards ?
|
||||
new URL(config.apis.rewards.endpoint) :
|
||||
window.location;
|
||||
|
||||
return [
|
||||
@@ -146,18 +146,18 @@ export function RewardsContextProvider({ children }: Props) {
|
||||
{ headers: { Authorization: `Bearer ${ apiToken }` } },
|
||||
], [ apiToken ]);
|
||||
|
||||
const balancesQuery = useApiQuery('rewards_user_balances', { queryOptions, fetchParams });
|
||||
const dailyRewardQuery = useApiQuery('rewards_user_daily_check', { queryOptions, fetchParams });
|
||||
const referralsQuery = useApiQuery('rewards_user_referrals', { queryOptions, fetchParams });
|
||||
const rewardsConfigQuery = useApiQuery('rewards_config', { queryOptions: { enabled: feature.isEnabled } });
|
||||
const checkUserQuery = useApiQuery('rewards_check_user', { queryOptions: { enabled: feature.isEnabled }, pathParams: { address } });
|
||||
const balancesQuery = useApiQuery('rewards:user_balances', { queryOptions, fetchParams });
|
||||
const dailyRewardQuery = useApiQuery('rewards:user_daily_check', { queryOptions, fetchParams });
|
||||
const referralsQuery = useApiQuery('rewards:user_referrals', { queryOptions, fetchParams });
|
||||
const rewardsConfigQuery = useApiQuery('rewards:config', { queryOptions: { enabled: feature.isEnabled } });
|
||||
const checkUserQuery = useApiQuery('rewards:check_user', { queryOptions: { enabled: feature.isEnabled }, pathParams: { address } });
|
||||
|
||||
// Reset queries when the API token is removed
|
||||
useEffect(() => {
|
||||
if (isInitialized && !apiToken) {
|
||||
queryClient.resetQueries({ queryKey: getResourceKey('rewards_user_balances'), exact: true });
|
||||
queryClient.resetQueries({ queryKey: getResourceKey('rewards_user_daily_check'), exact: true });
|
||||
queryClient.resetQueries({ queryKey: getResourceKey('rewards_user_referrals'), exact: true });
|
||||
queryClient.resetQueries({ queryKey: getResourceKey('rewards:user_balances'), exact: true });
|
||||
queryClient.resetQueries({ queryKey: getResourceKey('rewards:user_daily_check'), exact: true });
|
||||
queryClient.resetQueries({ queryKey: getResourceKey('rewards:user_referrals'), exact: true });
|
||||
}
|
||||
}, [ isInitialized, apiToken, queryClient ]);
|
||||
|
||||
@@ -203,9 +203,9 @@ export function RewardsContextProvider({ children }: Props) {
|
||||
throw new Error();
|
||||
}
|
||||
const [ nonceResponse, checkCodeResponse ] = await Promise.all([
|
||||
apiFetch('rewards_nonce') as Promise<rewards.AuthNonceResponse>,
|
||||
apiFetch('rewards:nonce') as Promise<rewards.AuthNonceResponse>,
|
||||
refCode ?
|
||||
apiFetch('rewards_check_ref_code', { pathParams: { code: refCode } }) as Promise<rewards.AuthCodeResponse> :
|
||||
apiFetch('rewards:check_ref_code', { pathParams: { code: refCode } }) as Promise<rewards.AuthCodeResponse> :
|
||||
Promise.resolve({ valid: true, reward: undefined }),
|
||||
]);
|
||||
if (!checkCodeResponse.valid) {
|
||||
@@ -217,7 +217,7 @@ export function RewardsContextProvider({ children }: Props) {
|
||||
await switchChainAsync({ chainId: Number(config.chain.id) });
|
||||
const message = getMessageToSign(address, nonceResponse.nonce, checkUserQuery.data?.exists, refCode);
|
||||
const signature = await signMessageAsync({ message });
|
||||
const loginResponse = await apiFetch('rewards_login', {
|
||||
const loginResponse = await apiFetch('rewards:login', {
|
||||
fetchParams: {
|
||||
method: 'POST',
|
||||
body: {
|
||||
@@ -241,7 +241,7 @@ export function RewardsContextProvider({ children }: Props) {
|
||||
// Claim daily reward
|
||||
const claim = useCallback(async() => {
|
||||
try {
|
||||
await apiFetch('rewards_user_daily_claim', {
|
||||
await apiFetch('rewards:user_daily_claim', {
|
||||
fetchParams: {
|
||||
method: 'POST',
|
||||
...fetchParams,
|
||||
|
||||
@@ -10,10 +10,10 @@ export default function useGetCsrfToken() {
|
||||
const nodeApiFetch = useFetch();
|
||||
|
||||
return useQuery({
|
||||
queryKey: getResourceKey('csrf'),
|
||||
queryKey: getResourceKey('general:csrf'),
|
||||
queryFn: async() => {
|
||||
if (!isNeedProxy()) {
|
||||
const url = buildUrl('csrf');
|
||||
const url = buildUrl('general:csrf');
|
||||
const apiResponse = await fetch(url, { credentials: 'include' });
|
||||
const csrfFromHeader = apiResponse.headers.get('x-bs-account-csrf');
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ const feature = config.features.rewards;
|
||||
const LAST_EXPLORE_TIME_KEY = 'rewards_activity_last_explore_time';
|
||||
|
||||
type RewardsActivityEndpoint =
|
||||
| 'rewards_user_activity_track_tx'
|
||||
| 'rewards_user_activity_track_tx_confirm'
|
||||
| 'rewards_user_activity_track_contract'
|
||||
| 'rewards_user_activity_track_contract_confirm'
|
||||
| 'rewards_user_activity_track_usage';
|
||||
| 'rewards:user_activity_track_tx'
|
||||
| 'rewards:user_activity_track_tx_confirm'
|
||||
| 'rewards:user_activity_track_contract'
|
||||
| 'rewards:user_activity_track_contract_confirm'
|
||||
| 'rewards:user_activity_track_usage';
|
||||
|
||||
export default function useRewardsActivity() {
|
||||
const { apiToken } = useRewardsContext();
|
||||
@@ -25,7 +25,7 @@ export default function useRewardsActivity() {
|
||||
const lastExploreTime = useRef<number>(0);
|
||||
|
||||
const profileQuery = useProfileQuery();
|
||||
const checkActivityPassQuery = useApiQuery('rewards_user_check_activity_pass', {
|
||||
const checkActivityPassQuery = useApiQuery('rewards:user_check_activity_pass', {
|
||||
queryOptions: {
|
||||
enabled: feature.isEnabled && Boolean(apiToken) && Boolean(profileQuery.data?.address_hash),
|
||||
},
|
||||
@@ -61,7 +61,7 @@ export default function useRewardsActivity() {
|
||||
|
||||
const trackTransaction = useCallback(async(from: string, to: string) => {
|
||||
return (
|
||||
await makeRequest('rewards_user_activity_track_tx', {
|
||||
await makeRequest('rewards:user_activity_track_tx', {
|
||||
from_address: from,
|
||||
to_address: to,
|
||||
chain_id: config.chain.id ?? '',
|
||||
@@ -70,12 +70,12 @@ export default function useRewardsActivity() {
|
||||
}, [ makeRequest ]);
|
||||
|
||||
const trackTransactionConfirm = useCallback((hash: string, token: string) =>
|
||||
makeRequest('rewards_user_activity_track_tx_confirm', { tx_hash: hash, token }),
|
||||
makeRequest('rewards:user_activity_track_tx_confirm', { tx_hash: hash, token }),
|
||||
[ makeRequest ],
|
||||
);
|
||||
|
||||
const trackContract = useCallback(async(address: string) =>
|
||||
makeRequest('rewards_user_activity_track_contract', {
|
||||
makeRequest('rewards:user_activity_track_contract', {
|
||||
address,
|
||||
chain_id: config.chain.id ?? '',
|
||||
}),
|
||||
@@ -99,7 +99,7 @@ export default function useRewardsActivity() {
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return makeRequest('rewards_user_activity_track_usage', {
|
||||
return makeRequest('rewards:user_activity_track_usage', {
|
||||
action,
|
||||
chain_id: config.chain.id ?? '',
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ interface Params {
|
||||
hash: string;
|
||||
}
|
||||
|
||||
const RESOURCE_NAME = 'contract_solidity_scan_report';
|
||||
const RESOURCE_NAME = 'general:contract_solidity_scan_report';
|
||||
const ERROR_NAME = 'Invalid response schema';
|
||||
|
||||
export default function useFetchReport({ hash }: Params) {
|
||||
|
||||
@@ -10,7 +10,7 @@ export default function useAccountWithDomain(isEnabled: boolean) {
|
||||
|
||||
const isQueryEnabled = config.features.nameService.isEnabled && Boolean(address) && Boolean(isEnabled);
|
||||
|
||||
const domainQuery = useApiQuery('address_domain', {
|
||||
const domainQuery = useApiQuery('bens:address_domain', {
|
||||
pathParams: {
|
||||
chainId: config.chain.id,
|
||||
address,
|
||||
|
||||
@@ -20,7 +20,7 @@ const wagmi = (() => {
|
||||
[currentChain.id]: fallback(
|
||||
config.chain.rpcUrls
|
||||
.map((url) => http(url))
|
||||
.concat(http(`${ config.api.endpoint }/api/eth-rpc`)),
|
||||
.concat(http(`${ config.apis.general.endpoint }/api/eth-rpc`)),
|
||||
),
|
||||
...(parentChain ? { [parentChain.id]: http(parentChain.rpcUrls.default.http[0]) } : {}),
|
||||
},
|
||||
|
||||
@@ -9,7 +9,7 @@ interface Params {
|
||||
hash: string;
|
||||
}
|
||||
|
||||
const RESOURCE_NAME = 'address_xstar_score';
|
||||
const RESOURCE_NAME = 'general:address_xstar_score';
|
||||
const ERROR_NAME = 'Invalid response schema';
|
||||
|
||||
export default function useFetchXStarScore({ hash }: Params) {
|
||||
|
||||
@@ -40,15 +40,8 @@ export function app(): CspDev.DirectiveDescriptor {
|
||||
config.app.isDev ? 'ws://localhost:3000/_next/webpack-hmr' : '',
|
||||
|
||||
// APIs
|
||||
config.api.endpoint,
|
||||
config.api.socket,
|
||||
getFeaturePayload(config.features.stats)?.api.endpoint,
|
||||
getFeaturePayload(config.features.sol2uml)?.api.endpoint,
|
||||
getFeaturePayload(config.features.verifiedTokens)?.api.endpoint,
|
||||
getFeaturePayload(config.features.addressVerification)?.api.endpoint,
|
||||
getFeaturePayload(config.features.nameService)?.api.endpoint,
|
||||
getFeaturePayload(config.features.addressMetadata)?.api.endpoint,
|
||||
getFeaturePayload(config.features.rewards)?.api.endpoint,
|
||||
...Object.values(config.apis).filter(Boolean).map((api) => api.endpoint),
|
||||
config.apis.general.socketEndpoint,
|
||||
|
||||
// chain RPC server
|
||||
...config.chain.rpcUrls,
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { compile } from 'path-to-regexp';
|
||||
|
||||
import config from 'configs/app';
|
||||
import { RESOURCES } from 'lib/api/resources';
|
||||
import type { ApiResource, ResourceName } from 'lib/api/resources';
|
||||
import getResourceParams from 'lib/api/getResourceParams';
|
||||
import type { ResourceName } from 'lib/api/resources';
|
||||
|
||||
export default function buildUrl(
|
||||
_resource: ApiResource | ResourceName,
|
||||
_resource: ResourceName,
|
||||
pathParams?: Record<string, string | undefined>,
|
||||
queryParams?: Record<string, string | number | undefined>,
|
||||
) {
|
||||
const resource: ApiResource = typeof _resource === 'string' ? RESOURCES[_resource] : _resource;
|
||||
const baseUrl = resource.endpoint || config.api.endpoint;
|
||||
const basePath = resource.basePath !== undefined ? resource.basePath : config.api.basePath;
|
||||
const { resource, api } = getResourceParams(_resource);
|
||||
const baseUrl = api.endpoint;
|
||||
const basePath = api.basePath ?? '';
|
||||
const path = basePath + resource.path;
|
||||
const url = new URL(compile(path)(pathParams), baseUrl);
|
||||
|
||||
|
||||
@@ -3,21 +3,14 @@ import fetch, { AbortError } from 'node-fetch';
|
||||
import buildUrl from 'nextjs/utils/buildUrl';
|
||||
import { httpLogger } from 'nextjs/utils/logger';
|
||||
|
||||
import { RESOURCES } from 'lib/api/resources';
|
||||
import type { ResourceName, ResourcePathParams, ResourcePayload } from 'lib/api/resources';
|
||||
import metrics from 'lib/monitoring/metrics';
|
||||
import { SECOND } from 'toolkit/utils/consts';
|
||||
|
||||
type Params<R extends ResourceName> = (
|
||||
{
|
||||
resource: R;
|
||||
pathParams?: ResourcePathParams<R>;
|
||||
queryParams?: Record<string, string | number | undefined>;
|
||||
} | {
|
||||
url: string;
|
||||
route: string;
|
||||
}
|
||||
) & {
|
||||
type Params<R extends ResourceName> = {
|
||||
resource: R;
|
||||
pathParams?: ResourcePathParams<R>;
|
||||
queryParams?: Record<string, string | number | undefined>;
|
||||
timeout?: number;
|
||||
};
|
||||
|
||||
@@ -27,15 +20,14 @@ export default async function fetchApi<R extends ResourceName = never, S = Resou
|
||||
controller.abort();
|
||||
}, params.timeout || SECOND);
|
||||
|
||||
const url = 'url' in params ? params.url : buildUrl(params.resource, params.pathParams, params.queryParams);
|
||||
const route = 'route' in params ? params.route : RESOURCES[params.resource]['path'];
|
||||
const url = buildUrl(params.resource, params.pathParams, params.queryParams);
|
||||
|
||||
const end = metrics?.apiRequestDuration.startTimer();
|
||||
|
||||
try {
|
||||
const response = await fetch(url, { signal: controller.signal });
|
||||
|
||||
const duration = end?.({ route, code: response.status });
|
||||
const duration = end?.({ route: params.resource, code: response.status });
|
||||
if (response.status === 200) {
|
||||
httpLogger.logger.info({ message: 'API fetch', url, code: response.status, duration });
|
||||
} else {
|
||||
@@ -45,7 +37,7 @@ export default async function fetchApi<R extends ResourceName = never, S = Resou
|
||||
return await response.json() as Promise<S>;
|
||||
} catch (error) {
|
||||
const code = error instanceof AbortError ? 504 : 500;
|
||||
const duration = end?.({ route, code });
|
||||
const duration = end?.({ route: params.resource, code });
|
||||
httpLogger.logger.error({ message: 'API fetch', url, code, duration });
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
<QueryClientProvider client={ queryClient }>
|
||||
<GrowthBookProvider growthbook={ growthBook }>
|
||||
<ScrollDirectionProvider>
|
||||
<SocketProvider url={ `${ config.api.socket }${ config.api.basePath }/socket/v2` }>
|
||||
<SocketProvider url={ `${ config.apis.general.socketEndpoint }${ config.apis.general.basePath ?? '' }/socket/v2` }>
|
||||
<RewardsContextProvider>
|
||||
<MarketplaceContextProvider>
|
||||
<SettingsContextProvider>
|
||||
|
||||
@@ -32,7 +32,7 @@ export const getServerSideProps: GetServerSideProps<Props<typeof pathname>> = as
|
||||
|
||||
if (botInfo?.type === 'social_preview') {
|
||||
const addressData = await fetchApi({
|
||||
resource: 'address',
|
||||
resource: 'general:address',
|
||||
pathParams: { hash: getQueryParamString(ctx.query.hash) },
|
||||
timeout: 1_000,
|
||||
});
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import { httpLogger } from 'nextjs/utils/logger';
|
||||
export default async function csrfHandler(_req: NextApiRequest, res: NextApiResponse) {
|
||||
httpLogger(_req, res);
|
||||
|
||||
const url = buildUrl('csrf');
|
||||
const url = buildUrl('general:csrf');
|
||||
const response = await fetchFactory(_req)(url);
|
||||
|
||||
if (response.status === 200) {
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ const handler = async(nextReq: NextApiRequest, nextRes: NextApiResponse) => {
|
||||
|
||||
const url = new URL(
|
||||
nextReq.url.replace(/^\/node-api\/proxy/, ''),
|
||||
nextReq.headers['x-endpoint']?.toString() || appConfig.api.endpoint,
|
||||
nextReq.headers['x-endpoint']?.toString() || appConfig.apis.general.endpoint,
|
||||
);
|
||||
const apiRes = await fetchFactory(nextReq)(
|
||||
url.toString(),
|
||||
|
||||
+16
-9
@@ -1,5 +1,6 @@
|
||||
import type { GetServerSideProps } from 'next';
|
||||
import dynamic from 'next/dynamic';
|
||||
import fetch from 'node-fetch';
|
||||
import React from 'react';
|
||||
|
||||
import type { NextPageWithLayout } from 'nextjs/types';
|
||||
@@ -49,19 +50,25 @@ export const getServerSideProps: GetServerSideProps<Props<typeof pathname>> = as
|
||||
|
||||
const appData = await(async() => {
|
||||
if ('configUrl' in feature) {
|
||||
const appList = await fetchApi<never, Array<MarketplaceAppOverview>>({
|
||||
url: config.app.baseUrl + feature.configUrl,
|
||||
route: '/marketplace_config',
|
||||
timeout: 1_000,
|
||||
});
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => {
|
||||
controller.abort();
|
||||
}, 1_000);
|
||||
|
||||
if (appList && Array.isArray(appList)) {
|
||||
return appList.find(app => app.id === getQueryParamString(ctx.query.id));
|
||||
try {
|
||||
const response = await fetch(feature.configUrl, { signal: controller.signal });
|
||||
const appList = await response.json() as Array<MarketplaceAppOverview>;
|
||||
clearTimeout(timeout);
|
||||
|
||||
if (appList && Array.isArray(appList)) {
|
||||
return appList.find(app => app.id === getQueryParamString(ctx.query.id));
|
||||
}
|
||||
} catch (error) {} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
} else {
|
||||
return await fetchApi({
|
||||
resource: 'marketplace_dapp',
|
||||
resource: 'admin:marketplace_dapp',
|
||||
pathParams: { dappId: getQueryParamString(ctx.query.id), chainId: config.chain.id },
|
||||
timeout: 1_000,
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ export const getServerSideProps: GetServerSideProps<Props<typeof pathname>> = as
|
||||
(config.meta.og.enhancedDataEnabled && detectBotRequest(ctx.req)?.type === 'social_preview')
|
||||
) {
|
||||
const chartData = await fetchApi({
|
||||
resource: 'stats_line',
|
||||
resource: 'stats:line',
|
||||
pathParams: { id: getQueryParamString(ctx.query.id) },
|
||||
queryParams: { from: dayjs().format('YYYY-MM-DD'), to: dayjs().format('YYYY-MM-DD') },
|
||||
timeout: 1000,
|
||||
|
||||
@@ -33,7 +33,7 @@ export const getServerSideProps: GetServerSideProps<Props<typeof pathname>> = as
|
||||
(config.meta.og.enhancedDataEnabled && detectBotRequest(ctx.req)?.type === 'social_preview')
|
||||
) {
|
||||
const tokenData = await fetchApi({
|
||||
resource: 'token',
|
||||
resource: 'general:token',
|
||||
pathParams: { hash: getQueryParamString(ctx.query.hash) },
|
||||
timeout: 500,
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ export const getServerSideProps: GetServerSideProps<Props<typeof pathname>> = as
|
||||
|
||||
if (botInfo?.type === 'social_preview') {
|
||||
const tokenData = await fetchApi({
|
||||
resource: 'token',
|
||||
resource: 'general:token',
|
||||
pathParams: { hash: getQueryParamString(ctx.query.hash) },
|
||||
timeout: 1_000,
|
||||
});
|
||||
|
||||
@@ -85,10 +85,10 @@ export const ENVS_MAP: Record<string, Array<[string, string]>> = {
|
||||
[ 'NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED', 'true' ],
|
||||
],
|
||||
nameService: [
|
||||
[ 'NEXT_PUBLIC_NAME_SERVICE_API_HOST', 'https://localhost:3101' ],
|
||||
[ 'NEXT_PUBLIC_NAME_SERVICE_API_HOST', 'https://localhost:3008' ],
|
||||
],
|
||||
rewardsService: [
|
||||
[ 'NEXT_PUBLIC_REWARDS_SERVICE_API_HOST', 'http://localhost:3003' ],
|
||||
[ 'NEXT_PUBLIC_REWARDS_SERVICE_API_HOST', 'http://localhost:3009' ],
|
||||
],
|
||||
addressBech32Format: [
|
||||
[ 'NEXT_PUBLIC_ADDRESS_FORMAT', '["bech32","base16"]' ],
|
||||
|
||||
+16
-16
@@ -66,26 +66,26 @@ export const TOKEN_HOLDER_ERC_1155: TokenHolder = {
|
||||
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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general:token_instance_holders'>(TOKEN_HOLDER_ERC_20, 10, { next_page_params: pagination });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -140,26 +140,26 @@ export const TOKEN_TRANSFER_ERC_404: TokenTransfer = {
|
||||
export const getTokenTransfersStub = (type?: TokenType, pagination: TokenTransferPagination | null = null): TokenTransferResponse => {
|
||||
switch (type) {
|
||||
case 'ERC-721':
|
||||
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_721, 50, { next_page_params: pagination });
|
||||
return generateListStub<'general:token_transfers'>(TOKEN_TRANSFER_ERC_721, 50, { next_page_params: pagination });
|
||||
case 'ERC-1155':
|
||||
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_1155, 50, { next_page_params: pagination });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general:token_transfers'>(TOKEN_TRANSFER_ERC_404, 50, { next_page_params: pagination });
|
||||
default:
|
||||
return generateListStub<'token_transfers'>(TOKEN_TRANSFER_ERC_20, 50, { next_page_params: pagination });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general: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 });
|
||||
return generateListStub<'general:token_instance_transfers'>(TOKEN_TRANSFER_ERC_20, 10, { next_page_params: pagination });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
import type { ArrayElement } from 'types/utils';
|
||||
|
||||
import type { PaginatedResources, PaginatedResponse, PaginatedResponseItems } from 'lib/api/resources';
|
||||
import type { PaginatedResourceName, PaginatedResourceResponse, PaginatedResourceResponseItems } from 'lib/api/resources';
|
||||
|
||||
export function generateListStub<Resource extends PaginatedResources>(
|
||||
stub: ArrayElement<PaginatedResponseItems<Resource>>,
|
||||
export function generateListStub<Resource extends PaginatedResourceName>(
|
||||
stub: ArrayElement<PaginatedResourceResponseItems<Resource>>,
|
||||
num = 50,
|
||||
rest: Omit<PaginatedResponse<Resource>, 'items'>,
|
||||
rest: Omit<PaginatedResourceResponse<Resource>, 'items'>,
|
||||
) {
|
||||
return {
|
||||
items: Array(num).fill(stub),
|
||||
|
||||
@@ -37,11 +37,11 @@ const AddressAccountHistory = ({ shouldRender = true, isQueryEnabled = true }: P
|
||||
const [ filterValue, setFilterValue ] = React.useState<NovesHistoryFilterValue>(getFilterValue(router.query.filter));
|
||||
|
||||
const { data, isError, pagination, isPlaceholderData } = useQueryWithPages({
|
||||
resourceName: 'noves_address_history',
|
||||
resourceName: 'general:noves_address_history',
|
||||
pathParams: { address: currentAddress },
|
||||
options: {
|
||||
enabled: isQueryEnabled,
|
||||
placeholderData: generateListStub<'noves_address_history'>(NOVES_TRANSLATE, 10, { hasNextPage: false, pageNumber: 1, pageSize: 10 }),
|
||||
placeholderData: generateListStub<'general:noves_address_history'>(NOVES_TRANSLATE, 10, { hasNextPage: false, pageNumber: 1, pageSize: 10 }),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ const AddressBlocksValidated = ({ shouldRender = true, isQueryEnabled = true }:
|
||||
|
||||
const addressHash = String(router.query.hash);
|
||||
const query = useQueryWithPages({
|
||||
resourceName: 'address_blocks_validated',
|
||||
resourceName: 'general:address_blocks_validated',
|
||||
pathParams: { hash: addressHash },
|
||||
options: {
|
||||
enabled: isQueryEnabled,
|
||||
placeholderData: generateListStub<'address_blocks_validated'>(
|
||||
placeholderData: generateListStub<'general:address_blocks_validated'>(
|
||||
BLOCK,
|
||||
50,
|
||||
{
|
||||
@@ -66,7 +66,7 @@ const AddressBlocksValidated = ({ shouldRender = true, isQueryEnabled = true }:
|
||||
setSocketAlert('');
|
||||
|
||||
queryClient.setQueryData(
|
||||
getResourceKey('address_blocks_validated', { pathParams: { hash: addressHash } }),
|
||||
getResourceKey('general:address_blocks_validated', { pathParams: { hash: addressHash } }),
|
||||
(prevData: AddressBlocksValidatedResponse | undefined) => {
|
||||
if (!prevData) {
|
||||
return;
|
||||
|
||||
@@ -13,8 +13,8 @@ const hooksConfig = {
|
||||
};
|
||||
|
||||
test('base view +@dark-mode', async({ render, page, mockApiResponse }) => {
|
||||
await mockApiResponse('address_coin_balance', balanceHistoryMock.baseResponse, { pathParams: { hash: addressHash } });
|
||||
await mockApiResponse('address_coin_balance_chart', balanceHistoryMock.chartResponse, { pathParams: { hash: addressHash } });
|
||||
await mockApiResponse('general:address_coin_balance', balanceHistoryMock.baseResponse, { pathParams: { hash: addressHash } });
|
||||
await mockApiResponse('general:address_coin_balance_chart', balanceHistoryMock.chartResponse, { pathParams: { hash: addressHash } });
|
||||
const component = await render(<AddressCoinBalance/>, { hooksConfig });
|
||||
await page.waitForFunction(() => {
|
||||
return document.querySelector('path[data-name="chart-Balances-small"]')?.getAttribute('opacity') === '1';
|
||||
@@ -28,8 +28,8 @@ test.describe('mobile', () => {
|
||||
test.use({ viewport: devices['iPhone 13 Pro'].viewport });
|
||||
|
||||
test('base view', async({ render, page, mockApiResponse }) => {
|
||||
await mockApiResponse('address_coin_balance', balanceHistoryMock.baseResponse, { pathParams: { hash: addressHash } });
|
||||
await mockApiResponse('address_coin_balance_chart', balanceHistoryMock.chartResponse, { pathParams: { hash: addressHash } });
|
||||
await mockApiResponse('general:address_coin_balance', balanceHistoryMock.baseResponse, { pathParams: { hash: addressHash } });
|
||||
await mockApiResponse('general:address_coin_balance_chart', balanceHistoryMock.chartResponse, { pathParams: { hash: addressHash } });
|
||||
const component = await render(<AddressCoinBalance/>, { hooksConfig });
|
||||
await page.waitForFunction(() => {
|
||||
return document.querySelector('path[data-name="chart-Balances-small"]')?.getAttribute('opacity') === '1';
|
||||
|
||||
@@ -33,12 +33,12 @@ const AddressCoinBalance = ({ shouldRender = true, isQueryEnabled = true }: Prop
|
||||
|
||||
const addressHash = getQueryParamString(router.query.hash);
|
||||
const coinBalanceQuery = useQueryWithPages({
|
||||
resourceName: 'address_coin_balance',
|
||||
resourceName: 'general:address_coin_balance',
|
||||
pathParams: { hash: addressHash },
|
||||
scrollRef,
|
||||
options: {
|
||||
enabled: isQueryEnabled,
|
||||
placeholderData: generateListStub<'address_coin_balance'>(
|
||||
placeholderData: generateListStub<'general:address_coin_balance'>(
|
||||
ADDRESS_COIN_BALANCE,
|
||||
50,
|
||||
{
|
||||
@@ -59,7 +59,7 @@ const AddressCoinBalance = ({ shouldRender = true, isQueryEnabled = true }: Prop
|
||||
setSocketAlert(false);
|
||||
|
||||
queryClient.setQueryData(
|
||||
getResourceKey('address_coin_balance', { pathParams: { hash: addressHash } }),
|
||||
getResourceKey('general:address_coin_balance', { pathParams: { hash: addressHash } }),
|
||||
(prevData: AddressCoinBalanceHistoryResponse | undefined) => {
|
||||
if (!prevData) {
|
||||
return;
|
||||
|
||||
@@ -12,9 +12,9 @@ import AddressContract from './AddressContract.pwstory';
|
||||
const hash = addressMock.contract.hash;
|
||||
|
||||
test.beforeEach(async({ mockApiResponse }) => {
|
||||
await mockApiResponse('address', addressMock.contract, { pathParams: { hash } });
|
||||
await mockApiResponse('general:address', addressMock.contract, { pathParams: { hash } });
|
||||
await mockApiResponse(
|
||||
'contract',
|
||||
'general:contract',
|
||||
{ ...contractInfoMock.verified, abi: [ ...contractMethodsMock.read, ...contractMethodsMock.write ] },
|
||||
{ pathParams: { hash } },
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ import AddressContract from './AddressContract';
|
||||
const AddressContractPwStory = () => {
|
||||
const router = useRouter();
|
||||
const hash = getQueryParamString(router.query.hash);
|
||||
const addressQuery = useApiQuery('address', { pathParams: { hash } });
|
||||
const addressQuery = useApiQuery('general:address', { pathParams: { hash } });
|
||||
const { tabs } = useContractTabs(addressQuery.data, false);
|
||||
return <AddressContract tabs={ tabs } shouldRender={ true } isLoading={ false }/>;
|
||||
};
|
||||
|
||||
@@ -21,8 +21,8 @@ test.describe('mobile', () => {
|
||||
test.use({ viewport: devices['iPhone 13 Pro'].viewport });
|
||||
|
||||
test('contract', async({ render, mockApiResponse, page }) => {
|
||||
await mockApiResponse('address', addressMock.contract, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('address_counters', countersMock.forContract, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address', addressMock.contract, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_counters', countersMock.forContract, { pathParams: { hash: ADDRESS_HASH } });
|
||||
|
||||
const component = await render(<AddressDetails addressQuery={{ data: addressMock.contract } as AddressQuery}/>, { hooksConfig });
|
||||
|
||||
@@ -33,8 +33,8 @@ test.describe('mobile', () => {
|
||||
});
|
||||
|
||||
test('validator', async({ render, page, mockApiResponse }) => {
|
||||
await mockApiResponse('address', addressMock.validator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address', addressMock.validator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
|
||||
const component = await render(<AddressDetails addressQuery={{ data: addressMock.validator } as AddressQuery}/>, { hooksConfig });
|
||||
|
||||
@@ -45,8 +45,8 @@ test.describe('mobile', () => {
|
||||
});
|
||||
|
||||
test('filecoin', async({ render, mockApiResponse, page }) => {
|
||||
await mockApiResponse('address', addressMock.filecoin, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address', addressMock.filecoin, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
|
||||
const component = await render(<AddressDetails addressQuery={{ data: addressMock.filecoin } as AddressQuery}/>, { hooksConfig });
|
||||
|
||||
@@ -58,8 +58,8 @@ test.describe('mobile', () => {
|
||||
});
|
||||
|
||||
test('contract', async({ render, page, mockApiResponse }) => {
|
||||
await mockApiResponse('address', addressMock.contract, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('address_counters', countersMock.forContract, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address', addressMock.contract, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_counters', countersMock.forContract, { pathParams: { hash: ADDRESS_HASH } });
|
||||
|
||||
const component = await render(<AddressDetails addressQuery={{ data: addressMock.contract } as AddressQuery}/>, { hooksConfig });
|
||||
|
||||
@@ -71,12 +71,12 @@ test('contract', async({ render, page, mockApiResponse }) => {
|
||||
|
||||
// there's an unexpected timeout occurred in this test
|
||||
test.fixme('token', async({ render, mockApiResponse, injectMetaMaskProvider, page }) => {
|
||||
await mockApiResponse('address', addressMock.token, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('address_counters', countersMock.forToken, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('address_tokens', tokensMock.erc20List, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-20' }, times: 1 });
|
||||
await mockApiResponse('address_tokens', tokensMock.erc721List, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-721' }, times: 1 });
|
||||
await mockApiResponse('address_tokens', tokensMock.erc1155List, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-1155' }, times: 1 });
|
||||
await mockApiResponse('address_tokens', tokensMock.erc404List, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-404' }, times: 1 });
|
||||
await mockApiResponse('general:address', addressMock.token, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_counters', countersMock.forToken, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_tokens', tokensMock.erc20List, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-20' }, times: 1 });
|
||||
await mockApiResponse('general:address_tokens', tokensMock.erc721List, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-721' }, times: 1 });
|
||||
await mockApiResponse('general:address_tokens', tokensMock.erc1155List, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-1155' }, times: 1 });
|
||||
await mockApiResponse('general:address_tokens', tokensMock.erc404List, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-404' }, times: 1 });
|
||||
await injectMetaMaskProvider();
|
||||
|
||||
const component = await render(
|
||||
@@ -93,8 +93,8 @@ test.fixme('token', async({ render, mockApiResponse, injectMetaMaskProvider, pag
|
||||
});
|
||||
|
||||
test('validator', async({ render, mockApiResponse, page }) => {
|
||||
await mockApiResponse('address', addressMock.validator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address', addressMock.validator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
|
||||
const component = await render(<AddressDetails addressQuery={{ data: addressMock.validator } as AddressQuery}/>, { hooksConfig });
|
||||
|
||||
@@ -105,8 +105,8 @@ test('validator', async({ render, mockApiResponse, page }) => {
|
||||
});
|
||||
|
||||
test('filecoin', async({ render, mockApiResponse, page }) => {
|
||||
await mockApiResponse('address', addressMock.filecoin, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address', addressMock.filecoin, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_counters', countersMock.forValidator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
|
||||
const component = await render(<AddressDetails addressQuery={{ data: addressMock.filecoin } as AddressQuery}/>, { hooksConfig });
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ const hooksConfig = {
|
||||
};
|
||||
|
||||
test('base view +@mobile', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('address_epoch_rewards', epochRewards, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_epoch_rewards', epochRewards, { pathParams: { hash: ADDRESS_HASH } });
|
||||
const component = await render(
|
||||
<Box pt={{ base: '134px', lg: 6 }}>
|
||||
<AddressEpochRewards/>
|
||||
|
||||
@@ -27,13 +27,13 @@ const AddressEpochRewards = ({ shouldRender = true, isQueryEnabled = true }: Pro
|
||||
const hash = getQueryParamString(router.query.hash);
|
||||
|
||||
const rewardsQuery = useQueryWithPages({
|
||||
resourceName: 'address_epoch_rewards',
|
||||
resourceName: 'general:address_epoch_rewards',
|
||||
pathParams: {
|
||||
hash,
|
||||
},
|
||||
options: {
|
||||
enabled: isQueryEnabled && Boolean(hash),
|
||||
placeholderData: generateListStub<'address_epoch_rewards'>(EPOCH_REWARD_ITEM, 50, { next_page_params: {
|
||||
placeholderData: generateListStub<'general:address_epoch_rewards'>(EPOCH_REWARD_ITEM, 50, { next_page_params: {
|
||||
amount: '1',
|
||||
items_count: 50,
|
||||
type: 'voter',
|
||||
|
||||
@@ -15,7 +15,7 @@ const hooksConfig = {
|
||||
|
||||
test('base view +@mobile', async({ render, mockApiResponse }) => {
|
||||
test.slow();
|
||||
await mockApiResponse('address_internal_txs', internalTxsMock.baseResponse, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_internal_txs', internalTxsMock.baseResponse, { pathParams: { hash: ADDRESS_HASH } });
|
||||
const component = await render(
|
||||
<Box pt={{ base: '134px', lg: 6 }}>
|
||||
<AddressInternalTxs/>
|
||||
|
||||
@@ -36,12 +36,12 @@ const AddressInternalTxs = ({ shouldRender = true, isQueryEnabled = true }: Prop
|
||||
const hash = getQueryParamString(router.query.hash);
|
||||
|
||||
const { data, isPlaceholderData, isError, pagination, onFilterChange } = useQueryWithPages({
|
||||
resourceName: 'address_internal_txs',
|
||||
resourceName: 'general:address_internal_txs',
|
||||
pathParams: { hash },
|
||||
filters: { filter: filterValue },
|
||||
options: {
|
||||
enabled: isQueryEnabled,
|
||||
placeholderData: generateListStub<'address_internal_txs'>(
|
||||
placeholderData: generateListStub<'general:address_internal_txs'>(
|
||||
INTERNAL_TX,
|
||||
50,
|
||||
{
|
||||
|
||||
@@ -25,11 +25,11 @@ const AddressLogs = ({ shouldRender = true, isQueryEnabled = true }: Props) => {
|
||||
|
||||
const hash = getQueryParamString(router.query.hash);
|
||||
const { data, isPlaceholderData, isError, pagination } = useQueryWithPages({
|
||||
resourceName: 'address_logs',
|
||||
resourceName: 'general:address_logs',
|
||||
pathParams: { hash },
|
||||
options: {
|
||||
enabled: isQueryEnabled,
|
||||
placeholderData: generateListStub<'address_logs'>(LOG, 3, { next_page_params: {
|
||||
placeholderData: generateListStub<'general:address_logs'>(LOG, 3, { next_page_params: {
|
||||
block_number: 9005750,
|
||||
index: 42,
|
||||
items_count: 50,
|
||||
|
||||
@@ -28,7 +28,7 @@ const tokenTransfersWoPagination = {
|
||||
};
|
||||
|
||||
test('with pagination', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('address_token_transfers', tokenTransfersWithPagination, {
|
||||
await mockApiResponse('general:address_token_transfers', tokenTransfersWithPagination, {
|
||||
pathParams: { hash: CURRENT_ADDRESS },
|
||||
queryParams: { type: [] },
|
||||
});
|
||||
@@ -42,7 +42,7 @@ test('with pagination', async({ render, mockApiResponse }) => {
|
||||
});
|
||||
|
||||
test('without pagination', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('address_token_transfers', tokenTransfersWoPagination, {
|
||||
await mockApiResponse('general:address_token_transfers', tokenTransfersWoPagination, {
|
||||
pathParams: { hash: CURRENT_ADDRESS },
|
||||
queryParams: { type: [] },
|
||||
});
|
||||
@@ -59,7 +59,7 @@ test.describe('mobile', () => {
|
||||
test.use({ viewport: devices['iPhone 13 Pro'].viewport });
|
||||
|
||||
test('with pagination', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('address_token_transfers', tokenTransfersWithPagination, {
|
||||
await mockApiResponse('general:address_token_transfers', tokenTransfersWithPagination, {
|
||||
pathParams: { hash: CURRENT_ADDRESS },
|
||||
queryParams: { type: [] },
|
||||
});
|
||||
@@ -73,7 +73,7 @@ test.describe('mobile', () => {
|
||||
});
|
||||
|
||||
test('without pagination', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('address_token_transfers', tokenTransfersWoPagination, {
|
||||
await mockApiResponse('general:address_token_transfers', tokenTransfersWoPagination, {
|
||||
pathParams: { hash: CURRENT_ADDRESS },
|
||||
queryParams: { type: [] },
|
||||
});
|
||||
@@ -94,7 +94,7 @@ test.describe('socket', () => {
|
||||
query: { hash: CURRENT_ADDRESS },
|
||||
},
|
||||
};
|
||||
await mockApiResponse('address_token_transfers', tokenTransfersWithPagination, {
|
||||
await mockApiResponse('general:address_token_transfers', tokenTransfersWithPagination, {
|
||||
pathParams: { hash: CURRENT_ADDRESS },
|
||||
queryParams: { type: [] },
|
||||
});
|
||||
@@ -127,7 +127,7 @@ test.describe('socket', () => {
|
||||
query: { hash: CURRENT_ADDRESS },
|
||||
},
|
||||
};
|
||||
await mockApiResponse('address_token_transfers', tokenTransfersWithPagination, {
|
||||
await mockApiResponse('general:address_token_transfers', tokenTransfersWithPagination, {
|
||||
pathParams: { hash: CURRENT_ADDRESS },
|
||||
queryParams: { type: [] },
|
||||
});
|
||||
@@ -163,7 +163,7 @@ test.describe('socket', () => {
|
||||
query: { hash: CURRENT_ADDRESS, type: 'ERC-1155' },
|
||||
},
|
||||
};
|
||||
await mockApiResponse('address_token_transfers', tokenTransfersWithPagination, {
|
||||
await mockApiResponse('general:address_token_transfers', tokenTransfersWithPagination, {
|
||||
pathParams: { hash: CURRENT_ADDRESS },
|
||||
queryParams: { type: 'ERC-1155' },
|
||||
});
|
||||
@@ -197,7 +197,7 @@ test.describe('socket', () => {
|
||||
query: { hash: CURRENT_ADDRESS, type: 'ERC-1155' },
|
||||
},
|
||||
};
|
||||
await mockApiResponse('address_token_transfers', tokenTransfersWithPagination, {
|
||||
await mockApiResponse('general:address_token_transfers', tokenTransfersWithPagination, {
|
||||
pathParams: { hash: CURRENT_ADDRESS },
|
||||
queryParams: { type: 'ERC-1155' },
|
||||
});
|
||||
|
||||
@@ -84,7 +84,7 @@ const AddressTokenTransfers = ({ overloadCount = OVERLOAD_COUNT, shouldRender =
|
||||
);
|
||||
|
||||
const { isError, isPlaceholderData, data, pagination, onFilterChange } = useQueryWithPages({
|
||||
resourceName: 'address_token_transfers',
|
||||
resourceName: 'general:address_token_transfers',
|
||||
pathParams: { hash: currentAddress },
|
||||
filters,
|
||||
options: {
|
||||
@@ -132,7 +132,7 @@ const AddressTokenTransfers = ({ overloadCount = OVERLOAD_COUNT, shouldRender =
|
||||
|
||||
if (newItems.length > 0) {
|
||||
queryClient.setQueryData(
|
||||
getResourceKey('address_token_transfers', { pathParams: { hash: currentAddress }, queryParams: { ...filters } }),
|
||||
getResourceKey('general:address_token_transfers', { pathParams: { hash: currentAddress }, queryParams: { ...filters } }),
|
||||
(prevData: AddressTokenTransferResponse | undefined) => {
|
||||
if (!prevData) {
|
||||
return;
|
||||
|
||||
@@ -39,13 +39,13 @@ test.beforeEach(async({ mockApiResponse }) => {
|
||||
next_page_params: nextPageParams,
|
||||
};
|
||||
|
||||
await mockApiResponse('address', addressMock.validator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('address_tokens', response20, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-20' } });
|
||||
await mockApiResponse('address_tokens', response721, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-721' } });
|
||||
await mockApiResponse('address_tokens', response1155, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-1155' } });
|
||||
await mockApiResponse('address_tokens', response404, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-404' } });
|
||||
await mockApiResponse('address_nfts', tokensMock.nfts, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: [] } });
|
||||
await mockApiResponse('address_collections', tokensMock.collections, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: [] } });
|
||||
await mockApiResponse('general:address', addressMock.validator, { pathParams: { hash: ADDRESS_HASH } });
|
||||
await mockApiResponse('general:address_tokens', response20, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-20' } });
|
||||
await mockApiResponse('general:address_tokens', response721, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-721' } });
|
||||
await mockApiResponse('general:address_tokens', response1155, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-1155' } });
|
||||
await mockApiResponse('general:address_tokens', response404, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-404' } });
|
||||
await mockApiResponse('general:address_nfts', tokensMock.nfts, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: [] } });
|
||||
await mockApiResponse('general:address_collections', tokensMock.collections, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: [] } });
|
||||
});
|
||||
|
||||
test('erc20 +@dark-mode', async({ render }) => {
|
||||
@@ -198,10 +198,18 @@ test.describe('update balances via socket', () => {
|
||||
next_page_params: null,
|
||||
};
|
||||
|
||||
const erc20ApiUrl = await mockApiResponse('address_tokens', response20, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-20' } });
|
||||
const erc721ApiUrl = await mockApiResponse('address_tokens', response721, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-721' } });
|
||||
const erc1155ApiUrl = await mockApiResponse('address_tokens', response1155, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-1155' } });
|
||||
const erc404ApiUrl = await mockApiResponse('address_tokens', response404, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-404' } });
|
||||
const erc20ApiUrl = await mockApiResponse('general:address_tokens', response20, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-20' } });
|
||||
const erc721ApiUrl = await mockApiResponse('general:address_tokens', response721, { pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-721' } });
|
||||
const erc1155ApiUrl = await mockApiResponse(
|
||||
'general:address_tokens',
|
||||
response1155,
|
||||
{ pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-1155' } },
|
||||
);
|
||||
const erc404ApiUrl = await mockApiResponse(
|
||||
'general:address_tokens',
|
||||
response404,
|
||||
{ pathParams: { hash: ADDRESS_HASH }, queryParams: { type: 'ERC-404' } },
|
||||
);
|
||||
|
||||
const component = await render(
|
||||
<Box pt={{ base: '134px', lg: 6 }}>
|
||||
|
||||
@@ -40,7 +40,8 @@ const TAB_LIST_PROPS_MOBILE = {
|
||||
my: 8,
|
||||
};
|
||||
|
||||
const getTokenFilterValue = (getFilterValuesFromQuery<NFTTokenType>).bind(null, NFT_TOKEN_TYPE_IDS);
|
||||
const getTokenFilterValue: (type: string | Array<string> | undefined) => Array<NFTTokenType> | undefined =
|
||||
(getFilterValuesFromQuery<NFTTokenType>).bind(null, NFT_TOKEN_TYPE_IDS);
|
||||
|
||||
type Props = {
|
||||
shouldRender?: boolean;
|
||||
@@ -62,35 +63,35 @@ const AddressTokens = ({ shouldRender = true, isQueryEnabled = true }: Props) =>
|
||||
const hash = getQueryParamString(router.query.hash);
|
||||
|
||||
const erc20Query = useQueryWithPages({
|
||||
resourceName: 'address_tokens',
|
||||
resourceName: 'general:address_tokens',
|
||||
pathParams: { hash },
|
||||
filters: { type: 'ERC-20' },
|
||||
scrollRef,
|
||||
options: {
|
||||
enabled: isQueryEnabled && (!tab || tab === 'tokens' || tab === 'tokens_erc20'),
|
||||
refetchOnMount: false,
|
||||
placeholderData: generateListStub<'address_tokens'>(ADDRESS_TOKEN_BALANCE_ERC_20, 10, { next_page_params: null }),
|
||||
placeholderData: generateListStub<'general:address_tokens'>(ADDRESS_TOKEN_BALANCE_ERC_20, 10, { next_page_params: null }),
|
||||
},
|
||||
});
|
||||
|
||||
const collectionsQuery = useQueryWithPages({
|
||||
resourceName: 'address_collections',
|
||||
resourceName: 'general:address_collections',
|
||||
pathParams: { hash },
|
||||
scrollRef,
|
||||
options: {
|
||||
enabled: isQueryEnabled && tab === 'tokens_nfts' && nftDisplayType === 'collection',
|
||||
placeholderData: generateListStub<'address_collections'>(ADDRESS_COLLECTION, 10, { next_page_params: null }),
|
||||
placeholderData: generateListStub<'general:address_collections'>(ADDRESS_COLLECTION, 10, { next_page_params: null }),
|
||||
},
|
||||
filters: { type: tokenTypes },
|
||||
});
|
||||
|
||||
const nftsQuery = useQueryWithPages({
|
||||
resourceName: 'address_nfts',
|
||||
resourceName: 'general:address_nfts',
|
||||
pathParams: { hash },
|
||||
scrollRef,
|
||||
options: {
|
||||
enabled: isQueryEnabled && tab === 'tokens_nfts' && nftDisplayType === 'list',
|
||||
placeholderData: generateListStub<'address_nfts'>(ADDRESS_NFT_1155, 10, { next_page_params: null }),
|
||||
placeholderData: generateListStub<'general:address_nfts'>(ADDRESS_NFT_1155, 10, { next_page_params: null }),
|
||||
},
|
||||
filters: { type: tokenTypes },
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ test.describe('base view', () => {
|
||||
|
||||
test.beforeEach(async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse(
|
||||
'address_txs',
|
||||
'general:address_txs',
|
||||
{
|
||||
items: [
|
||||
txMock.base,
|
||||
@@ -60,7 +60,7 @@ test.describe('base view', () => {
|
||||
|
||||
test('mobile', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse(
|
||||
'address_txs',
|
||||
'general:address_txs',
|
||||
{
|
||||
items: [
|
||||
txMock.base,
|
||||
@@ -87,7 +87,7 @@ test.describe('socket', () => {
|
||||
|
||||
test('with update', async({ render, mockApiResponse, page, createSocket }) => {
|
||||
await mockApiResponse(
|
||||
'address_txs',
|
||||
'general:address_txs',
|
||||
{ items: [ txMock.pending ], next_page_params: DEFAULT_PAGINATION },
|
||||
{ pathParams: { hash: CURRENT_ADDRESS } },
|
||||
);
|
||||
@@ -117,7 +117,7 @@ test.describe('socket', () => {
|
||||
|
||||
test('with overload', async({ render, mockApiResponse, page, createSocket }) => {
|
||||
await mockApiResponse(
|
||||
'address_txs',
|
||||
'general:address_txs',
|
||||
{ items: [ txMock.base ], next_page_params: DEFAULT_PAGINATION },
|
||||
{ pathParams: { hash: CURRENT_ADDRESS } },
|
||||
);
|
||||
@@ -156,7 +156,7 @@ test.describe('socket', () => {
|
||||
};
|
||||
|
||||
await mockApiResponse(
|
||||
'address_txs',
|
||||
'general:address_txs',
|
||||
{ items: [ txMock.base ], next_page_params: DEFAULT_PAGINATION },
|
||||
{ pathParams: { hash: CURRENT_ADDRESS }, queryParams: { filter: 'from' } },
|
||||
);
|
||||
@@ -192,7 +192,7 @@ test.describe('socket', () => {
|
||||
};
|
||||
|
||||
await mockApiResponse(
|
||||
'address_txs',
|
||||
'general:address_txs',
|
||||
{ items: [ txMock.base ], next_page_params: DEFAULT_PAGINATION },
|
||||
{ pathParams: { hash: CURRENT_ADDRESS }, queryParams: { filter: 'from' } },
|
||||
);
|
||||
|
||||
@@ -42,13 +42,13 @@ const AddressTxs = ({ shouldRender = true, isQueryEnabled = true }: Props) => {
|
||||
const [ filterValue, setFilterValue ] = React.useState<AddressFromToFilter>(initialFilterValue);
|
||||
|
||||
const addressTxsQuery = useQueryWithPages({
|
||||
resourceName: 'address_txs',
|
||||
resourceName: 'general:address_txs',
|
||||
pathParams: { hash: currentAddress },
|
||||
filters: { filter: filterValue },
|
||||
sorting: getSortParamsFromValue<TransactionsSortingValue, TransactionsSortingField, TransactionsSorting['order']>(sort),
|
||||
options: {
|
||||
enabled: isQueryEnabled,
|
||||
placeholderData: generateListStub<'address_txs'>(TX, 50, { next_page_params: {
|
||||
placeholderData: generateListStub<'general:address_txs'>(TX, 50, { next_page_params: {
|
||||
block_number: 9005713,
|
||||
index: 5,
|
||||
items_count: 50,
|
||||
|
||||
@@ -21,11 +21,11 @@ const AddressUserOps = ({ scrollRef, shouldRender = true, isQueryEnabled = true
|
||||
const hash = getQueryParamString(router.query.hash);
|
||||
|
||||
const userOpsQuery = useQueryWithPages({
|
||||
resourceName: 'user_ops',
|
||||
resourceName: 'general:user_ops',
|
||||
scrollRef,
|
||||
options: {
|
||||
enabled: isQueryEnabled && Boolean(hash),
|
||||
placeholderData: generateListStub<'user_ops'>(USER_OPS_ITEM, 50, { next_page_params: {
|
||||
placeholderData: generateListStub<'general:user_ops'>(USER_OPS_ITEM, 50, { next_page_params: {
|
||||
page_token: '10355938,0x5956a847d8089e254e02e5111cad6992b99ceb9e5c2dc4343fd53002834c4dc6',
|
||||
page_size: 50,
|
||||
} }),
|
||||
|
||||
@@ -24,11 +24,11 @@ const AddressWithdrawals = ({ shouldRender = true, isQueryEnabled = true }: Prop
|
||||
const hash = getQueryParamString(router.query.hash);
|
||||
|
||||
const { data, isPlaceholderData, isError, pagination } = useQueryWithPages({
|
||||
resourceName: 'address_withdrawals',
|
||||
resourceName: 'general:address_withdrawals',
|
||||
pathParams: { hash },
|
||||
options: {
|
||||
enabled: isQueryEnabled,
|
||||
placeholderData: generateListStub<'address_withdrawals'>(WITHDRAWAL, 50, { next_page_params: {
|
||||
placeholderData: generateListStub<'general:address_withdrawals'>(WITHDRAWAL, 50, { next_page_params: {
|
||||
index: 5,
|
||||
items_count: 50,
|
||||
} }),
|
||||
|
||||
@@ -9,7 +9,7 @@ const addressHash = 'hash';
|
||||
|
||||
test('average report +@dark-mode +@mobile', async({ render, mockApiResponse, page }) => {
|
||||
await mockApiResponse(
|
||||
'contract_solidity_scan_report',
|
||||
'general:contract_solidity_scan_report',
|
||||
solidityscanReportMock.solidityscanReportAverage,
|
||||
{ pathParams: { hash: addressHash } },
|
||||
);
|
||||
@@ -23,7 +23,7 @@ test('average report +@dark-mode +@mobile', async({ render, mockApiResponse, pag
|
||||
|
||||
test('great report', async({ render, mockApiResponse, page }) => {
|
||||
await mockApiResponse(
|
||||
'contract_solidity_scan_report',
|
||||
'general:contract_solidity_scan_report',
|
||||
solidityscanReportMock.solidityscanReportGreat,
|
||||
{ pathParams: { hash: addressHash } },
|
||||
);
|
||||
@@ -41,7 +41,7 @@ test('great report', async({ render, mockApiResponse, page }) => {
|
||||
|
||||
test('low report', async({ render, mockApiResponse, page }) => {
|
||||
await mockApiResponse(
|
||||
'contract_solidity_scan_report',
|
||||
'general:contract_solidity_scan_report',
|
||||
solidityscanReportMock.solidityscanReportLow,
|
||||
{ pathParams: { hash: addressHash } },
|
||||
);
|
||||
|
||||
@@ -11,7 +11,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const AddressCoinBalanceChart = ({ addressHash }: Props) => {
|
||||
const { data, isPending, isError } = useApiQuery('address_coin_balance_chart', {
|
||||
const { data, isPending, isError } = useApiQuery('general:address_coin_balance_chart', {
|
||||
pathParams: { hash: addressHash },
|
||||
});
|
||||
|
||||
|
||||
@@ -24,14 +24,14 @@ test.beforeEach(async({ mockApiResponse, page }) => {
|
||||
await page.route('https://cdn.jsdelivr.net/npm/[email protected]/**', (route) => {
|
||||
route.abort();
|
||||
});
|
||||
addressApiUrl = await mockApiResponse('address', addressMock.contract, { pathParams: { hash: addressMock.contract.hash } });
|
||||
addressApiUrl = await mockApiResponse('general:address', addressMock.contract, { pathParams: { hash: addressMock.contract.hash } });
|
||||
});
|
||||
|
||||
test.describe('full view', () => {
|
||||
test.beforeEach(async({ mockApiResponse }) => {
|
||||
await mockApiResponse('contract', contractMock.withChangedByteCode, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse('general:contract', contractMock.withChangedByteCode, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse(
|
||||
'contract',
|
||||
'general:contract',
|
||||
contractMock.withChangedByteCode,
|
||||
{ pathParams: { hash: addressMock.contract.implementations?.[0].address_hash as string } },
|
||||
);
|
||||
@@ -90,9 +90,9 @@ test.describe('mobile view', () => {
|
||||
test.use({ viewport: pwConfig.viewport.mobile });
|
||||
|
||||
test('source code', async({ render, createSocket, mockApiResponse }) => {
|
||||
await mockApiResponse('contract', contractMock.withChangedByteCode, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse('general:contract', contractMock.withChangedByteCode, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse(
|
||||
'contract',
|
||||
'general:contract',
|
||||
contractMock.withChangedByteCode,
|
||||
{ pathParams: { hash: addressMock.contract.implementations?.[0].address_hash as string } },
|
||||
);
|
||||
@@ -104,7 +104,7 @@ test.describe('mobile view', () => {
|
||||
});
|
||||
|
||||
test('verified via lookup in eth_bytecode_db', async({ render, mockApiResponse, createSocket, page }) => {
|
||||
const contractApiUrl = await mockApiResponse('contract', contractMock.nonVerified, { pathParams: { hash: addressMock.contract.hash } });
|
||||
const contractApiUrl = await mockApiResponse('general:contract', contractMock.nonVerified, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await render(<ContractDetails/>, { hooksConfig }, { withSocket: true });
|
||||
|
||||
const socket = await createSocket();
|
||||
@@ -117,7 +117,7 @@ test('verified via lookup in eth_bytecode_db', async({ render, mockApiResponse,
|
||||
});
|
||||
|
||||
test('verified with multiple sources', async({ render, page, mockApiResponse, createSocket }) => {
|
||||
await mockApiResponse('contract', contractMock.withMultiplePaths, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse('general:contract', contractMock.withMultiplePaths, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await render(<ContractDetails/>, { hooksConfig }, { withSocket: true });
|
||||
const socket = await createSocket();
|
||||
await socketServer.joinChannel(socket, `addresses:${ addressMock.contract.hash.toLowerCase() }`);
|
||||
@@ -138,7 +138,7 @@ test('self destructed', async({ render, mockApiResponse, page, createSocket }) =
|
||||
query: { hash: addressMock.contract.hash, tab: 'contract_bytecode' },
|
||||
},
|
||||
};
|
||||
await mockApiResponse('contract', contractMock.selfDestructed, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse('general:contract', contractMock.selfDestructed, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await render(<ContractDetails/>, { hooksConfig }, { withSocket: true });
|
||||
const socket = await createSocket();
|
||||
await socketServer.joinChannel(socket, `addresses:${ addressMock.contract.hash.toLowerCase() }`);
|
||||
@@ -148,8 +148,8 @@ test('self destructed', async({ render, mockApiResponse, page, createSocket }) =
|
||||
});
|
||||
|
||||
test('non verified', async({ render, mockApiResponse, createSocket }) => {
|
||||
await mockApiResponse('address', { ...addressMock.contract, name: null }, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse('contract', contractMock.nonVerified, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse('general:address', { ...addressMock.contract, name: null }, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse('general:contract', contractMock.nonVerified, { pathParams: { hash: addressMock.contract.hash } });
|
||||
const component = await render(<ContractDetails/>, { hooksConfig }, { withSocket: true });
|
||||
const socket = await createSocket();
|
||||
await socketServer.joinChannel(socket, `addresses:${ addressMock.contract.hash.toLowerCase() }`);
|
||||
|
||||
@@ -53,7 +53,7 @@ const ContractDetails = ({ addressData, channel, mainContractQuery }: Props) =>
|
||||
|
||||
const [ selectedItem, setSelectedItem ] = React.useState(sourceItems.find((item) => item.address_hash === sourceAddress) || sourceItems[0]);
|
||||
|
||||
const contractQuery = useApiQuery('contract', {
|
||||
const contractQuery = useApiQuery('general:contract', {
|
||||
pathParams: { hash: selectedItem?.address_hash },
|
||||
queryOptions: {
|
||||
enabled: Boolean(selectedItem?.address_hash && !mainContractQuery.isPlaceholderData),
|
||||
@@ -67,10 +67,10 @@ const ContractDetails = ({ addressData, channel, mainContractQuery }: Props) =>
|
||||
|
||||
const handleContractWasVerifiedMessage: SocketMessage.SmartContractWasVerified['handler'] = React.useCallback(() => {
|
||||
queryClient.refetchQueries({
|
||||
queryKey: getResourceKey('address', { pathParams: { hash: addressData.hash } }),
|
||||
queryKey: getResourceKey('general:address', { pathParams: { hash: addressData.hash } }),
|
||||
});
|
||||
queryClient.refetchQueries({
|
||||
queryKey: getResourceKey('contract', { pathParams: { hash: addressData.hash } }),
|
||||
queryKey: getResourceKey('general:contract', { pathParams: { hash: addressData.hash } }),
|
||||
});
|
||||
}, [ addressData.hash, queryClient ]);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ type Props = {
|
||||
};
|
||||
|
||||
const ContractSecurityAudits = ({ addressHash }: Props) => {
|
||||
const { data, isPlaceholderData } = useApiQuery('contract_security_audits', {
|
||||
const { data, isPlaceholderData } = useApiQuery('general:contract_security_audits', {
|
||||
pathParams: { hash: addressHash },
|
||||
queryOptions: {
|
||||
refetchOnMount: false,
|
||||
|
||||
@@ -49,7 +49,7 @@ const ContractSubmitAuditForm = ({ address, onSuccess }: Props) => {
|
||||
|
||||
const onFormSubmit: SubmitHandler<Inputs> = React.useCallback(async(data) => {
|
||||
try {
|
||||
await apiFetch<'contract_security_audits', SmartContractSecurityAuditSubmission, AuditSubmissionErrors>('contract_security_audits', {
|
||||
await apiFetch<'general:contract_security_audits', SmartContractSecurityAuditSubmission, AuditSubmissionErrors>('general:contract_security_audits', {
|
||||
pathParams: { hash: address },
|
||||
fetchParams: {
|
||||
method: 'POST',
|
||||
|
||||
@@ -50,7 +50,7 @@ test.describe('with audits feature', () => {
|
||||
});
|
||||
|
||||
test('no audits', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('contract_security_audits', { items: [] }, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse('general:contract_security_audits', { items: [] }, { pathParams: { hash: addressMock.contract.hash } });
|
||||
const props = {
|
||||
data: contractMock.verified,
|
||||
isLoading: false,
|
||||
@@ -62,7 +62,7 @@ test.describe('with audits feature', () => {
|
||||
});
|
||||
|
||||
test('has audits', async({ render, mockApiResponse }) => {
|
||||
await mockApiResponse('contract_security_audits', contractAudits, { pathParams: { hash: addressMock.contract.hash } });
|
||||
await mockApiResponse('general:contract_security_audits', contractAudits, { pathParams: { hash: addressMock.contract.hash } });
|
||||
const props = {
|
||||
data: contractMock.verified,
|
||||
isLoading: false,
|
||||
|
||||
@@ -28,7 +28,7 @@ authTest('without data', async({ render }) => {
|
||||
|
||||
authTest('with data', async({ render, mockApiResponse }) => {
|
||||
const abi: Array<AbiItem> = [ ...methodsMock.read, ...methodsMock.write ];
|
||||
await mockApiResponse('custom_abi', [ {
|
||||
await mockApiResponse('general:custom_abi', [ {
|
||||
abi,
|
||||
contract_address_hash: addressHash,
|
||||
contract_address: addressMock.withName,
|
||||
|
||||
@@ -38,14 +38,14 @@ const ContractMethodsCustom = ({ isLoading: isLoadingProp }: Props) => {
|
||||
|
||||
const isAuth = useIsAuth();
|
||||
|
||||
const customAbiQuery = useApiQuery('custom_abi', {
|
||||
const customAbiQuery = useApiQuery('general:custom_abi', {
|
||||
queryOptions: {
|
||||
enabled: !isLoadingProp && isAuth,
|
||||
refetchOnMount: false,
|
||||
},
|
||||
});
|
||||
|
||||
const contractQueryData = queryClient.getQueryData<SmartContract>(getResourceKey('contract', { pathParams: { hash: addressHash } }));
|
||||
const contractQueryData = queryClient.getQueryData<SmartContract>(getResourceKey('general:contract', { pathParams: { hash: addressHash } }));
|
||||
|
||||
const isLoading = isLoadingProp || (isAuth && customAbiQuery.isLoading);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ const ContractMethodsMudSystem = ({ items }: Props) => {
|
||||
|
||||
const [ selectedItem, setSelectedItem ] = React.useState(items.find((item) => item.address_hash === sourceAddress) || items[0]);
|
||||
|
||||
const systemInfoQuery = useApiQuery('contract_mud_system_info', {
|
||||
const systemInfoQuery = useApiQuery('general:mud_system_info', {
|
||||
pathParams: { hash: addressHash, system_address: selectedItem.address_hash },
|
||||
queryOptions: {
|
||||
enabled: Boolean(selectedItem?.address_hash),
|
||||
|
||||
@@ -18,7 +18,7 @@ test('with one implementation +@mobile', async({ render, mockApiResponse }) => {
|
||||
const implementations = [
|
||||
{ address_hash: '0x2F4F4A52295940C576417d29F22EEb92B440eC89', name: 'HomeBridge' },
|
||||
];
|
||||
await mockApiResponse('contract', { ...contractMock.verified, abi: methodsMock.read }, { pathParams: { hash: implementations[0].address_hash } });
|
||||
await mockApiResponse('general:contract', { ...contractMock.verified, abi: methodsMock.read }, { pathParams: { hash: implementations[0].address_hash } });
|
||||
|
||||
const component = await render(<ContractMethodsProxy implementations={ implementations }/>, { hooksConfig });
|
||||
await expect(component).toHaveScreenshot();
|
||||
@@ -34,7 +34,7 @@ test('with multiple implementations +@mobile', async({ render, mockApiResponse }
|
||||
{ address_hash: '0x2F4F4A52295940C576417d29F22EEb92B440eC89', name: 'HomeBridge' },
|
||||
{ address_hash: '0xc9e91eDeA9DC16604022e4E5b437Df9c64EdB05A', name: 'Diamond' },
|
||||
];
|
||||
await mockApiResponse('contract', { ...contractMock.verified, abi: methodsMock.read }, { pathParams: { hash: implementations[0].address_hash } });
|
||||
await mockApiResponse('general:contract', { ...contractMock.verified, abi: methodsMock.read }, { pathParams: { hash: implementations[0].address_hash } });
|
||||
|
||||
const component = await render(<ContractMethodsProxy implementations={ implementations }/>, { hooksConfig });
|
||||
await expect(component).toHaveScreenshot();
|
||||
|
||||
@@ -30,7 +30,7 @@ const ContractMethodsProxy = ({ implementations, isLoading: isInitialLoading, pr
|
||||
|
||||
const [ selectedItem, setSelectedItem ] = React.useState(implementations.find((item) => item.address_hash === sourceAddress) || implementations[0]);
|
||||
|
||||
const contractQuery = useApiQuery('contract', {
|
||||
const contractQuery = useApiQuery('general:contract', {
|
||||
pathParams: { hash: selectedItem.address_hash },
|
||||
queryOptions: {
|
||||
enabled: Boolean(selectedItem.address_hash),
|
||||
|
||||
@@ -8,7 +8,7 @@ import useContractTabs from '../useContractTabs';
|
||||
const ContractDetails = () => {
|
||||
const router = useRouter();
|
||||
const hash = getQueryParamString(router.query.hash);
|
||||
const addressQuery = useApiQuery('address', { pathParams: { hash } });
|
||||
const addressQuery = useApiQuery('general:address', { pathParams: { hash } });
|
||||
const { tabs } = useContractTabs(addressQuery.data, false);
|
||||
const content = tabs.find(({ id }) => id === 'contract_code')?.component;
|
||||
return content ?? null;
|
||||
|
||||
@@ -42,7 +42,7 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
|
||||
setIsQueryEnabled(true);
|
||||
}, []);
|
||||
|
||||
const contractQuery = useApiQuery('contract', {
|
||||
const contractQuery = useApiQuery('general:contract', {
|
||||
pathParams: { hash: data?.hash },
|
||||
queryOptions: {
|
||||
enabled: isEnabled && isQueryEnabled,
|
||||
@@ -51,7 +51,7 @@ export default function useContractTabs(data: Address | undefined, isPlaceholder
|
||||
},
|
||||
});
|
||||
|
||||
const mudSystemsQuery = useApiQuery('contract_mud_systems', {
|
||||
const mudSystemsQuery = useApiQuery('general:mud_systems', {
|
||||
pathParams: { hash: data?.hash },
|
||||
queryOptions: {
|
||||
enabled: isEnabled && isQueryEnabled && hasMudTab,
|
||||
|
||||
@@ -28,7 +28,7 @@ const AddressBalance = ({ data, isLoading }: Props) => {
|
||||
}
|
||||
|
||||
setLastBlockNumber(blockNumber);
|
||||
const queryKey = getResourceKey('address', { pathParams: { hash: data.hash } });
|
||||
const queryKey = getResourceKey('general:address', { pathParams: { hash: data.hash } });
|
||||
queryClient.setQueryData(queryKey, (prevData: Address | undefined) => {
|
||||
if (!prevData) {
|
||||
return;
|
||||
|
||||
@@ -36,7 +36,7 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
|
||||
}, [ watchListId, deleteModalProps, addModalProps ]);
|
||||
|
||||
const handleAddOrDeleteSuccess = React.useCallback(async() => {
|
||||
const queryKey = getResourceKey('address', { pathParams: { hash: router.query.hash?.toString() } });
|
||||
const queryKey = getResourceKey('general:address', { pathParams: { hash: router.query.hash?.toString() } });
|
||||
await queryClient.refetchQueries({ queryKey });
|
||||
addModalProps.onClose();
|
||||
}, [ addModalProps, queryClient, router.query.hash ]);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user