Commit 4a3627c7 authored by tom's avatar tom

Merge branch 'main' of github.com:blockscout/frontend into chakra-v3

parents 58b6067b ae759780
...@@ -97,11 +97,11 @@ jobs: ...@@ -97,11 +97,11 @@ jobs:
} }
if (projects.length > 1) { if (projects.length > 1) {
core.info(`Fould ${ projects.length } with the similar name:`); core.info(`Found ${ projects.length } with the similar name:`);
projects.forEach((issue) => { projects.forEach((issue) => {
core.info(` #${ projects.number } - ${ projects.title }`); core.info(` #${ projects.number } - ${ projects.title }`);
}) })
core.setFailed('Fould multiple projects with the similar name. Cannot determine which one to use.'); core.setFailed('Found multiple projects with the similar name. Cannot determine which one to use.');
return; return;
} }
...@@ -212,8 +212,12 @@ jobs: ...@@ -212,8 +212,12 @@ jobs:
for (const item of items) { for (const item of items) {
core.info(`Changing field value for item ${ item }...`); core.info(`Changing field value for item ${ item }...`);
try {
await changeItemFieldValue(item); await changeItemFieldValue(item);
core.info('Done.\n'); core.info('Done.\n');
} catch (error) {
core.info(`Error: ${ error.message }\n`);
}
} }
async function changeItemFieldValue(itemId) { async function changeItemFieldValue(itemId) {
......
...@@ -28,6 +28,15 @@ ...@@ -28,6 +28,15 @@
**Full list of the ENV variables**: [v1.2.3](https://github.com/blockscout/frontend/blob/v1.2.3/docs/ENVS.md) **Full list of the ENV variables**: [v1.2.3](https://github.com/blockscout/frontend/blob/v1.2.3/docs/ENVS.md)
## 💑 Compatibility
From this version onward, the app is compatible only with the following API versions:
| Service | Version |
| --- | --- |
| Blockscout API | ... |
| Stats microservice API | ... |
| ... | ... |
## 🦄 New Contributors ## 🦄 New Contributors
- @contributor1 made their first contribution in https://github.com/blockscout/frontend/pull/1 - @contributor1 made their first contribution in https://github.com/blockscout/frontend/pull/1
- @contributor2 made their first contribution in https://github.com/blockscout/frontend/pull/2 - @contributor2 made their first contribution in https://github.com/blockscout/frontend/pull/2
......
...@@ -10,9 +10,6 @@ NEXT_PUBLIC_APP_ENV=development ...@@ -10,9 +10,6 @@ NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
# Instance ENVs # Instance ENVs
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "728471", "width": "728", "height": "90" }
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "728470", "width": "320", "height": "100" }
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER=adbutler
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/ NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=eth.blockscout.com NEXT_PUBLIC_API_HOST=eth.blockscout.com
...@@ -20,9 +17,11 @@ NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout ...@@ -20,9 +17,11 @@ 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_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.services.blockscout.com NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED=true NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED=true
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swapscout','icon':'swap','dappId':'swapscout'},{'text':'Disperse','icon':'txn_batches_slim','dappId':'smol'},{'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.json NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth.json
NEXT_PUBLIC_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/eth-mainnet.json NEXT_PUBLIC_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/eth-mainnet.json
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}&partner=blockscout&utm_source=blockscout&disableBridges=true', 'dapp_id': 'smol-refuel', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'} NEXT_PUBLIC_GAS_REFUEL_PROVIDER_CONFIG={'name': 'Need gas?', 'url_template': 'https://smolrefuel.com/?outboundChain={chainId}&partner=blockscout&utm_source=blockscout&disableBridges=true', 'dapp_id': 'smol-refuel', 'logo': 'https://blockscout-content.s3.amazonaws.com/smolrefuel-logo-action-button.png'}
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xd01175f1efa23f36c5579b3c13e2bbd0885017643a7efef5cbcb6b474384dfa8 NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xd01175f1efa23f36c5579b3c13e2bbd0885017643a7efef5cbcb6b474384dfa8
NEXT_PUBLIC_HAS_BEACON_CHAIN=true NEXT_PUBLIC_HAS_BEACON_CHAIN=true
...@@ -32,7 +31,7 @@ NEXT_PUBLIC_HIDE_INDEXING_ALERT_BLOCKS=true ...@@ -32,7 +31,7 @@ NEXT_PUBLIC_HIDE_INDEXING_ALERT_BLOCKS=true
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs', 'coin_price', 'market_cap'] NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs', 'coin_price', 'market_cap']
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_LOGOUT_URL=https://ethereum-mainnet.us.auth0.com/v2/logout NEXT_PUBLIC_LOGOUT_URL=https://ethereum-mainnet.us.auth0.com/v2/logout
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=<p>Participated in our recent Blockscout activities? <a href="https://badges.blockscout.com?utm_source=instance&utm_medium=eth" target="_blank">Check your eligibility</a> and claim your NFT Scout badges. More exciting things are coming soon!</p> NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=<p>Joined recent campaigns? Mint your Merit Badge <a href="https://badges.blockscout.com?utm_source=instance&utm_medium=eth">here</a></p>
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maikReal/974c47f86a3158c1a86b092ae2f044b3/raw/abcc7e02150cd85d4974503a0357162c0a2c35a9/merits-banner.html NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maikReal/974c47f86a3158c1a86b092ae2f044b3/raw/abcc7e02150cd85d4974503a0357162c0a2c35a9/merits-banner.html
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://swap.blockscout.com?utm_source=blockscout&utm_medium=eth NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://swap.blockscout.com?utm_source=blockscout&utm_medium=eth
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json
...@@ -45,11 +44,11 @@ NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com ...@@ -45,11 +44,11 @@ NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com
NEXT_PUBLIC_METASUITES_ENABLED=true 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'},{'name': 'zapper', 'url_template': 'https://zapper.xyz/account/{address}', 'logo': 'https://blockscout-content.s3.amazonaws.com/zapper-icon.png'}] 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'},{'name': 'zapper', 'url_template': 'https://zapper.xyz/account/{address}', 'logo': 'https://blockscout-content.s3.amazonaws.com/zapper-icon.png'}]
NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com
NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/apps'] NEXT_PUBLIC_NAVIGATION_HIGHLIGHTED_ROUTES=['/pools']
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'GeckoTerminal','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/geckoterminal.png','baseUrl':'https://www.geckoterminal.com/','paths':{'token':'/eth/pools'}},{'title':'Etherscan','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/etherscan.png','baseUrl':'https://etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}, {'title':'Blockchair','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/blockchair.png','baseUrl':'https://blockchair.com/','paths':{'tx':'/ethereum/transaction','address':'/ethereum/address','token':'/ethereum/erc-20/token','block':'/ethereum/block'}},{'title':'Sentio','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/sentio.png','baseUrl':'https://app.sentio.xyz/','paths':{'tx':'/tx/1','address':'/contract/1'}}, {'title':'Tenderly','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/tenderly.png','baseUrl':'https://dashboard.tenderly.co','paths':{'tx':'/tx/mainnet'}}, {'title':'0xPPL','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/0xPPL.png','baseUrl':'https://0xppl.com','paths':{'tx':'/Ethereum/tx','address':'/','token':'/c/Ethereum'}}, {'title':'3xpl','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/3xpl.png','baseUrl':'https://3xpl.com/','paths':{'tx':'/ethereum/transaction','address':'/ethereum/address'}} ] NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Moralis','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/moralis.png','baseUrl':'https://moralis.com/','paths':{'token':'/chain/ethereum/token/price'}},{'title':'GeckoTerminal','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/geckoterminal.png','baseUrl':'https://www.geckoterminal.com/','paths':{'token':'/eth/pools'}},{'title':'Etherscan','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/etherscan.png','baseUrl':'https://etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}, {'title':'Blockchair','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/blockchair.png','baseUrl':'https://blockchair.com/','paths':{'tx':'/ethereum/transaction','address':'/ethereum/address','token':'/ethereum/erc-20/token','block':'/ethereum/block'}},{'title':'Sentio','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/sentio.png','baseUrl':'https://app.sentio.xyz/','paths':{'tx':'/tx/1','address':'/contract/1'}}, {'title':'Tenderly','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/tenderly.png','baseUrl':'https://dashboard.tenderly.co','paths':{'tx':'/tx/mainnet'}}, {'title':'0xPPL','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/0xPPL.png','baseUrl':'https://0xppl.com','paths':{'tx':'/Ethereum/tx','address':'/','token':'/c/Ethereum'}}, {'title':'3xpl','logo':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/explorer-logos/3xpl.png','baseUrl':'https://3xpl.com/','paths':{'tx':'/ethereum/transaction','address':'/ethereum/address'}} ]
NEXT_PUBLIC_NETWORK_ID=1 NEXT_PUBLIC_NETWORK_ID=1
NEXT_PUBLIC_NETWORK_NAME=Ethereum NEXT_PUBLIC_NETWORK_NAME=Ethereum
NEXT_PUBLIC_NETWORK_RPC_URL=https://eth.drpc.org NEXT_PUBLIC_NETWORK_RPC_URL=https://eth.drpc.org
...@@ -61,10 +60,10 @@ NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://eth.drpc.org?ref=559183','text':'Public ...@@ -61,10 +60,10 @@ NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://eth.drpc.org?ref=559183','text':'Public
NEXT_PUBLIC_REWARDS_SERVICE_API_HOST=https://merits.blockscout.com NEXT_PUBLIC_REWARDS_SERVICE_API_HOST=https://merits.blockscout.com
NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-mainnet.safe.global NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-mainnet.safe.global
NEXT_PUBLIC_SAVE_ON_GAS_ENABLED=true NEXT_PUBLIC_SAVE_ON_GAS_ENABLED=true
NEXT_PUBLIC_SEO_ENHANCED_DATA_ENABLED=true
NEXT_PUBLIC_STATS_API_HOST=https://stats-eth-main.k8s-prod-1.blockscout.com NEXT_PUBLIC_STATS_API_HOST=https://stats-eth-main.k8s-prod-1.blockscout.com
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES=[{'name':'Rarible','collection_url':'https://rarible.com/collection/{hash}/items','instance_url':'https://rarible.com/token/{hash}:{id}','logo_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/nft-marketplace-logos/rarible.png'},{'name':'Blur','collection_url':'https://blur.io/eth/collection/{hash}','instance_url':'https://blur.io/eth/asset/{hash}/{id}','logo_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/nft-marketplace-logos/blur.png'},{'name':'Nftrade','collection_url':'https://nftrade.com/assets/eth/{hash}','instance_url':'https://nftrade.com/assets/eth/{hash}/{id}','logo_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/nft-marketplace-logos/nftrade.png'},{'name':'MagicEden','collection_url':'https://magiceden.io/collections/ethereum/{hash}','instance_url':'https://magiceden.io/item-details/ethereum/{hash}/{id}','logo_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/nft-marketplace-logos/magiceden.png'}]
NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED=true
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.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 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
\ No newline at end of file
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/hiddenBlockBadge
\ No newline at end of file
...@@ -14,14 +14,15 @@ NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "632019", "width": "728", "height ...@@ -14,14 +14,15 @@ NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={ "id": "632019", "width": "728", "height
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "632018", "width": "320", "height": "100" } NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={ "id": "632018", "width": "320", "height": "100" }
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com
NEXT_PUBLIC_API_BASE_PATH=/ NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_HOST=eth-sepolia.k8s-dev.blockscout.com NEXT_PUBLIC_API_HOST=eth-sepolia.blockscout.com
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
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_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_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com
NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED=true NEXT_PUBLIC_DATA_AVAILABILITY_ENABLED=true
NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'cow-swap'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'}] NEXT_PUBLIC_DEFI_DROPDOWN_ITEMS=[{'text':'Swap','icon':'swap','dappId':'cow-swap'},{'text':'Payment link','icon':'payment_link','dappId':'peanut-protocol'}]
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-sepolia.json 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_FOOTER_LINKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/footer-links/sepolia.json
NEXT_PUBLIC_GAME_BADGE_CLAIM_LINK=https://badges.blockscout.com/mint/sherblockHolmesBadge
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xbf69c7abc4fee283b59a9633dadfdaedde5c5ee0fba3e80a08b5b8a3acbd4363 NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xbf69c7abc4fee283b59a9633dadfdaedde5c5ee0fba3e80a08b5b8a3acbd4363
NEXT_PUBLIC_HAS_BEACON_CHAIN=true NEXT_PUBLIC_HAS_BEACON_CHAIN=true
NEXT_PUBLIC_HAS_USER_OPS=true NEXT_PUBLIC_HAS_USER_OPS=true
...@@ -30,12 +31,11 @@ NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['rgba(51, 53, 67, 1)'],'t ...@@ -30,12 +31,11 @@ NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['rgba(51, 53, 67, 1)'],'t
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_IS_TESTNET=true NEXT_PUBLIC_IS_TESTNET=true
NEXT_PUBLIC_LOGOUT_URL=https://blockscout-goerli.us.auth0.com/v2/logout NEXT_PUBLIC_LOGOUT_URL=https://blockscout-goerli.us.auth0.com/v2/logout
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=<p>Participated in our recent Blockscout activities? <a href="https://badges.blockscout.com?utm_source=instance&utm_medium=sepolia" target="_blank">Check your eligibility</a> and claim your NFT Scout badges. More exciting things are coming soon!</p> NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE=<p>Joined recent campaigns? Mint your Merit Badge <a href="https://badges.blockscout.com?utm_source=instance&utm_medium=sepolia">here</a></p>
NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maikReal/974c47f86a3158c1a86b092ae2f044b3/raw/abcc7e02150cd85d4974503a0357162c0a2c35a9/merits-banner.html NEXT_PUBLIC_MARKETPLACE_BANNER_CONTENT_URL=https://gist.githubusercontent.com/maikReal/974c47f86a3158c1a86b092ae2f044b3/raw/abcc7e02150cd85d4974503a0357162c0a2c35a9/merits-banner.html
NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://swap.blockscout.com?utm_source=blockscout&utm_medium=eth-sepolia NEXT_PUBLIC_MARKETPLACE_BANNER_LINK_URL=https://swap.blockscout.com?utm_source=blockscout&utm_medium=eth-sepolia
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-categories/default.json 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_ENABLED=true
NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_API_KEY=patbqG4V2CI998jAq.9810c58c9de973ba2650621c94559088cbdfa1a914498e385621ed035d33c0d0
NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs NEXT_PUBLIC_MARKETPLACE_RATING_AIRTABLE_BASE_ID=appGkvtmKI7fXE4Vs
NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-security-reports/default.json NEXT_PUBLIC_MARKETPLACE_SECURITY_REPORTS_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/marketplace-security-reports/default.json
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://airtable.com/appiy5yijZpMMSKjT/shr6uMGPKjj1DK7NL
...@@ -62,11 +62,10 @@ NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation ...@@ -62,11 +62,10 @@ NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true
NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/sepolia-testnet.png NEXT_PUBLIC_OG_IMAGE_URL=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/og-images/sepolia-testnet.png
NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://sepolia.drpc.org?ref=559183','text':'Public RPC'}] 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_REWARDS_SERVICE_API_HOST=https://merits.blockscout.com
NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-sepolia.safe.global NEXT_PUBLIC_SAFE_TX_SERVICE_URL=https://safe-transaction-sepolia.safe.global
NEXT_PUBLIC_STATS_API_HOST=https://stats-sepolia.k8s.blockscout.com NEXT_PUBLIC_STATS_API_HOST=https://stats-sepolia.k8s-prod-2.blockscout.com
NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=noves NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.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 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
\ No newline at end of file
NEXT_PUBLIC_DEX_POOLS_ENABLED=true
...@@ -87,8 +87,11 @@ download_and_save_asset() { ...@@ -87,8 +87,11 @@ download_and_save_asset() {
else else
# Check if the value is a URL # Check if the value is a URL
if [[ "$url" == http* ]]; then if [[ "$url" == http* ]]; then
# Download the asset using curl # Download the asset using curl with timeouts
curl -s -o "$destination" "$url" if ! curl -f -s --connect-timeout 5 --max-time 15 -o "$destination" "$url"; then
echo " [-] $env_var: Failed to download from $url (timeout or connection error)"
return 1
fi
else else
# Convert single-quoted JSON-like content to valid JSON # Convert single-quoted JSON-like content to valid JSON
json_content=$(echo "${!env_var}" | sed "s/'/\"/g") json_content=$(echo "${!env_var}" | sed "s/'/\"/g")
......
...@@ -32,14 +32,20 @@ if (process.env.NEXT_PUBLIC_OG_IMAGE_URL) { ...@@ -32,14 +32,20 @@ if (process.env.NEXT_PUBLIC_OG_IMAGE_URL) {
console.log('⏳ Making request to OG image generator service...'); console.log('⏳ Making request to OG image generator service...');
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 30_000);
const response = await fetch('https://bigs.services.blockscout.com/generate/og', { const response = await fetch('https://bigs.services.blockscout.com/generate/og', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify(data), body: JSON.stringify(data),
signal: controller.signal,
}); });
clearTimeout(timeoutId);
if (response.ok) { if (response.ok) {
console.log('⬇️ Downloading the image...'); console.log('⬇️ Downloading the image...');
const buffer = await response.arrayBuffer(); const buffer = await response.arrayBuffer();
......
...@@ -141,40 +141,32 @@ function getEnvsPlaceholders(filePath: string): Promise<Array<string>> { ...@@ -141,40 +141,32 @@ function getEnvsPlaceholders(filePath: string): Promise<Array<string>> {
function printDeprecationWarning(envsMap: Record<string, string>) { function printDeprecationWarning(envsMap: Record<string, string>) {
if (envsMap.NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY && envsMap.NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY) { if (envsMap.NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY && envsMap.NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
console.warn('The NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY variable is now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY variable.'); console.warn('❗ The NEXT_PUBLIC_RE_CAPTCHA_V3_APP_SITE_KEY variable is now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY variable.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
} }
if ( if (
(envsMap.NEXT_PUBLIC_SENTRY_DSN || envsMap.SENTRY_CSP_REPORT_URI || envsMap.NEXT_PUBLIC_SENTRY_ENABLE_TRACING) && (envsMap.NEXT_PUBLIC_SENTRY_DSN || envsMap.SENTRY_CSP_REPORT_URI || envsMap.NEXT_PUBLIC_SENTRY_ENABLE_TRACING) &&
envsMap.NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN envsMap.NEXT_PUBLIC_ROLLBAR_CLIENT_TOKEN
) { ) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
console.warn('The Sentry monitoring is now deprecated and will be removed in the next release. Please migrate to the Rollbar error monitoring.'); console.warn('❗ The Sentry monitoring is now deprecated and will be removed in the next release. Please migrate to the Rollbar error monitoring.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
} }
if ( if (
envsMap.NEXT_PUBLIC_ROLLUP_PARENT_CHAIN_NAME || envsMap.NEXT_PUBLIC_ROLLUP_PARENT_CHAIN_NAME ||
envsMap.NEXT_PUBLIC_ROLLUP_L1_BASE_URL envsMap.NEXT_PUBLIC_ROLLUP_L1_BASE_URL
) { ) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
console.warn('The NEXT_PUBLIC_ROLLUP_L1_BASE_URL and NEXT_PUBLIC_ROLLUP_PARENT_CHAIN_NAME variables are now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_ROLLUP_PARENT_CHAIN variable.'); console.warn('❗ The NEXT_PUBLIC_ROLLUP_L1_BASE_URL and NEXT_PUBLIC_ROLLUP_PARENT_CHAIN_NAME variables are now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_ROLLUP_PARENT_CHAIN variable.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
} }
if ( if (
envsMap.NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR || envsMap.NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR ||
envsMap.NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND envsMap.NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND
) { ) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
console.warn('The NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR and NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND variables are now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG variable.'); console.warn('❗ The NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR and NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND variables are now deprecated and will be removed in the next release. Please migrate to the NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG variable.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
} }
if ( if (
...@@ -182,10 +174,8 @@ function printDeprecationWarning(envsMap: Record<string, string>) { ...@@ -182,10 +174,8 @@ function printDeprecationWarning(envsMap: Record<string, string>) {
envsMap.NEXT_PUBLIC_AUTH_URL || envsMap.NEXT_PUBLIC_AUTH_URL ||
envsMap.NEXT_PUBLIC_LOGOUT_URL envsMap.NEXT_PUBLIC_LOGOUT_URL
) { ) {
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗');
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
console.warn('The NEXT_PUBLIC_AUTH0_CLIENT_ID, NEXT_PUBLIC_AUTH_URL and NEXT_PUBLIC_LOGOUT_URL variables are now deprecated and will be removed in the next release.'); console.warn('❗ The NEXT_PUBLIC_AUTH0_CLIENT_ID, NEXT_PUBLIC_AUTH_URL and NEXT_PUBLIC_LOGOUT_URL variables are now deprecated and will be removed in the next release.');
console.log('❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗\n');
} }
} }
......
...@@ -6,15 +6,27 @@ const stripTrailingSlash = (str) => str[str.length - 1] === '/' ? str.slice(0, - ...@@ -6,15 +6,27 @@ const stripTrailingSlash = (str) => str[str.length - 1] === '/' ? str.slice(0, -
const fetchResource = async(url, formatter) => { const fetchResource = async(url, formatter) => {
console.log('🌀 [next-sitemap] Fetching resource:', url); console.log('🌀 [next-sitemap] Fetching resource:', url);
try { try {
const res = await fetch(url); const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 15_000);
const res = await fetch(url, {
signal: controller.signal,
});
clearTimeout(timeoutId);
if (res.ok) { if (res.ok) {
const data = await res.json(); const data = await res.json();
console.log('✅ [next-sitemap] Data fetched for resource:', url); console.log('✅ [next-sitemap] Data fetched for resource:', url);
return formatter(data); return formatter(data);
} }
} catch (error) { } catch (error) {
if (error.name === 'AbortError') {
console.log('🚨 [next-sitemap] Request timeout for resource:', url);
} else {
console.log('🚨 [next-sitemap] Error fetching resource:', url, error); console.log('🚨 [next-sitemap] Error fetching resource:', url, error);
} }
}
}; };
const siteUrl = [ const siteUrl = [
...@@ -42,6 +54,15 @@ module.exports = { ...@@ -42,6 +54,15 @@ module.exports = {
siteUrl, siteUrl,
generateIndexSitemap: false, generateIndexSitemap: false,
generateRobotsTxt: true, generateRobotsTxt: true,
robotsTxtOptions: {
policies: [
{
userAgent: '*',
allow: '/',
disallow: ['/auth/*', '/login', '/sprite', '/account/*', '/api/*', '/node-api/*'],
},
],
},
sourceDir: path.resolve(process.cwd(), '../../../.next'), sourceDir: path.resolve(process.cwd(), '../../../.next'),
outDir: path.resolve(process.cwd(), '../../../public'), outDir: path.resolve(process.cwd(), '../../../public'),
exclude: [ exclude: [
......
...@@ -283,7 +283,7 @@ Settings for meta tags, OG tags and SEO ...@@ -283,7 +283,7 @@ Settings for meta tags, OG tags and SEO
#### Token views #### Token views
| Variable | Type | Description | Compulsoriness | Default value | Example value | Version | | Variable | Type | Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED | `boolean` | Show the "Hide scam tokens" toggle in the site settings dropdown. This option controls the visibility of tokens with a poor reputation in the search results. | - | - | `'["value","tx_fee"]'` | v1.38.0+ | | NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED | `boolean` | Show the "Hide scam tokens" toggle in the site settings dropdown. This option controls the visibility of tokens with a poor reputation in the search results. | - | `false` | `true` | v1.38.0+ |
&nbsp; &nbsp;
......
...@@ -2,12 +2,18 @@ import { getAddress } from 'viem'; ...@@ -2,12 +2,18 @@ import { getAddress } from 'viem';
import config from 'configs/app'; import config from 'configs/app';
const ERC1191_CHAIN_IDS = [
'30', // RSK Mainnet
'31', // RSK Testnet
];
export default function getCheckedSummedAddress(address: string): string { export default function getCheckedSummedAddress(address: string): string {
try { try {
return getAddress( return getAddress(
address, address,
// We need to pass chainId to getAddress to make it work correctly for some chains, e.g. Rootstock // We need to pass chainId to getAddress to make it work correctly for chains that support ERC-1191
config.chain.id ? Number(config.chain.id) : undefined, // https://eips.ethereum.org/EIPS/eip-1191#usage--table
ERC1191_CHAIN_IDS.includes(config.chain.id ?? '') ? Number(config.chain.id) : undefined,
); );
} catch (error) { } catch (error) {
return address; return address;
......
...@@ -635,7 +635,7 @@ export const RESOURCES = { ...@@ -635,7 +635,7 @@ export const RESOURCES = {
filterFields: [], filterFields: [],
}, },
address_xstar_score: { address_xstar_score: {
path: '/api/v2/proxy/3rdparty/xname/addresses/:hash', path: '/api/v2/proxy/3dparty/xname/addresses/:hash',
pathParams: [ 'hash' as const ], pathParams: [ 'hash' as const ],
}, },
...@@ -1090,16 +1090,16 @@ export const RESOURCES = { ...@@ -1090,16 +1090,16 @@ export const RESOURCES = {
// NOVES-FI // NOVES-FI
noves_transaction: { noves_transaction: {
path: '/api/v2/proxy/3rdparty/noves-fi/transactions/:hash', path: '/api/v2/proxy/3dparty/noves-fi/transactions/:hash',
pathParams: [ 'hash' as const ], pathParams: [ 'hash' as const ],
}, },
noves_address_history: { noves_address_history: {
path: '/api/v2/proxy/3rdparty/noves-fi/addresses/:address/transactions', path: '/api/v2/proxy/3dparty/noves-fi/addresses/:address/transactions',
pathParams: [ 'address' as const ], pathParams: [ 'address' as const ],
filterFields: [], filterFields: [],
}, },
noves_describe_txs: { noves_describe_txs: {
path: '/api/v2/proxy/3rdparty/noves-fi/transaction-descriptions', path: '/api/v2/proxy/3dparty/noves-fi/transaction-descriptions',
}, },
// USER OPS // USER OPS
......
import React from 'react';
import type { AddEthereumChainParameter } from 'viem';
import config from 'configs/app';
import useProvider from './useProvider';
import { getHexadecimalChainId } from './utils';
function getParams(): AddEthereumChainParameter {
if (!config.chain.id) {
throw new Error('Missing required chain config');
}
return {
chainId: getHexadecimalChainId(Number(config.chain.id)),
chainName: config.chain.name ?? '',
nativeCurrency: {
name: config.chain.currency.name ?? '',
symbol: config.chain.currency.symbol ?? '',
decimals: config.chain.currency.decimals ?? 18,
},
rpcUrls: config.chain.rpcUrls,
blockExplorerUrls: [ config.app.baseUrl ],
};
}
export default function useAddChain() {
const { wallet, provider } = useProvider();
return React.useCallback(() => {
if (!wallet || !provider) {
throw new Error('Wallet or provider not found');
}
return provider.request({
method: 'wallet_addEthereumChain',
params: [ getParams() ],
});
}, [ wallet, provider ]);
}
import React from 'react';
import config from 'configs/app';
import useProvider from './useProvider';
import { getHexadecimalChainId } from './utils';
function getParams(): { chainId: string } {
if (!config.chain.id) {
throw new Error('Missing required chain config');
}
return { chainId: getHexadecimalChainId(Number(config.chain.id)) };
}
export default function useSwitchChain() {
const { wallet, provider } = useProvider();
return React.useCallback(() => {
if (!wallet || !provider) {
throw new Error('Wallet or provider not found');
}
return provider.request({
method: 'wallet_switchEthereumChain',
params: [ getParams() ],
});
}, [ wallet, provider ]);
}
import { get } from 'es-toolkit/compat'; import { get } from 'es-toolkit/compat';
import React from 'react'; import React from 'react';
import config from 'configs/app';
import getErrorObj from 'lib/errors/getErrorObj'; import getErrorObj from 'lib/errors/getErrorObj';
import useAddChain from './useAddChain';
import useProvider from './useProvider'; import useProvider from './useProvider';
import useSwitchChain from './useSwitchChain';
export default function useAddOrSwitchChain() { export default function useSwitchOrAddChain() {
const { wallet, provider } = useProvider(); const { wallet, provider } = useProvider();
const addChain = useAddChain();
const switchChain = useSwitchChain();
return React.useCallback(async() => { return React.useCallback(async() => {
if (!wallet || !provider) { if (!wallet || !provider) {
return; return;
} }
const hexadecimalChainId = '0x' + Number(config.chain.id).toString(16);
try { try {
return await provider.request({ return switchChain();
method: 'wallet_switchEthereumChain',
params: [ { chainId: hexadecimalChainId } ],
});
} catch (error) { } catch (error) {
const errorObj = getErrorObj(error); const errorObj = getErrorObj(error);
const code = errorObj && 'code' in errorObj ? errorObj.code : undefined; const code = get(errorObj, 'code');
const originalErrorCode = get(errorObj, 'data.originalError.code'); const originalErrorCode = get(errorObj, 'data.originalError.code');
// This error code indicates that the chain has not been added to Wallet. // This error code indicates that the chain has not been added to Wallet.
if (code === 4902 || originalErrorCode === 4902) { if (code === 4902 || originalErrorCode === 4902) {
const params = [ { return addChain();
chainId: hexadecimalChainId,
chainName: config.chain.name,
nativeCurrency: {
name: config.chain.currency.name,
symbol: config.chain.currency.symbol,
decimals: config.chain.currency.decimals,
},
rpcUrls: config.chain.rpcUrls,
blockExplorerUrls: [ config.app.baseUrl ],
} ] as never;
// in wagmi types for wallet_addEthereumChain method is not provided
return await provider.request({
method: 'wallet_addEthereumChain',
params: params,
});
} }
throw error; throw error;
} }
}, [ provider, wallet ]); }, [ addChain, provider, wallet, switchChain ]);
} }
export function getHexadecimalChainId(chainId: number) {
return '0x' + Number(chainId).toString(16);
}
...@@ -82,7 +82,6 @@ export const token: Address = { ...@@ -82,7 +82,6 @@ export const token: Address = {
creation_transaction_hash: '0xc38cf7377bf72d6436f63c37b01b24d032101f20ec1849286dc703c712f10c98', creation_transaction_hash: '0xc38cf7377bf72d6436f63c37b01b24d032101f20ec1849286dc703c712f10c98',
creator_address_hash: '0x34A9c688512ebdB575e82C50c9803F6ba2916E72', creator_address_hash: '0x34A9c688512ebdB575e82C50c9803F6ba2916E72',
exchange_rate: '0.04311', exchange_rate: '0.04311',
has_decompiled_code: false,
has_logs: false, has_logs: false,
has_token_transfers: true, has_token_transfers: true,
has_tokens: true, has_tokens: true,
...@@ -96,7 +95,6 @@ export const eoa: Address = { ...@@ -96,7 +95,6 @@ export const eoa: Address = {
creation_transaction_hash: '0xf2aff6501b632604c39978b47d309813d8a1bcca721864bbe86abf59704f195e', creation_transaction_hash: '0xf2aff6501b632604c39978b47d309813d8a1bcca721864bbe86abf59704f195e',
creator_address_hash: '0x803ad3F50b9e1fF68615e8B053A186e1be288943', creator_address_hash: '0x803ad3F50b9e1fF68615e8B053A186e1be288943',
exchange_rate: '0.04311', exchange_rate: '0.04311',
has_decompiled_code: false,
has_logs: true, has_logs: true,
has_token_transfers: false, has_token_transfers: false,
has_tokens: true, has_tokens: true,
...@@ -120,7 +118,6 @@ export const contract: Address = { ...@@ -120,7 +118,6 @@ export const contract: Address = {
creation_transaction_hash: '0xf2aff6501b632604c39978b47d309813d8a1bcca721864bbe86abf59704f195e', creation_transaction_hash: '0xf2aff6501b632604c39978b47d309813d8a1bcca721864bbe86abf59704f195e',
creator_address_hash: '0x803ad3F50b9e1fF68615e8B053A186e1be288943', creator_address_hash: '0x803ad3F50b9e1fF68615e8B053A186e1be288943',
exchange_rate: '0.04311', exchange_rate: '0.04311',
has_decompiled_code: false,
has_logs: true, has_logs: true,
has_token_transfers: false, has_token_transfers: false,
has_tokens: false, has_tokens: false,
...@@ -146,7 +143,6 @@ export const validator: Address = { ...@@ -146,7 +143,6 @@ export const validator: Address = {
creation_transaction_hash: null, creation_transaction_hash: null,
creator_address_hash: null, creator_address_hash: null,
exchange_rate: '0.00432018', exchange_rate: '0.00432018',
has_decompiled_code: false,
has_logs: false, has_logs: false,
has_token_transfers: false, has_token_transfers: false,
has_tokens: false, has_tokens: false,
......
...@@ -46,7 +46,7 @@ Promise<GetServerSidePropsResult<Props<Pathname>>> => { ...@@ -46,7 +46,7 @@ Promise<GetServerSidePropsResult<Props<Pathname>>> => {
const isTrackingDisabled = process.env.DISABLE_TRACKING === 'true'; const isTrackingDisabled = process.env.DISABLE_TRACKING === 'true';
if (!isTrackingDisabled) { if (!isTrackingDisabled && !config.app.isDev) {
// log pageview // log pageview
const hostname = req.headers.host; const hostname = req.headers.host;
const timestamp = new Date().toISOString(); const timestamp = new Date().toISOString();
......
...@@ -15,4 +15,4 @@ const Page: NextPage = () => { ...@@ -15,4 +15,4 @@ const Page: NextPage = () => {
export default Page; export default Page;
export { dev as getServerSideProps } from 'nextjs/getServerSideProps'; export { base as getServerSideProps } from 'nextjs/getServerSideProps';
...@@ -22,7 +22,6 @@ export const ADDRESS_INFO: Address = { ...@@ -22,7 +22,6 @@ export const ADDRESS_INFO: Address = {
creation_transaction_hash: null, creation_transaction_hash: null,
creator_address_hash: ADDRESS_HASH, creator_address_hash: ADDRESS_HASH,
exchange_rate: null, exchange_rate: null,
has_decompiled_code: false,
has_logs: true, has_logs: true,
has_token_transfers: false, has_token_transfers: false,
has_tokens: false, has_tokens: false,
......
...@@ -4,13 +4,21 @@ import { ThemeProvider, useTheme } from 'next-themes'; ...@@ -4,13 +4,21 @@ import { ThemeProvider, useTheme } from 'next-themes';
import type { ThemeProviderProps } from 'next-themes'; import type { ThemeProviderProps } from 'next-themes';
import * as React from 'react'; import * as React from 'react';
import config from 'configs/app';
export interface ColorModeProviderProps extends ThemeProviderProps {} export interface ColorModeProviderProps extends ThemeProviderProps {}
export type ColorMode = 'light' | 'dark'; export type ColorMode = 'light' | 'dark';
export function ColorModeProvider(props: ColorModeProviderProps) { export function ColorModeProvider(props: ColorModeProviderProps) {
return ( return (
<ThemeProvider attribute="class" scriptProps={{ 'data-cfasync': 'false' }} disableTransitionOnChange { ...props }/> <ThemeProvider
attribute="class"
scriptProps={{ 'data-cfasync': 'false' }}
enableSystem={ false }
defaultTheme={ config.UI.colorTheme.default?.colorMode }
disableTransitionOnChange { ...props }
/>
); );
} }
......
...@@ -20,7 +20,6 @@ export interface Address extends UserTags { ...@@ -20,7 +20,6 @@ export interface Address extends UserTags {
zilliqa?: AddressZilliqaParams; zilliqa?: AddressZilliqaParams;
// TODO: if we are happy with tabs-counters method, should we delete has_something fields? // TODO: if we are happy with tabs-counters method, should we delete has_something fields?
has_beacon_chain_withdrawals?: boolean; has_beacon_chain_withdrawals?: boolean;
has_decompiled_code: boolean;
has_logs: boolean; has_logs: boolean;
has_token_transfers: boolean; has_token_transfers: boolean;
has_tokens: boolean; has_tokens: boolean;
......
...@@ -172,8 +172,8 @@ export interface BlockEpoch { ...@@ -172,8 +172,8 @@ export interface BlockEpoch {
carbon_offsetting_transfer: TokenTransfer | null; carbon_offsetting_transfer: TokenTransfer | null;
community_transfer: TokenTransfer | null; community_transfer: TokenTransfer | null;
reserve_bolster_transfer: TokenTransfer | null; reserve_bolster_transfer: TokenTransfer | null;
}; } | null;
aggregated_election_rewards: Record<EpochRewardsType, BlockEpochElectionReward | null>; aggregated_election_rewards: Record<EpochRewardsType, BlockEpochElectionReward | null> | null;
} }
export interface BlockEpochElectionRewardDetails { export interface BlockEpochElectionRewardDetails {
......
...@@ -15,10 +15,10 @@ export type Pool = { ...@@ -15,10 +15,10 @@ export type Pool = {
quote_token_address: string; quote_token_address: string;
quote_token_symbol: string; quote_token_symbol: string;
quote_token_icon_url: string | null; quote_token_icon_url: string | null;
base_token_fully_diluted_valuation_usd: string; base_token_fully_diluted_valuation_usd: string | null;
base_token_market_cap_usd: string; base_token_market_cap_usd: string | null;
quote_token_fully_diluted_valuation_usd: string; quote_token_fully_diluted_valuation_usd: string | null;
quote_token_market_cap_usd: string; quote_token_market_cap_usd: string | null;
liquidity: string; liquidity: string;
dex: { dex: {
id: string; id: string;
......
...@@ -10,7 +10,7 @@ interface Props { ...@@ -10,7 +10,7 @@ interface Props {
} }
const ContractDetailsAlertVerificationSource = ({ data }: Props) => { const ContractDetailsAlertVerificationSource = ({ data }: Props) => {
if (data?.is_verified_via_eth_bytecode_db) { if (data?.is_verified && data?.is_verified_via_eth_bytecode_db) {
return ( return (
<Alert status="warning" whiteSpace="pre-wrap"> <Alert status="warning" whiteSpace="pre-wrap">
<span>This contract has been { data.is_partially_verified ? 'partially ' : '' }verified using </span> <span>This contract has been { data.is_partially_verified ? 'partially ' : '' }verified using </span>
...@@ -25,7 +25,7 @@ const ContractDetailsAlertVerificationSource = ({ data }: Props) => { ...@@ -25,7 +25,7 @@ const ContractDetailsAlertVerificationSource = ({ data }: Props) => {
); );
} }
if (data?.is_verified_via_sourcify) { if (data?.is_verified && data?.is_verified_via_sourcify) {
return ( return (
<Alert status="warning" whiteSpace="pre-wrap"> <Alert status="warning" whiteSpace="pre-wrap">
<span>This contract has been { data.is_partially_verified ? 'partially ' : '' }verified via Sourcify. </span> <span>This contract has been { data.is_partially_verified ? 'partially ' : '' }verified via Sourcify. </span>
......
...@@ -77,7 +77,6 @@ export default function useAddressQuery({ hash, isEnabled = true }: Params): Add ...@@ -77,7 +77,6 @@ export default function useAddressQuery({ hash, isEnabled = true }: Params): Add
creation_transaction_hash: null, creation_transaction_hash: null,
exchange_rate: null, exchange_rate: null,
ens_domain_name: null, ens_domain_name: null,
has_decompiled_code: false,
has_logs: false, has_logs: false,
has_token_transfers: false, has_token_transfers: false,
has_tokens: false, has_tokens: false,
......
...@@ -25,7 +25,7 @@ const BlockEpochRewards = ({ heightOrHash }: Props) => { ...@@ -25,7 +25,7 @@ const BlockEpochRewards = ({ heightOrHash }: Props) => {
return <DataFetchAlert/>; return <DataFetchAlert/>;
} }
if (!query.data) { if (!query.data || (!query.data.aggregated_election_rewards && !query.data.distribution)) {
return <span>No block epoch rewards data</span>; return <span>No block epoch rewards data</span>;
} }
......
...@@ -15,6 +15,10 @@ interface Props { ...@@ -15,6 +15,10 @@ interface Props {
} }
const BlockEpochElectionRewards = ({ data, isLoading }: Props) => { const BlockEpochElectionRewards = ({ data, isLoading }: Props) => {
if (!data.aggregated_election_rewards) {
return null;
}
return ( return (
<Box mt={ 8 }> <Box mt={ 8 }>
<Heading level="3" mb={ 3 }>Election rewards</Heading> <Heading level="3" mb={ 3 }>Election rewards</Heading>
......
...@@ -15,6 +15,10 @@ interface Props { ...@@ -15,6 +15,10 @@ interface Props {
const BlockEpochRewardsDistribution = ({ data, isLoading }: Props) => { const BlockEpochRewardsDistribution = ({ data, isLoading }: Props) => {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
if (!data.distribution) {
return null;
}
if (!data.distribution.community_transfer && !data.distribution.carbon_offsetting_transfer && !data.distribution.reserve_bolster_transfer) { if (!data.distribution.community_transfer && !data.distribution.carbon_offsetting_transfer && !data.distribution.reserve_bolster_transfer) {
return null; return null;
} }
......
import type { BlockEpoch } from 'types/api/block'; import type { BlockEpoch } from 'types/api/block';
import type { ExcludeNull } from 'types/utils';
export function getRewardNumText(type: keyof BlockEpoch['aggregated_election_rewards'], num: number) { export function getRewardNumText(type: keyof BlockEpoch['aggregated_election_rewards'], num: number) {
const postfix1 = num !== 1 ? 's' : ''; const postfix1 = num !== 1 ? 's' : '';
...@@ -26,7 +27,7 @@ export function getRewardNumText(type: keyof BlockEpoch['aggregated_election_rew ...@@ -26,7 +27,7 @@ export function getRewardNumText(type: keyof BlockEpoch['aggregated_election_rew
return `${ num } ${ text }`; return `${ num } ${ text }`;
} }
export function getRewardDetailsTableTitles(type: keyof BlockEpoch['aggregated_election_rewards']): [string, string] { export function getRewardDetailsTableTitles(type: keyof ExcludeNull<BlockEpoch['aggregated_election_rewards']>): [string, string] {
switch (type) { switch (type) {
case 'delegated_payment': case 'delegated_payment':
return [ 'Beneficiary', 'Validator' ]; return [ 'Beneficiary', 'Validator' ];
...@@ -39,6 +40,6 @@ export function getRewardDetailsTableTitles(type: keyof BlockEpoch['aggregated_e ...@@ -39,6 +40,6 @@ export function getRewardDetailsTableTitles(type: keyof BlockEpoch['aggregated_e
} }
} }
export function formatRewardType(type: keyof BlockEpoch['aggregated_election_rewards']) { export function formatRewardType(type: keyof ExcludeNull<BlockEpoch['aggregated_election_rewards']>) {
return type.replaceAll('_', '-'); return type.replaceAll('_', '-');
} }
...@@ -43,6 +43,9 @@ const UserOp = () => { ...@@ -43,6 +43,9 @@ const UserOp = () => {
if (!userOpQuery.data) { if (!userOpQuery.data) {
return true; return true;
} else { } else {
if (!userOpQuery.data.user_logs_start_index || !userOpQuery.data.user_logs_count) {
return false;
}
if (inRange( if (inRange(
Number(tt.log_index), Number(tt.log_index),
userOpQuery.data?.user_logs_start_index, userOpQuery.data?.user_logs_start_index,
...@@ -58,6 +61,9 @@ const UserOp = () => { ...@@ -58,6 +61,9 @@ const UserOp = () => {
if (!userOpQuery.data) { if (!userOpQuery.data) {
return true; return true;
} else { } else {
if (!userOpQuery.data.user_logs_start_index || !userOpQuery.data.user_logs_count) {
return false;
}
if (inRange(log.index, userOpQuery.data?.user_logs_start_index, userOpQuery.data?.user_logs_start_index + userOpQuery.data?.user_logs_count)) { if (inRange(log.index, userOpQuery.data?.user_logs_start_index, userOpQuery.data?.user_logs_start_index + userOpQuery.data?.user_logs_count)) {
return true; return true;
} }
......
...@@ -67,7 +67,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => { ...@@ -67,7 +67,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
</DetailedInfo.ItemLabel> </DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue> <DetailedInfo.ItemValue>
<Skeleton loading={ isPlaceholderData }> <Skeleton loading={ isPlaceholderData }>
${ Number(data.base_token_fully_diluted_valuation_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) } { data.base_token_fully_diluted_valuation_usd ?
`$${ Number(data.base_token_fully_diluted_valuation_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }` :
'N/A'
}
</Skeleton> </Skeleton>
</DetailedInfo.ItemValue> </DetailedInfo.ItemValue>
...@@ -79,7 +82,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => { ...@@ -79,7 +82,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
</DetailedInfo.ItemLabel> </DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue> <DetailedInfo.ItemValue>
<Skeleton loading={ isPlaceholderData }> <Skeleton loading={ isPlaceholderData }>
${ Number(data.base_token_market_cap_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) } { data.base_token_market_cap_usd ?
`$${ Number(data.base_token_market_cap_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }` :
'N/A'
}
</Skeleton> </Skeleton>
</DetailedInfo.ItemValue> </DetailedInfo.ItemValue>
...@@ -91,7 +97,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => { ...@@ -91,7 +97,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
</DetailedInfo.ItemLabel> </DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue> <DetailedInfo.ItemValue>
<Skeleton loading={ isPlaceholderData }> <Skeleton loading={ isPlaceholderData }>
${ Number(data.quote_token_fully_diluted_valuation_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) } { data.quote_token_fully_diluted_valuation_usd ?
`$${ Number(data.quote_token_fully_diluted_valuation_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }` :
'N/A'
}
</Skeleton> </Skeleton>
</DetailedInfo.ItemValue> </DetailedInfo.ItemValue>
...@@ -103,7 +112,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => { ...@@ -103,7 +112,10 @@ const PoolInfo = ({ data, isPlaceholderData }: Props) => {
</DetailedInfo.ItemLabel> </DetailedInfo.ItemLabel>
<DetailedInfo.ItemValue> <DetailedInfo.ItemValue>
<Skeleton loading={ isPlaceholderData }> <Skeleton loading={ isPlaceholderData }>
${ Number(data.quote_token_market_cap_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) } { data.quote_token_market_cap_usd ?
`$${ Number(data.quote_token_market_cap_usd).toLocaleString(undefined, { maximumFractionDigits: 2, notation: 'compact' }) }` :
'N/A'
}
</Skeleton> </Skeleton>
</DetailedInfo.ItemValue> </DetailedInfo.ItemValue>
......
...@@ -2,8 +2,9 @@ import React from 'react'; ...@@ -2,8 +2,9 @@ import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import useAddOrSwitchChain from 'lib/web3/useAddOrSwitchChain'; import useAddChain from 'lib/web3/useAddChain';
import useProvider from 'lib/web3/useProvider'; import useProvider from 'lib/web3/useProvider';
import useSwitchChain from 'lib/web3/useSwitchChain';
import { WALLETS_INFO } from 'lib/web3/wallets'; import { WALLETS_INFO } from 'lib/web3/wallets';
import { Button } from 'toolkit/chakra/button'; import { Button } from 'toolkit/chakra/button';
import { toaster } from 'toolkit/chakra/toaster'; import { toaster } from 'toolkit/chakra/toaster';
...@@ -13,7 +14,8 @@ const feature = config.features.web3Wallet; ...@@ -13,7 +14,8 @@ const feature = config.features.web3Wallet;
const NetworkAddToWallet = () => { const NetworkAddToWallet = () => {
const { provider, wallet } = useProvider(); const { provider, wallet } = useProvider();
const addOrSwitchChain = useAddOrSwitchChain(); const addChain = useAddChain();
const switchChain = useSwitchChain();
const handleClick = React.useCallback(async() => { const handleClick = React.useCallback(async() => {
if (!wallet || !provider) { if (!wallet || !provider) {
...@@ -21,7 +23,8 @@ const NetworkAddToWallet = () => { ...@@ -21,7 +23,8 @@ const NetworkAddToWallet = () => {
} }
try { try {
await addOrSwitchChain(); await addChain();
await switchChain();
toaster.success({ toaster.success({
title: 'Success', title: 'Success',
...@@ -39,7 +42,7 @@ const NetworkAddToWallet = () => { ...@@ -39,7 +42,7 @@ const NetworkAddToWallet = () => {
description: (error as Error)?.message || 'Something went wrong', description: (error as Error)?.message || 'Something went wrong',
}); });
} }
}, [ addOrSwitchChain, provider, wallet ]); }, [ addChain, provider, wallet, switchChain ]);
if (!provider || !wallet || !config.chain.rpcUrls.length || !feature.isEnabled) { if (!provider || !wallet || !config.chain.rpcUrls.length || !feature.isEnabled) {
return null; return null;
......
...@@ -31,7 +31,7 @@ const init = () => { ...@@ -31,7 +31,7 @@ const init = () => {
projectId: feature.walletConnect.projectId, projectId: feature.walletConnect.projectId,
features: { features: {
analytics: false, analytics: false,
email: true, email: false,
socials: [], socials: [],
onramp: false, onramp: false,
swaps: false, swaps: false,
......
import { Box, chakra } from '@chakra-ui/react'; import { Box, chakra } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { WatchAssetParams } from 'viem';
import type { TokenInfo } from 'types/api/token'; import type { TokenInfo } from 'types/api/token';
import config from 'configs/app'; import config from 'configs/app';
import useIsMobile from 'lib/hooks/useIsMobile';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import useAddOrSwitchChain from 'lib/web3/useAddOrSwitchChain';
import useProvider from 'lib/web3/useProvider'; import useProvider from 'lib/web3/useProvider';
import useSwitchOrAddChain from 'lib/web3/useSwitchOrAddChain';
import { WALLETS_INFO } from 'lib/web3/wallets'; import { WALLETS_INFO } from 'lib/web3/wallets';
import { IconButton } from 'toolkit/chakra/icon-button'; import { IconButton } from 'toolkit/chakra/icon-button';
import { Skeleton } from 'toolkit/chakra/skeleton'; import { Skeleton } from 'toolkit/chakra/skeleton';
...@@ -16,17 +18,50 @@ import IconSvg from 'ui/shared/IconSvg'; ...@@ -16,17 +18,50 @@ import IconSvg from 'ui/shared/IconSvg';
const feature = config.features.web3Wallet; const feature = config.features.web3Wallet;
function getRequestParams(token: TokenInfo, tokenId?: string): WatchAssetParams | undefined {
switch (token.type) {
case 'ERC-20':
return {
type: 'ERC20',
options: {
address: token.address,
symbol: token.symbol || '',
decimals: Number(token.decimals) || 18,
image: token.icon_url || '',
},
};
case 'ERC-721':
case 'ERC-1155': {
if (!tokenId) {
return;
}
return {
type: token.type === 'ERC-721' ? 'ERC721' : 'ERC1155',
options: {
address: token.address,
tokenId: tokenId,
},
} as never; // There is no official EIP, and therefore no typings for these token types.
}
default:
return;
}
}
interface Props { interface Props {
className?: string; className?: string;
token: TokenInfo; token: TokenInfo;
tokenId?: string;
isLoading?: boolean; isLoading?: boolean;
variant?: 'icon' | 'button'; variant?: 'icon' | 'button';
iconSize?: number; iconSize?: number;
} }
const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', iconSize = 6 }: Props) => { const AddressAddToWallet = ({ className, token, tokenId, isLoading, variant = 'icon', iconSize = 6 }: Props) => {
const { provider, wallet } = useProvider(); const { provider, wallet } = useProvider();
const addOrSwitchChain = useAddOrSwitchChain(); const switchOrAddChain = useSwitchOrAddChain();
const isMobile = useIsMobile();
const handleClick = React.useCallback(async() => { const handleClick = React.useCallback(async() => {
if (!wallet) { if (!wallet) {
...@@ -34,20 +69,18 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico ...@@ -34,20 +69,18 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico
} }
try { try {
const params = getRequestParams(token, tokenId);
if (!params) {
throw new Error('Unsupported token type');
}
// switch to the correct network otherwise the token will be added to the wrong one // switch to the correct network otherwise the token will be added to the wrong one
await addOrSwitchChain(); await switchOrAddChain();
const wasAdded = await provider?.request?.({ const wasAdded = await provider?.request?.({
method: 'wallet_watchAsset', method: 'wallet_watchAsset',
params: { params,
type: 'ERC20', // Initially only supports ERC20, but eventually more!
options: {
address: token.address,
symbol: token.symbol || '',
decimals: Number(token.decimals) || 18,
image: token.icon_url || '',
},
},
}); });
if (wasAdded) { if (wasAdded) {
...@@ -68,7 +101,7 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico ...@@ -68,7 +101,7 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico
description: (error as Error)?.message || 'Something went wrong', description: (error as Error)?.message || 'Something went wrong',
}); });
} }
}, [ token, provider, wallet, addOrSwitchChain ]); }, [ wallet, token, tokenId, switchOrAddChain, provider ]);
if (!provider || !wallet) { if (!provider || !wallet) {
return null; return null;
...@@ -78,7 +111,16 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico ...@@ -78,7 +111,16 @@ const AddressAddToWallet = ({ className, token, isLoading, variant = 'icon', ico
return <Skeleton loading className={ className } boxSize={ iconSize } borderRadius="base"/>; return <Skeleton loading className={ className } boxSize={ iconSize } borderRadius="base"/>;
} }
if (!feature.isEnabled) { const canBeAdded = (
// MetaMask can add NFTs now, but this is still experimental feature, and doesn't work on mobile devices
// https://docs.metamask.io/wallet/how-to/display/tokens/#display-nfts
wallet === 'metamask' &&
[ 'ERC-721', 'ERC-1155' ].includes(token.type) &&
tokenId &&
!isMobile
) || token.type === 'ERC-20';
if (!feature.isEnabled || !canBeAdded) {
return null; return null;
} }
......
...@@ -12,7 +12,7 @@ interface Props extends FeaturedNetwork { ...@@ -12,7 +12,7 @@ interface Props extends FeaturedNetwork {
isMobile?: boolean; isMobile?: boolean;
} }
const NetworkMenuLink = ({ title, icon, isActive, isMobile, url, invertIconInDarkMode }: Props) => { const NetworkMenuLink = ({ title, icon, isActive: isActiveProp, isMobile, url, invertIconInDarkMode }: Props) => {
const darkModeFilter = { filter: 'brightness(0) invert(1)' }; const darkModeFilter = { filter: 'brightness(0) invert(1)' };
const style = useColorModeValue({}, invertIconInDarkMode ? darkModeFilter : {}); const style = useColorModeValue({}, invertIconInDarkMode ? darkModeFilter : {});
...@@ -26,6 +26,21 @@ const NetworkMenuLink = ({ title, icon, isActive, isMobile, url, invertIconInDar ...@@ -26,6 +26,21 @@ const NetworkMenuLink = ({ title, icon, isActive, isMobile, url, invertIconInDar
/> />
); );
const isActive = (() => {
if (isActiveProp !== undefined) {
return isActiveProp;
}
try {
const itemOrigin = new URL(url).origin;
const currentOrigin = window.location.origin;
return itemOrigin === currentOrigin;
} catch (error) {
return false;
}
})();
return ( return (
<Box as="li" listStyleType="none"> <Box as="li" listStyleType="none">
<chakra.a <chakra.a
......
...@@ -101,7 +101,7 @@ const TokenInstancePageTitle = ({ isLoading, token, instance, hash }: Props) => ...@@ -101,7 +101,7 @@ const TokenInstancePageTitle = ({ isLoading, token, instance, hash }: Props) =>
maxW="700px" maxW="700px"
/> />
) } ) }
{ !isLoading && token && <AddressAddToWallet token={ token } variant="button"/> } { !isLoading && token && <AddressAddToWallet token={ token } tokenId={ instance?.id } variant="button"/> }
<AddressQrCode hash={ address.hash } isLoading={ isLoading }/> <AddressQrCode hash={ address.hash } isLoading={ isLoading }/>
<AccountActionsMenu isLoading={ isLoading } showUpdateMetadataItem/> <AccountActionsMenu isLoading={ isLoading } showUpdateMetadataItem/>
{ appLink } { appLink }
......
...@@ -76,7 +76,9 @@ const TxsStats = () => { ...@@ -76,7 +76,9 @@ const TxsStats = () => {
> >
{ txCount24h && ( { txCount24h && (
<StatsWidget <StatsWidget
label={ txsStatsQuery.data?.transactions_24h?.title || 'Transactions' } label={ txsStatsQuery.data?.transactions_24h?.title ?
getLabelFromTitle(txsStatsQuery.data?.transactions_24h?.title) :
'Transactions' }
value={ Number(txCount24h).toLocaleString() } value={ Number(txCount24h).toLocaleString() }
period="24h" period="24h"
isLoading={ isLoading } isLoading={ isLoading }
...@@ -85,7 +87,9 @@ const TxsStats = () => { ...@@ -85,7 +87,9 @@ const TxsStats = () => {
) } ) }
{ operationalTxns24h && ( { operationalTxns24h && (
<StatsWidget <StatsWidget
label={ txsStatsQuery.data?.operational_transactions_24h?.title || 'Daily op txns' } label={ txsStatsQuery.data?.operational_transactions_24h?.title ?
getLabelFromTitle(txsStatsQuery.data?.operational_transactions_24h?.title) :
'Daily op txns' }
value={ Number(operationalTxns24h).toLocaleString() } value={ Number(operationalTxns24h).toLocaleString() }
period="24h" period="24h"
isLoading={ isLoading } isLoading={ isLoading }
...@@ -93,7 +97,9 @@ const TxsStats = () => { ...@@ -93,7 +97,9 @@ const TxsStats = () => {
) } ) }
{ pendingTxns && ( { pendingTxns && (
<StatsWidget <StatsWidget
label={ txsStatsQuery.data?.pending_transactions_30m?.title || 'Pending transactions' } label={ txsStatsQuery.data?.pending_transactions_30m?.title ?
getLabelFromTitle(txsStatsQuery.data?.pending_transactions_30m?.title) :
'Pending transactions' }
value={ Number(pendingTxns).toLocaleString() } value={ Number(pendingTxns).toLocaleString() }
period={ isStatsFeatureEnabled ? '30min' : '1h' } period={ isStatsFeatureEnabled ? '30min' : '1h' }
isLoading={ isLoading } isLoading={ isLoading }
...@@ -101,7 +107,9 @@ const TxsStats = () => { ...@@ -101,7 +107,9 @@ const TxsStats = () => {
) } ) }
{ txFeeSum24h && ( { txFeeSum24h && (
<StatsWidget <StatsWidget
label={ txsStatsQuery.data?.transactions_fee_24h?.title || 'Transactions fees' } label={ txsStatsQuery.data?.transactions_fee_24h?.title ?
getLabelFromTitle(txsStatsQuery.data?.transactions_fee_24h?.title) :
'Transactions fees' }
value={ txFeeSum24h.toLocaleString(undefined, { maximumFractionDigits: 2 }) } value={ txFeeSum24h.toLocaleString(undefined, { maximumFractionDigits: 2 }) }
valuePostfix={ thinsp + config.chain.currency.symbol } valuePostfix={ thinsp + config.chain.currency.symbol }
period="24h" period="24h"
...@@ -111,7 +119,9 @@ const TxsStats = () => { ...@@ -111,7 +119,9 @@ const TxsStats = () => {
) } ) }
{ txFeeAvg && ( { txFeeAvg && (
<StatsWidget <StatsWidget
label={ txsStatsQuery.data?.average_transactions_fee_24h?.title || 'Avg. transaction fee' } label={ txsStatsQuery.data?.average_transactions_fee_24h?.title ?
getLabelFromTitle(txsStatsQuery.data?.average_transactions_fee_24h?.title) :
'Avg. transaction fee' }
value={ txFeeAvg.usd ? txFeeAvg.usd : txFeeAvg.valueStr } value={ txFeeAvg.usd ? txFeeAvg.usd : txFeeAvg.valueStr }
valuePrefix={ txFeeAvg.usd ? '$' : undefined } valuePrefix={ txFeeAvg.usd ? '$' : undefined }
valuePostfix={ txFeeAvg.usd ? undefined : thinsp + config.chain.currency.symbol } valuePostfix={ txFeeAvg.usd ? undefined : thinsp + config.chain.currency.symbol }
...@@ -124,4 +134,9 @@ const TxsStats = () => { ...@@ -124,4 +134,9 @@ const TxsStats = () => {
); );
}; };
// remove period from title
function getLabelFromTitle(title: string) {
return title.replace(/\s*\([^)]*\)\s*$/, '');
}
export default React.memo(TxsStats); export default React.memo(TxsStats);
...@@ -14,6 +14,7 @@ import AddressEntity from 'ui/shared/entities/address/AddressEntity'; ...@@ -14,6 +14,7 @@ import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile'; import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip'; import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
import TruncatedValue from 'ui/shared/TruncatedValue';
interface Props { interface Props {
data: VerifiedContract; data: VerifiedContract;
...@@ -57,11 +58,12 @@ const VerifiedContractsListItem = ({ data, isLoading }: Props) => { ...@@ -57,11 +58,12 @@ const VerifiedContractsListItem = ({ data, isLoading }: Props) => {
flexShrink={ 0 } flexShrink={ 0 }
/> />
</Flex> </Flex>
<Flex columnGap={ 3 }> <Flex columnGap={ 3 } w="100%">
<Skeleton loading={ isLoading } fontWeight={ 500 }>Balance { currencyUnits.ether }</Skeleton> <Skeleton loading={ isLoading } fontWeight={ 500 } flexShrink="0">Balance { currencyUnits.ether }</Skeleton>
<Skeleton loading={ isLoading } color="text.secondary"> <TruncatedValue
<span>{ balance }</span> value={ balance }
</Skeleton> isLoading={ isLoading }
/>
</Flex> </Flex>
<Flex columnGap={ 3 }> <Flex columnGap={ 3 }>
<Skeleton loading={ isLoading } fontWeight={ 500 }>Txs count</Skeleton> <Skeleton loading={ isLoading } fontWeight={ 500 }>Txs count</Skeleton>
......
...@@ -14,6 +14,7 @@ import ContractCertifiedLabel from 'ui/shared/ContractCertifiedLabel'; ...@@ -14,6 +14,7 @@ import ContractCertifiedLabel from 'ui/shared/ContractCertifiedLabel';
import AddressEntity from 'ui/shared/entities/address/AddressEntity'; import AddressEntity from 'ui/shared/entities/address/AddressEntity';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip'; import TimeAgoWithTooltip from 'ui/shared/TimeAgoWithTooltip';
import TruncatedValue from 'ui/shared/TruncatedValue';
interface Props { interface Props {
data: VerifiedContract; data: VerifiedContract;
...@@ -59,9 +60,12 @@ const VerifiedContractsTableItem = ({ data, isLoading }: Props) => { ...@@ -59,9 +60,12 @@ const VerifiedContractsTableItem = ({ data, isLoading }: Props) => {
/> />
</TableCell> </TableCell>
<TableCell isNumeric> <TableCell isNumeric>
<Skeleton loading={ isLoading } display="inline-block" my={ 1 }> <TruncatedValue
{ balance } value={ balance }
</Skeleton> isLoading={ isLoading }
my={ 1 }
w="100%"
/>
</TableCell> </TableCell>
<TableCell isNumeric> <TableCell isNumeric>
<Skeleton loading={ isLoading } display="inline-block" my={ 1 }> <Skeleton loading={ isLoading } display="inline-block" my={ 1 }>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment