Merge branch 'main' of github.com:blockscout/frontend into email-confirmation

This commit is contained in:
tom
2023-05-22 12:01:33 -03:00
333 changed files with 5582 additions and 855 deletions
+4 -1
View File
@@ -32,13 +32,14 @@ NEXT_PUBLIC_FOOTER_TELEGRAM_LINK=__PLACEHOLDER_FOR_NEXT_PUBLIC_FOOTER_TELEGRAM_L
NEXT_PUBLIC_FOOTER_STAKING_LINK=__PLACEHOLDER_FOR_NEXT_PUBLIC_FOOTER_STAKING_LINK__
NEXT_PUBLIC_FEATURED_NETWORKS=__PLACEHOLDER_FOR_NEXT_PUBLIC_FEATURED_NETWORKS__
NEXT_PUBLIC_NETWORK_EXPLORERS=__PLACEHOLDER_FOR_NEXT_PUBLIC_NETWORK_EXPLORERS__
NEXT_PUBLIC_OTHER_LINKS=__PLACEHOLDER_FOR_NEXT_PUBLIC_OTHER_LINKS__
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_MARKETPLACE_CONFIG_URL__
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=__PLACEHOLDER_FOR_NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM__
NEXT_PUBLIC_LOGOUT_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_LOGOUT_URL__
NEXT_PUBLIC_LOGOUT_RETURN_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_LOGOUT_RETURN_URL__
NEXT_PUBLIC_HOMEPAGE_CHARTS=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_CHARTS__
NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR__
NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT__
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND__
NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER__
NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=__PLACEHOLDER_FOR_NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME__
NEXT_PUBLIC_AD_DOMAIN_WITH_AD=__PLACEHOLDER_FOR_NEXT_PUBLIC_AD_DOMAIN_WITH_AD__
@@ -55,6 +56,8 @@ NEXT_PUBLIC_API_PORT=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_PORT__
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL__
NEXT_PUBLIC_STATS_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_STATS_API_HOST__
NEXT_PUBLIC_VISUALIZE_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_VISUALIZE_API_HOST__
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_CONTRACT_INFO_API_HOST__
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=__PLACEHOLDER_FOR_NEXT_PUBLIC_ADMIN_SERVICE_API_HOST__
NEXT_PUBLIC_API_SPEC_URL=__PLACEHOLDER_FOR_NEXT_PUBLIC_API_SPEC_URL__
# external services config
+3
View File
@@ -1,5 +1,6 @@
name: Checks
on:
workflow_dispatch:
pull_request:
push:
branches:
@@ -9,6 +10,7 @@ jobs:
lint:
name: ESLint
runs-on: ubuntu-latest
if: "!contains(github.event.pull_request.labels.*.name, 'WIP')"
steps:
- name: Checkout repo
uses: actions/checkout@v3
@@ -30,6 +32,7 @@ jobs:
type_check:
name: TypeScript
runs-on: ubuntu-latest
if: "!contains(github.event.pull_request.labels.*.name, 'WIP')"
steps:
- name: Checkout repo
uses: actions/checkout@v3
+3
View File
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
+13 -2
View File
@@ -1,4 +1,5 @@
/* eslint-disable no-restricted-properties */
import type { NavItemExternal } from 'types/client/navigation-items';
import type { WalletType } from 'types/client/wallets';
import type { NetworkExplorer } from 'types/networks';
import type { ChainIndicatorId } from 'ui/home/indicators/types';
@@ -11,6 +12,7 @@ const parseEnvJson = <DataType>(env: string | undefined): DataType | null => {
return null;
}
};
const stripTrailingSlash = (str: string) => str[str.length - 1] === '/' ? str.slice(0, -1) : str;
const getWeb3DefaultWallet = (): WalletType => {
const envValue = getEnvValue(process.env.NEXT_PUBLIC_WEB3_DEFAULT_WALLET);
@@ -100,6 +102,7 @@ const config = Object.freeze({
telegram: getEnvValue(process.env.NEXT_PUBLIC_FOOTER_TELEGRAM_LINK),
staking: getEnvValue(process.env.NEXT_PUBLIC_FOOTER_STAKING_LINK),
},
otherLinks: parseEnvJson<Array<NavItemExternal>>(getEnvValue(process.env.NEXT_PUBLIC_OTHER_LINKS)) || [],
featuredNetworks: getEnvValue(process.env.NEXT_PUBLIC_FEATURED_NETWORKS),
blockScoutVersion: getEnvValue(process.env.NEXT_PUBLIC_BLOCKSCOUT_VERSION),
isAccountSupported: getEnvValue(process.env.NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED) === 'true',
@@ -141,11 +144,19 @@ const config = Object.freeze({
endpoint: getEnvValue(process.env.NEXT_PUBLIC_VISUALIZE_API_HOST),
basePath: '',
},
contractInfoApi: {
endpoint: getEnvValue(process.env.NEXT_PUBLIC_CONTRACT_INFO_API_HOST),
basePath: '',
},
adminServiceApi: {
endpoint: getEnvValue(process.env.NEXT_PUBLIC_ADMIN_SERVICE_API_HOST),
basePath: '',
},
homepage: {
charts: parseEnvJson<Array<ChainIndicatorId>>(getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_CHARTS)) || [],
plate: {
gradient: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT) ||
'radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%)',
background: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND) ||
'radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%), var(--chakra-colors-blue-400)',
textColor: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR) || 'white',
},
showGasTracker: getEnvValue(process.env.NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER) === 'false' ? false : true,
+4 -2
View File
@@ -13,5 +13,7 @@ NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout
# api config
NEXT_PUBLIC_API_HOST=blockscout.com
NEXT_PUBLIC_STATS_API_HOST=https://stats-test.aws-k8s.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.aws-k8s.blockscout.com
NEXT_PUBLIC_STATS_API_HOST=https://stats-test.k8s-dev.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.k8s-dev.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info-test.k8s-dev.blockscout.com
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs-test.k8s-dev.blockscout.com
+1 -1
View File
@@ -1,6 +1,6 @@
# ui config
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/ethereum/goerli/transaction','address':'/ethereum/ethereum/goerli/address'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address'}}]
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
# network config
+1 -1
View File
@@ -1,7 +1,7 @@
# ui config
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/base-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS=
NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT=linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0x4a0ed8ddf751a7cb5297f827699117b0f6d21a0b2907594d300dc9fed75c7e62
NEXT_PUBLIC_WEB3_DEFAULT_WALLET=coinbase
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=true
+1 -1
View File
@@ -13,7 +13,7 @@ NEXT_PUBLIC_FOOTER_GITHUB_LINK=https://github.com/blockscout/blockscout
NEXT_PUBLIC_FOOTER_TWITTER_LINK=https://www.twitter.com/blockscoutcom
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}]
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cup']
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap']
NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
# network config
+3 -3
View File
@@ -2,9 +2,9 @@
NEXT_PUBLIC_FOOTER_TELEGRAM_LINK=https://t.me/poa_network
NEXT_PUBLIC_FOOTER_STAKING_LINK=https://duneanalytics.com/maxaleks/xdai-staking
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}]
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cup']
#NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT=linear-gradient(136.9deg, \#235643 1.5%, \#16191E 77.77%)
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address','block':'/ethereum/poa/core/block'}}]
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap']
#NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND='no-repeat bottom 20% right 0px/100% url(https://neon-labs.org/images/index/banner.jpg)'
#NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=\#DCFE76
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-logos/poa.svg
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/network-icons/poa.svg
+5 -2
View File
@@ -11,10 +11,11 @@ NEXT_PUBLIC_FOOTER_GITHUB_LINK=https://github.com/blockscout/blockscout
NEXT_PUBLIC_FOOTER_TWITTER_LINK=https://www.twitter.com/blockscoutcom
NEXT_PUBLIC_FOOTER_TELEGRAM_LINK=https://t.me/poa_network
NEXT_PUBLIC_FOOTER_STAKING_LINK=https://duneanalytics.com/maxaleks/xdai-staking
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/poa/core/transaction','address':'/ethereum/poa/core/address'}}]
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cup']
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs','coin_price','market_cap']
NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true
NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=true
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND=
NEXT_PUBLIC_FEATURED_NETWORKS=
NEXT_PUBLIC_NETWORK_LOGO=
NEXT_PUBLIC_NETWORK_LOGO_DARK=
@@ -41,5 +42,7 @@ NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://localhost:3000/marketplace-submit-fo
# api config
NEXT_PUBLIC_API_HOST=https://localhost:3003
NEXT_PUBLIC_STATS_API_HOST=https://localhost:3004
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://localhost:3005
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://localhost:3006
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx
NEXT_PUBLIC_API_BASE_PATH=/
+7 -3
View File
@@ -5,7 +5,7 @@ blockscout:
app: blockscout
enabled: true
image:
_default: &image blockscout/blockscout-optimism-l2-advanced:5.1.2-prerelease-465ba09e
_default: &image blockscout/blockscout-optimism-l2-advanced:5.1.4-prerelease-a8c134e4
replicas:
app: 1
# init container
@@ -385,7 +385,7 @@ frontend:
_default: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/base-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS:
_default: ''
NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT:
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND:
_default: "linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)"
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS:
_default: ''
@@ -398,9 +398,13 @@ frontend:
NEXT_PUBLIC_HOMEPAGE_CHARTS:
_default: "['daily_txs']"
NEXT_PUBLIC_IS_TESTNET:
_default: "true"
_default: true
NEXT_PUBLIC_VISUALIZE_API_HOST:
_default: https://visualizer-optimism-goerli.test.aws-k8s.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST:
_default: https://contracts-info-test.k8s-dev.blockscout.com
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST:
_default: https://admin-rs-test.k8s-dev.blockscout.com
NEXT_PUBLIC_IS_L2_NETWORK:
_default: "true"
NEXT_PUBLIC_L1_BASE_URL:
+9 -5
View File
@@ -299,12 +299,12 @@ frontend:
NEXT_PUBLIC_FEATURED_NETWORKS:
_default: https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS:
_default: "[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/ethereum/goerli/transaction','address':'/ethereum/ethereum/goerli/address'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address'}}]"
_default: "[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]"
# network config
NEXT_PUBLIC_NETWORK_NAME:
_default: Ethereum
_default: Göerli
NEXT_PUBLIC_NETWORK_SHORT_NAME:
_default: Goerli
_default: Göerli
NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME:
_default: ethereum
NEXT_PUBLIC_NETWORK_LOGO:
@@ -343,9 +343,13 @@ frontend:
NEXT_PUBLIC_API_HOST:
_default: blockscout.com/eth/goerli
NEXT_PUBLIC_STATS_API_HOST:
_default: https://stats-test.aws-k8s.blockscout.com/
_default: https://stats-test.aws-k8s.blockscout.com
NEXT_PUBLIC_VISUALIZE_API_HOST:
_default: https://visualizer.aws-k8s.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST:
_default: https://contracts-info-test.k8s-dev.blockscout.com
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST:
_default: https://admin-rs-test.k8s-dev.blockscout.com
NEXT_PUBLIC_APP_HOST:
_default: blockscout.com/eth/goerli
NEXT_PUBLIC_LOGOUT_URL:
@@ -355,7 +359,7 @@ frontend:
NEXT_PUBLIC_NETWORK_RPC_URL:
_default: https://rpc.ankr.com/eth_goerli
NEXT_PUBLIC_HOMEPAGE_CHARTS:
_default: "['daily_txs','coin_price','market_cup']"
_default: "['daily_txs','coin_price','market_cap']"
NEXT_PUBLIC_API_SPEC_URL:
_default: https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL:
+6 -2
View File
@@ -113,7 +113,7 @@ frontend:
_default: https://raw.githubusercontent.com/blockscout/frontend-configs/dev/configs/marketplace/base-goerli.json
NEXT_PUBLIC_NETWORK_EXPLORERS:
_default: ''
NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT:
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND:
_default: "linear-gradient(136.9deg,rgb(107 94 236) 1.5%,rgb(0 82 255) 56.84%,rgb(82 62 231) 98.54%)"
NEXT_PUBLIC_NETWORK_TOKEN_ADDRESS:
_default: ''
@@ -126,9 +126,13 @@ frontend:
NEXT_PUBLIC_HOMEPAGE_CHARTS:
_default: "['daily_txs']"
NEXT_PUBLIC_IS_TESTNET:
_default: "true"
_default: true
NEXT_PUBLIC_VISUALIZE_API_HOST:
_default: https://visualizer-optimism-goerli.test.aws-k8s.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST:
_default: https://contracts-info-test.k8s-dev.blockscout.com
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST:
_default: https://admin-rs-test.k8s-dev.blockscout.com
NEXT_PUBLIC_IS_L2_NETWORK:
_default: "true"
NEXT_PUBLIC_L1_BASE_URL:
+9 -4
View File
@@ -39,6 +39,7 @@ frontend:
- "/csv-export"
- "/verified-contracts"
- "/graphiql"
- "/login"
resources:
limits:
@@ -67,9 +68,9 @@ frontend:
NEXT_PUBLIC_FOOTER_STAKING_LINK:
_default: https://duneanalytics.com/maxaleks/xdai-staking
NEXT_PUBLIC_NETWORK_NAME:
_default: Ethereum
_default: Göerli
NEXT_PUBLIC_NETWORK_SHORT_NAME:
_default: Goerli
_default: Göerli
NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME:
_default: ethereum
NEXT_PUBLIC_NETWORK_LOGO:
@@ -97,6 +98,10 @@ frontend:
_default: https://stats-test.aws-k8s.blockscout.com/
NEXT_PUBLIC_VISUALIZE_API_HOST:
_default: https://visualizer.aws-k8s.blockscout.com
NEXT_PUBLIC_CONTRACT_INFO_API_HOST:
_default: https://contracts-info-test.k8s-dev.blockscout.com
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST:
_default: https://admin-rs-test.k8s-dev.blockscout.com
NEXT_PUBLIC_AUTH_URL:
_default: https://blockscout-main.test.aws-k8s.blockscout.com
NEXT_PUBLIC_API_BASE_PATH:
@@ -109,13 +114,13 @@ frontend:
_default: https://blockscout.com/auth/logout
review: blockscout-main.test.aws-k8s.blockscout.com/auth/logout
NEXT_PUBLIC_HOMEPAGE_CHARTS:
_default: "['daily_txs','coin_price','market_cup']"
_default: "['daily_txs','coin_price','market_cap']"
NEXT_PUBLIC_APP_HOST:
_default: blockscout.com
NEXT_PUBLIC_NETWORK_RPC_URL:
_default: https://rpc.ankr.com/eth_goerli
NEXT_PUBLIC_NETWORK_EXPLORERS:
_default: "[{'title':'Anyblock','baseUrl':'https://explorer.anyblock.tools','paths':{'tx':'/ethereum/ethereum/goerli/transaction','address':'/ethereum/ethereum/goerli/address'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address'}}]"
_default: "[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]"
NEXT_PUBLIC_API_SPEC_URL:
_default: https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL:
+6 -3
View File
@@ -29,6 +29,7 @@ The app instance could be customized by passing following variables to NodeJS en
| Variable | Type| Description | Is required | Default value | Example value |
| --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_FEATURED_NETWORKS | `string` | URL of configuration file (`.json` format only) which contains list of featured networks that will be shown in the network menu. See [below](#featured-network-configuration-properties) list of available properties for particular network | - | - | `https://example.com/featured_networks_config.json` |
| NEXT_PUBLIC_OTHER_LINKS | `Array<{url: string; text: string}>` | List of links for the "Other" navigation menu | - | - | `[{'url':'https://blockscout.com','text':'Blockscout'}]` |
| NEXT_PUBLIC_BLOCKSCOUT_VERSION | `string` | Current running version of Blockscout (used to display link to release in the footer) | - | - | `v.5.1.0-beta`
| NEXT_PUBLIC_FOOTER_GITHUB_LINK | `string` | Link to Github in the footer | - | - | `https://github.com/blockscout/blockscout` |
| NEXT_PUBLIC_FOOTER_TWITTER_LINK | `string` | Link to Twitter in the footer | - | - | `https://www.twitter.com/blockscoutcom` |
@@ -41,9 +42,9 @@ The app instance could be customized by passing following variables to NodeJS en
| NEXT_PUBLIC_AUTH_URL | `string` | Account auth base url; the login path (`/auth/auth0`) will be added to it at execution time. Required if account is supported for the app instance. | - | - | `https://blockscout.com` |
| NEXT_PUBLIC_LOGOUT_URL | `string` | Account logout url. Required if account is supported for the app instance. | - | - | `https://blockscoutcom.us.auth0.com/v2/logout` |
| NEXT_PUBLIC_LOGOUT_RETURN_URL | `string` | Account logout return url. Required if account is supported for the app instance. | - | - | `https://blockscout.com/poa/core/auth/logout` |
| NEXT_PUBLIC_HOMEPAGE_CHARTS | `Array<'daily_txs' \| 'coin_price' \| 'market_cup'>` | List of charts displayed on the home page | - | - | `['daily_txs','coin_price','market_cup']` |
| NEXT_PUBLIC_HOMEPAGE_CHARTS | `Array<'daily_txs' \| 'coin_price' \| 'market_cap'>` | List of charts displayed on the home page | - | - | `['daily_txs','coin_price','market_cap']` |
| NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR | `string` | Text color of the hero plate on the homepage (escape "#" symbol if you use HEX color codes) | `\#FFFFFF \| rgb(220, 254, 118)` | `\#DCFE76` |
| NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT | `string` | Gradient value for hero plate on the homepage (escape "#" symbol if you use HEX color codes) | - | `radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%)` | `radial-gradient(at 15% 86%, hsla(350,65%,70%,1) 0px, transparent 50%), radial-gradient(at 72% 57%, hsla(14,95%,76%,1) 0px, transparent 50%)` |
| NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND | `string` | Background css value for hero plate on the homepage (escape "#" symbol if you use HEX color codes) | - | `radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%), var(--chakra-colors-blue-400)` | `radial-gradient(at 15% 86%, hsla(350,65%,70%,1) 0px, transparent 50%)` \| `no-repeat bottom 20% right 0px/100% url(https://placekitten/1400/200)` |
| NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER | `boolean` | Set to false if network doesn't have gas tracker | - | `true` | `false` |
| NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME | `boolean` | Set to false if average block time is useless for the network | - | `true` | `false` |
| NEXT_PUBLIC_AD_DOMAIN_WITH_AD | `string` | The domain on which we display ads | - | - | `blockscout.com` |
@@ -103,7 +104,7 @@ For each application, you need to specify the `MarketplaceCategoryId` to which i
| --- | --- | --- | --- | --- | --- |
| title | `string` | Displayed name of the explorer | yes | - | `Anyblock` |
| baseUrl | `string` | Base url of the explorer | yes | - | `https://explorer.anyblock.tools` |
| paths | `Record<'tx' \| 'block' \| 'address', string>` | Map of explorer entities and their paths | yes | - | `{'tx':'/ethereum/poa/core/tx'}` |
| paths | `Record<'tx' \| 'block' \| 'address' \| 'token', string>` | Map of explorer entities and their paths | yes | - | `{'tx':'/ethereum/poa/core/tx'}` |
*Note* The url of an entity will be constructed as `<baseUrl><paths[<entity-type>]><entity-id>`, e.g `https://explorer.anyblock.tools/ethereum/poa/core/tx/<tx-id>`
@@ -128,6 +129,8 @@ For each application, you need to specify the `MarketplaceCategoryId` to which i
| NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL | `ws \| wss` | Main API websocket protocol | - | `wss` | `ws` |
| NEXT_PUBLIC_STATS_API_HOST | `string` | Stats API endpoint url | - | - | `https://my-host.com` |
| NEXT_PUBLIC_VISUALIZE_API_HOST | `string` | Visualize API endpoint url | - | - | `https://my-host.com` |
| NEXT_PUBLIC_CONTRACT_INFO_API_HOST | `string` | Contract Info API endpoint url | - | - | `https://my-host.com` |
| NEXT_PUBLIC_ADMIN_SERVICE_API_HOST | `string` | Admin Service API endpoint url | - | - | `https://my-host.com` |
## External services configuration
+4
View File
@@ -0,0 +1,4 @@
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.26 17.5H4.027a.47.47 0 0 1-.47-.469V5.312c0-.26.21-.469.47-.469h2.137V2.969c0-.259.21-.469.468-.469h5.89l.015.003.014.003a.449.449 0 0 1 .14.03.463.463 0 0 1 .156.095l3.452 3.31-.002.002a.466.466 0 0 1 .146.337v7.3c0 .87-.708 1.577-1.577 1.577h-1.029v.766c0 .87-.707 1.577-1.577 1.577Zm2.823-11.69L12.99 3.794v1.379a.64.64 0 0 0 .638.639h1.454Zm-2.755-2.648H6.826v11.333h8.316a.64.64 0 0 0 .639-.64V6.474H13.63c-.87 0-1.302-.432-1.302-1.301v-2.01ZM6.164 5.505H4.22v11.333h8.316c.352 0 .639-.563.639-.915v-.766H6.632a.469.469 0 0 1-.468-.469V5.505ZM8.85 8.5a.25.25 0 1 0 0 .5h4.7a.25.25 0 1 0 0-.5h-4.7Zm-.25 1.95a.25.25 0 0 1 .25-.25h4.7a.25.25 0 1 1 0 .5h-4.7a.25.25 0 0 1-.25-.25ZM8.85 12a.25.25 0 1 0 0 .5h4.7a.25.25 0 1 0 0-.5h-4.7Z" fill="currentColor"/>
<path d="M6.164 4.843v.35h.35v-.35h-.35Zm6.373-2.34-.098.336h.003l.095-.336Zm0 0 .099-.336h-.003l-.095.336Zm.014.003.02-.35-.02.35Zm.123.025.12-.33h-.004l-.115.33Zm.017.005.101-.335-.101.335Zm.025.009.145-.319h-.002l-.143.319Zm.13.086.243-.253-.243.252ZM16.3 5.94l.247.248.253-.253-.258-.247-.242.252Zm-.002.002-.247-.248-.252.252.257.248.242-.252Zm-2.46 9.214v-.35h-.35v.35h.35Zm-.846-11.364.242-.252-.593-.572v.824h.35Zm2.092 2.018v.35h.867l-.624-.602-.243.252ZM6.826 3.162v-.35h-.35v.35h.35Zm5.502 0h.35v-.35h-.35v.35ZM6.826 14.495h-.35v.35h.35v-.35Zm8.955-8.022h.35v-.35h-.35v.35ZM4.22 5.505v-.35h-.35v.35h.35Zm1.944 0h.35v-.35h-.35v.35ZM4.22 16.838h-.35v.35h.35v-.35Zm8.955-1.68h.35v-.35h-.35v.35ZM4.027 17.85h8.233v-.7H4.027v.7Zm-.82-.819a.82.82 0 0 0 .82.819v-.7a.12.12 0 0 1-.12-.119h-.7Zm0-11.719v11.719h.7V5.312h-.7Zm.82-.819a.82.82 0 0 0-.82.819h.7a.12.12 0 0 1 .12-.119v-.7Zm2.137 0H4.027v.7h2.137v-.7Zm-.35-1.524v1.874h.7V2.969h-.7Zm.818-.819a.819.819 0 0 0-.818.819h.7c0-.066.053-.119.118-.119v-.7Zm5.89 0h-5.89v.7h5.89v-.7Zm.114.017s-.015-.005-.033-.008a.389.389 0 0 0-.081-.009v.7a.313.313 0 0 1-.065-.007c-.013-.002-.022-.006-.018-.004l.197-.672Zm-.003 0-.191.673.191-.674Zm-.063-.01a.308.308 0 0 1 .053.007l.013.003-.197.672.027.007a.39.39 0 0 0 .066.01l.038-.7Zm.22.043a.8.8 0 0 0-.218-.044l-.041.7a.1.1 0 0 1 .028.005l.231-.66Zm.002 0 .001.001-.237.659c.015.005.029.01.033.01l.203-.67Zm.067.025c-.032-.014-.061-.022-.067-.024l-.203.67h.004-.002a.208.208 0 0 1-.018-.007l.286-.639Zm.23.153a.812.812 0 0 0-.228-.152l-.29.637a.11.11 0 0 1 .033.02l.485-.505Zm3.452 3.31-3.452-3.31-.485.505 3.453 3.311.484-.505Zm.004.502.001-.001-.495-.495-.001.001.495.495Zm.248.09a.818.818 0 0 0-.253-.59l-.485.505a.117.117 0 0 1 .038.085h.7Zm0 7.3v-7.3h-.7v7.3h.7Zm-1.927 1.927a1.929 1.929 0 0 0 1.927-1.927h-.7c0 .677-.551 1.227-1.227 1.227v.7Zm-1.029 0h1.029v-.7h-1.029v.7Zm.35.416v-.766h-.7v.766h.7ZM12.26 17.85a1.929 1.929 0 0 0 1.927-1.927h-.7c0 .676-.55 1.227-1.227 1.227v.7Zm.488-13.805 2.092 2.018.486-.504-2.093-2.018-.486.504Zm.593 1.127v-1.38h-.7v1.38h.7Zm.288.289a.29.29 0 0 1-.288-.29h-.7a.99.99 0 0 0 .988.99v-.7Zm1.454 0h-1.454v.7h1.454v-.7ZM6.826 3.512h5.502v-.7H6.826v.7Zm.35 10.983V3.162h-.7v11.333h.7Zm7.966-.35H6.826v.7h8.316v-.7Zm.289-.29a.29.29 0 0 1-.29.29v.7a.99.99 0 0 0 .99-.99h-.7Zm0-7.382v7.383h.7V6.473h-.7Zm-1.801.35h2.15v-.7h-2.15v.7Zm-1.652-1.651c0 .488.122.918.427 1.224.306.306.737.427 1.225.427v-.7c-.382 0-.602-.095-.73-.222-.127-.127-.222-.348-.222-.73h-.7Zm0-2.01v2.01h.7v-2.01h-.7ZM4.22 5.855h1.944v-.7H4.22v.7Zm.35 10.983V5.505h-.7v11.333h.7Zm7.966-.35H4.22v.7h8.316v-.7Zm.289-.565a.862.862 0 0 1-.134.404c-.099.156-.167.16-.155.16v.7c.364 0 .615-.276.748-.489.143-.229.24-.52.24-.775h-.7Zm0-.766v.766h.7v-.766h-.7Zm-6.193.35h6.543v-.7H6.632v.7Zm-.818-.819c0 .452.365.82.818.82v-.7a.119.119 0 0 1-.118-.12h-.7Zm0-9.183v9.183h.7V5.505h-.7ZM8.95 8.75a.1.1 0 0 1-.1.1v-.7a.6.6 0 0 0-.6.6h.7Zm-.1-.1a.1.1 0 0 1 .1.1h-.7a.6.6 0 0 0 .6.6v-.7Zm4.7 0h-4.7v.7h4.7v-.7Zm-.1.1a.1.1 0 0 1 .1-.1v.7a.6.6 0 0 0 .6-.6h-.7Zm.1.1a.1.1 0 0 1-.1-.1h.7a.6.6 0 0 0-.6-.6v.7Zm-4.7 0h4.7v-.7h-4.7v.7Zm0 1a.6.6 0 0 0-.6.6h.7a.1.1 0 0 1-.1.1v-.7Zm4.7 0h-4.7v.7h4.7v-.7Zm.6.6a.6.6 0 0 0-.6-.6v.7a.1.1 0 0 1-.1-.1h.7Zm-.6.6a.6.6 0 0 0 .6-.6h-.7a.1.1 0 0 1 .1-.1v.7Zm-4.7 0h4.7v-.7h-4.7v.7Zm-.6-.6a.6.6 0 0 0 .6.6v-.7a.1.1 0 0 1 .1.1h-.7Zm.7 1.8a.1.1 0 0 1-.1.1v-.7a.6.6 0 0 0-.6.6h.7Zm-.1-.1a.1.1 0 0 1 .1.1h-.7a.6.6 0 0 0 .6.6v-.7Zm4.7 0h-4.7v.7h4.7v-.7Zm-.1.1a.1.1 0 0 1 .1-.1v.7a.6.6 0 0 0 .6-.6h-.7Zm.1.1a.1.1 0 0 1-.1-.1h.7a.6.6 0 0 0-.6-.6v.7Zm-4.7 0h4.7v-.7h-4.7v.7Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M21 5H3v13.58h18V5ZM4.256 7.163v9.25L8.8 11.766 4.256 7.163Zm14.622 10.16H5.12l4.56-4.662.879.89c.782.788 2.156.78 2.925.006l.865-.87 4.528 4.637Zm.866-.91V7.257l-4.51 4.539 4.51 4.617ZM18.97 6.256H5.125l6.327 6.411c.29.292.864.286 1.142.005l6.375-6.416Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 409 B

+11
View File
@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20">
<g fill="currentColor" clip-path="url(#explorer_svg__a)">
<path d="M14.192 5.808a.624.624 0 0 0-.64-.15L7.927 7.531a.625.625 0 0 0-.395.395l-1.875 5.625a.625.625 0 0 0 .79.791l5.626-1.875a.626.626 0 0 0 .395-.395l1.875-5.625a.625.625 0 0 0-.151-.64Zm-6.954 6.954L8.62 8.619l2.762 2.762-4.143 1.38Z"/>
<path d="M10 18.75A8.75 8.75 0 1 1 18.75 10 8.76 8.76 0 0 1 10 18.75ZM10 2.5a7.5 7.5 0 1 0 7.5 7.5A7.509 7.509 0 0 0 10 2.5Z"/>
</g>
<defs>
<clipPath id="explorer_svg__a">
<path fill="currentColor" d="M0 0h20v20H0z"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 649 B

+2 -9
View File
@@ -1,10 +1,3 @@
<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#link_svg__a)">
<path d="M5.547 6.073c1.303-1.303 3.469-1.303 4.772 0 1.171 1.172 1.345 3.04.382 4.387l-.026.038a.75.75 0 0 1-1.221-.872l.026-.038a1.89 1.89 0 0 0-2.874-2.435l-2.63 2.632c-.738.717-.738 1.934 0 2.672a1.887 1.887 0 0 0 2.433.202l.038-.047a.772.772 0 0 1 1.045.194.75.75 0 0 1-.173 1.048l-.038.026a3.389 3.389 0 0 1-4.366-5.154l2.632-2.653Zm6.914 5.833A3.388 3.388 0 0 1 7.307 7.54l.026-.038c.22-.335.689-.415 1.045-.173.338.22.417.689.176 1.045l-.026.038c-.537.731-.452 1.781.202 2.435a1.893 1.893 0 0 0 2.671 0l2.63-2.632c.738-.738.738-1.955 0-2.672a1.887 1.887 0 0 0-2.433-.202l-.037.026c-.338.242-.806.143-1.046-.174a.749.749 0 0 1 .174-1.046l.037-.026a3.389 3.389 0 0 1 4.367 5.153l-2.632 2.632Z" fill="currentColor"/>
</g>
<defs>
<clipPath id="link_svg__a">
<path fill="#fff" transform="translate(1.504 3)" d="M0 0h15v12H0z"/>
</clipPath>
</defs>
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.17 3a5.073 5.073 0 0 0-3.568 1.424l-.01.01-1.401 1.393a1 1 0 0 0 1.41 1.419l1.396-1.388a3.073 3.073 0 0 1 4.346 4.344l-2.437 2.438a3.072 3.072 0 0 1-4.635-.332 1 1 0 1 0-1.601 1.198 5.074 5.074 0 0 0 7.65.548l2.444-2.444.012-.012A5.073 5.073 0 0 0 16.17 3Zm-5.34 5.657a5.073 5.073 0 0 0-3.95 1.474l-2.444 2.444-.012.012a5.073 5.073 0 0 0 7.174 7.174l.012-.013 1.393-1.393a1 1 0 1 0-1.414-1.414l-1.387 1.387a3.073 3.073 0 0 1-4.345-4.346l2.437-2.437a3.072 3.072 0 0 1 4.635.332 1 1 0 0 0 1.601-1.198 5.074 5.074 0 0 0-3.7-2.022Z" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 991 B

After

Width:  |  Height:  |  Size: 686 B

+4
View File
@@ -0,0 +1,4 @@
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 9.375a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5Z" stroke="currentColor" stroke-width="1.4" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.25 9.938c-1.188.937-2.125 2.25-2.5 3.812h1.438c.937 0 1.625-.875 1.375-1.75a9.626 9.626 0 0 1-.375-2.688C6.25 5.876 7.813 2.939 10 1.875c2.188 1.063 3.75 4 3.75 7.375 0 .938-.125 1.875-.375 2.688-.25.874.438 1.75 1.375 1.75h1.5c-.375-1.563-1.313-2.938-2.5-3.813M10 13.75v5M8.125 15v2.5m3.75-2.5v2.5" stroke="currentColor" stroke-width="1.4" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 687 B

+8
View File
@@ -0,0 +1,8 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2 2a9.996 9.996 0 0 1 10.014 10.026c0 5.483-4.523 10-10.092 9.974-5.385-.052-9.908-4.49-9.908-10 0-5.535 4.444-10.026 9.987-10ZM4.594 17.222c0 .104.052.156.105.235.392.548.836 1.07 1.359 1.514.235.21.47.418.732.6.732.47 1.49.914 2.327 1.202.68.235 1.385.418 2.091.496.55.052 1.124.078 1.673 0 .314-.052.654-.052.968-.183.052.026-.026-.958 0-.958.653-.105.392-.896 1.02-1.157 2.039-.887 2.797-1.828 3.79-3.812.89-1.75 1.726-2.767 1.438-4.7-.261-1.853-1.882-2.428-3.137-3.785-1.673-1.906-1.908-2.455-4.444-2.611-1.125-.079-1.15.81-2.223 1.175-1.751.574-3.059.391-4.235 1.827C4.724 8.71 4.776 9.911 4.697 12c-.026.522-.182 1.332-.104 1.854.157 1.175-1.02 1.801-.418 2.82.157.156.261.365.418.548Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.253 7.04c-.575-.105-1.15-.21-1.752-.183-.653.026-1.228.235-1.83.47-.705.26-1.359.626-1.882 1.174-.575.601-.889 1.332-1.02 2.168-.104.704-.13 1.41-.209 2.114-.13 1.515-.366 3.03-.993 4.413-.183-.157-.288-.392-.392-.575a8.801 8.801 0 0 1-1.15-3.315c-.079-.523-.131-1.019-.105-1.54.078-2.09.732-3.97 2.065-5.614C6.135 4.716 7.6 3.723 9.351 3.149a9.54 9.54 0 0 1 3.32-.444c2.51.157 4.654 1.175 6.353 3.029a9.16 9.16 0 0 1 2.301 4.83c.288 1.932 0 3.786-.889 5.535-.993 1.985-2.536 3.42-4.575 4.308a7.7 7.7 0 0 1-1.909.575c-.052 0-.078.078-.104.026-.157-.992.078-1.932.47-2.846.497-1.097 1.203-2.037 1.987-2.95.654-.758 1.412-1.463 2.144-2.168.418-.417.785-.835.994-1.383.366-.888.157-1.62-.628-2.194-.601-.443-1.307-.678-2.013-.887a26.36 26.36 0 0 1-2.013-.731c-.13-.444-.444-.731-.863-.888-.549-.13-1.098-.078-1.673.078Zm8.55 5.56h.052c.104-.365.104-.757.104-1.148 0-.444-.052-.888-.13-1.332a7.48 7.48 0 0 0-1.962-3.76c-.627-.652-1.333-1.2-2.039-1.775-.627-.522-1.307-.914-2.091-1.123-.758-.182-1.49-.287-2.275-.156-.052 0-.104 0-.104.052s.052.052.104.052c1.15.209 2.249.575 3.32.992 1.046.418 1.935 1.019 2.589 1.958.444.653.863 1.332 1.202 2.063.445.992.785 2.01.994 3.055.105.418.183.757.235 1.123Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.894 7.927c.993 0 1.778.81 1.778 1.775 0 .992-.81 1.776-1.804 1.802-.994 0-1.778-.81-1.778-1.802s.81-1.775 1.804-1.775Zm1.255 1.801c0-.705-.55-1.253-1.255-1.253-.706 0-1.255.548-1.255 1.253 0 .68.55 1.254 1.229 1.254h.026c.68 0 1.229-.549 1.255-1.254Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.358 13.41c.68.418 1.438.47 2.196.444a8.302 8.302 0 0 0 2.98-.705c.367-.157.733-.314 1.072-.522.027-.027.053-.053.105-.027-.026.079-.105.105-.183.157-1.02.679-2.144 1.097-3.346 1.332-.68.13-1.386.13-2.04-.105-.34-.13-.653-.34-.784-.574Zm-.104-6.37c.549-.158 1.124-.21 1.673 0 .418.156.732.443.862.887-.784-.418-1.647-.679-2.535-.888Z" fill="transparent"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.358 13.41c.68.417 1.438.469 2.196.443a8.304 8.304 0 0 0 2.98-.705c.367-.157.733-.313 1.073-.522.026-.026.052-.052.104-.026-.026.078-.104.104-.183.156-1.02.68-2.144 1.097-3.346 1.332-.68.13-1.386.13-2.04-.104-.34-.131-.653-.34-.784-.575Zm4.942-1.54a.402.402 0 0 1-.393-.392c0-.21.157-.392.366-.392.21 0 .392.157.418.365-.026.236-.183.418-.392.418Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.815 12.523a.056.056 0 0 1-.052.052c0-.052.026-.078.052-.052Zm.078-.052-.078.052-.026-.026c.052-.026.078-.026.104-.026Z" fill="transparent"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.59 14.774c.245-.016.482-.099.684-.238h.004c.197-.125.369-.288.511-.484.138-.662.211-1.349.211-2.052 0-5.523-4.477-10-10-10S2 6.477 2 12c0 1.55.352 3.017.981 4.326l5.643-9.058c.733-1.118 1.486-1.178 1.989-1.03.76.22 1.161.96 1.191 2.195v5.356l2.712-4.388.02-.034c.457-.73 1.59-2.544 3.1-2.102.907.264 1.449 1.239 1.449 2.608v2.852c0 .93.278 1.613.793 1.905.22.11.465.16.711.144Zm-.018 2.38a3.683 3.683 0 0 1-1.808-.442c-1.28-.717-2.009-2.17-2.009-3.987v-2.48c-.08.116-.17.25-.264.408l-3.013 4.877c-1.014 1.647-1.982 1.774-2.614 1.59-.633-.184-1.386-.813-1.386-2.758v-4.047L4.392 18.49A9.978 9.978 0 0 0 12 22a9.995 9.995 0 0 0 8.572-4.847Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 797 B

+6
View File
@@ -0,0 +1,6 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="m8.074 22 .128-3.79a13.266 13.266 0 0 1-5.491 1.181v.805a1.803 1.803 0 0 0 1.803 1.805h3.56Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.631 2h2.797a9.95 9.95 0 0 1 4.552 1.094 13.202 13.202 0 0 0-1.871 2.688.873.873 0 0 0-.633.03.942.942 0 0 0-1.806 0 .922.922 0 0 0-1.09.287.913.913 0 0 0-.126.207c-.24-.328-.586-.533-.96-.754-.309-.183-.637-.377-.937-.661a.266.266 0 0 0-.406.02.534.534 0 0 0-.058.54c.323.762.72 1.305 1.075 1.787.114.156.224.305.325.454a.667.667 0 0 0 .488.316 3.043 3.043 0 0 0-.417 1.13c-.458.124-.805.676-.805 1.341 0 .59.276 1.096.66 1.286l-.217 6.446a13.266 13.266 0 0 1-5.491 1.18V6.922A4.924 4.924 0 0 0 7.63 2Zm-.514 6.574a.457.457 0 0 0-.11-.345.446.446 0 0 0-.149-.11L5.591 7.55a.304.304 0 0 0-.304.524l1.127.814a.444.444 0 0 0 .522-.003.456.456 0 0 0 .125-.136.456.456 0 0 0 .056-.175Zm-.11 7.395a.446.446 0 0 0 .092-.16h-.002a.456.456 0 0 0-.038-.359.445.445 0 0 0-.646-.138l-1.128.812a.304.304 0 0 0 .305.525l1.267-.57a.446.446 0 0 0 .15-.11ZM4.33 12.372l.484.166a.544.544 0 1 0 0-1.032l-.484.166a.37.37 0 0 0 0 .7Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.98 3.094A9.993 9.993 0 0 1 20.422 12a9.997 9.997 0 0 1-5.394 8.877l-.304-9.017v-.096a.403.403 0 0 0 .065-.038c.352-.211.595-.692.595-1.247 0-.066-.003-.132-.01-.198-.061-.575-.382-1.032-.795-1.144a2.988 2.988 0 0 0-.409-1.13.666.666 0 0 0 .496-.316c.101-.15.211-.3.326-.458.35-.481.745-1.022 1.066-1.768l.018-.042a.365.365 0 0 0-.044-.38.373.373 0 0 0-.566-.035c-.294.28-.607.457-.9.623-.34.194-.652.37-.874.674a.97.97 0 0 0-.583-.523c.51-.97 1.138-1.873 1.871-2.688Zm3.348 9.442.486-.166a.37.37 0 0 0 0-.7l-.486-.166a.545.545 0 1 0 0 1.032Zm-.708 4.122a.304.304 0 0 0 .084-.536l-1.127-.813a.443.443 0 0 0-.645.139.443.443 0 0 0 .202.628l1.268.57a.294.294 0 0 0 .218.012ZM15.985 8.23a.448.448 0 0 0-.11.345.444.444 0 0 0 .182.313.447.447 0 0 0 .521.002l1.128-.814a.304.304 0 0 0-.304-.524l-1.268.57a.445.445 0 0 0-.15.108Z" fill="currentColor"/>
<path d="M6.19 5.48A4.924 4.924 0 0 0 7.63 2H4.514A1.803 1.803 0 0 0 2.71 3.803v3.119a4.92 4.92 0 0 0 3.479-1.443Zm6.286 5.224-.507.466a.314.314 0 0 0-.09.152c-.033.134-.099.397-.152.647a.152.152 0 0 1-.152.115.152.152 0 0 1-.152-.115l-.162-.647a.304.304 0 0 0-.09-.152l-.506-.466a.151.151 0 0 1-.033-.175.153.153 0 0 1 .156-.086l.76.103h.042l.06-.007.7-.096a.153.153 0 0 1 .153.085.152.152 0 0 1-.035.176m.76-.17a1.82 1.82 0 0 1 .271-.927.608.608 0 0 0 .05-.503l-.036.032a.888.888 0 0 1-1.086.009c0 .313-.286.572-.66.618a.988.988 0 0 1-.118 0c-.427 0-.776-.28-.776-.626a.888.888 0 0 1-1.086-.009.65.65 0 0 1-.114-.12.596.596 0 0 0-.034.628c.147.277.224.585.223.898 0 .327-.087.648-.253.93a.609.609 0 0 0 .056.689c.437.525 1.135.961 1.803 1.02h.165c.773 0 1.38-.482 1.813-1.114a.599.599 0 0 0 .026-.626 1.892 1.892 0 0 1-.228-.897" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10Zm-8.293-4.547c1.539.117 2.84 1.137 2.84 1.137s1.453 2.11 1.71 6.25c-1.464 1.691-3.69 1.703-3.69 1.703l-.466-.621a5.672 5.672 0 0 0 2.454-1.652c-.922.699-2.309 1.422-4.547 1.422-2.239 0-3.63-.727-4.547-1.422a5.672 5.672 0 0 0 2.453 1.652l-.465.621s-2.226-.012-3.691-1.703c.25-4.14 1.703-6.25 1.703-6.25s1.226-.984 2.84-1.137l.136.278c-1.27.285-2.027.828-2.695 1.425 1.149-.586 2.285-1.136 4.262-1.136 1.976 0 3.113.55 4.262 1.136-.668-.597-1.305-1.086-2.696-1.425l.137-.278Zm-4.55 5.114c0 .628.444 1.136.995 1.136.551 0 .996-.508.996-1.136 0-.63-.445-1.137-.996-1.137-.55 0-.996.508-.996 1.137Zm3.694 0c0 .628.446 1.136.997 1.136.546 0 .996-.508.996-1.136 0-.63-.446-1.137-.996-1.137-.551 0-.997.508-.997 1.137Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 937 B

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.122 12.061C22.122 6.505 17.618 2 12.062 2 6.504 2 2 6.505 2 12.061c0 5.022 3.68 9.184 8.49 9.939v-7.03H7.933v-2.91h2.555V9.845c0-2.522 1.502-3.915 3.8-3.915 1.101 0 2.252.197 2.252.197v2.476h-1.268c-1.25 0-1.64.775-1.64 1.57v1.888h2.79l-.445 2.908h-2.345V22c4.81-.755 8.49-4.917 8.49-9.939Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 409 B

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.005 2c-5.525 0-10 4.475-10 10a9.994 9.994 0 0 0 6.837 9.488c.5.087.688-.213.688-.476 0-.237-.013-1.024-.013-1.862-2.512.463-3.162-.612-3.362-1.175-.113-.288-.6-1.175-1.025-1.413-.35-.187-.85-.65-.013-.662.788-.013 1.35.725 1.538 1.025.9 1.512 2.337 1.087 2.912.825.088-.65.35-1.087.638-1.337-2.225-.25-4.55-1.113-4.55-4.938 0-1.088.387-1.987 1.025-2.688-.1-.25-.45-1.275.1-2.65 0 0 .837-.262 2.75 1.026a9.28 9.28 0 0 1 2.5-.338c.85 0 1.7.112 2.5.337 1.912-1.3 2.75-1.024 2.75-1.024.55 1.375.2 2.4.1 2.65.637.7 1.025 1.587 1.025 2.687 0 3.838-2.338 4.688-4.563 4.938.363.312.675.912.675 1.85 0 1.337-.012 2.412-.012 2.75 0 .262.187.574.687.474A10.016 10.016 0 0 0 22.005 12c0-5.525-4.475-10-10-10Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 855 B

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2c5.52 0 10 4.48 10 10s-4.48 10-10 10S2 17.52 2 12 6.48 2 12 2ZM8.874 17.62V9.81H6.277v7.81h2.597Zm9.36 0v-4.478c0-2.4-1.281-3.515-2.989-3.515-1.377 0-1.994.757-2.34 1.29V9.81H10.31c.034.732 0 7.809 0 7.809h2.596v-4.361c0-.234.016-.467.085-.634.188-.466.615-.95 1.332-.95.939 0 1.315.717 1.315 1.767v4.178h2.596ZM7.593 6.045c-.888 0-1.469.584-1.469 1.35 0 .749.563 1.349 1.435 1.349h.016c.906 0 1.47-.6 1.47-1.35-.018-.765-.564-1.35-1.452-1.35Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 603 B

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2C6.478 2 2 6.477 2 12s4.478 10 10 10c5.523 0 10-4.477 10-10S17.523 2 12 2Zm5.673 6.628h-.455c-.17 0-.409.244-.409.4v5.662c0 .156.24.369.409.369h.455v1.344h-4.127v-1.344h.864V9.108h-.043l-2.017 7.295h-1.562L8.797 9.108h-.05v5.951h.863v1.344H6.155v-1.344h.442c.182 0 .421-.213.421-.37v-5.66c0-.156-.239-.4-.421-.4h-.442V7.284h4.32l1.42 5.28h.038l1.432-5.28h4.308v1.344Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 487 B

+8
View File
@@ -0,0 +1,8 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="opensea_filled_svg__a" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="2" y="2" width="20" height="20">
<path d="M22 2H2v20h20V2Z" fill="#fff"/>
</mask>
<g mask="url(#opensea_filled_svg__a)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.037 2.035c5.52 0 10 4.48 10 10s-4.48 10-10 10-10-4.48-10-10 4.48-10 10-10Zm2.732 7.245.053.068.075.098c.02.04.06.081.08.142.036.053.068.106.099.16l.026.045c.031.053.063.107.099.16.02.06.06.121.08.182.082.162.143.325.163.507.02.04.02.081.02.101.02.04.02.102.02.162.02.183 0 .345-.02.527-.007.03-.015.058-.023.085l-.015.054a2.655 2.655 0 0 0-.023.084c-.02.061-.04.142-.08.223-.062.142-.143.284-.224.426-.02.04-.06.101-.101.162-.04.061-.081.102-.101.162-.041.061-.102.122-.142.183-.04.06-.081.121-.142.182-.061.081-.142.162-.203.243-.04.041-.081.102-.142.142-.04.04-.08.102-.142.142-.06.061-.121.122-.182.162l-.122.102c-.02.02-.04.02-.06.02h-.893v1.135h1.115c.244 0 .487-.08.67-.243.06-.06.344-.304.688-.669.02-.02.02-.02.041-.02l3.081-.892c.122-.06.162-.02.162.04v.65c0 .04-.02.06-.06.08-.203.081-.913.405-1.197.81-.75 1.035-1.317 2.514-2.574 2.514h-5.29a3.396 3.396 0 0 1-3.385-3.405v-.06c0-.041.04-.082.08-.082h2.98c.061 0 .102.061.102.101-.02.183.02.386.101.568.182.365.547.568.933.568h1.459v-1.135h-1.44a.091.091 0 0 1-.08-.142.28.28 0 0 0 .06-.082c.142-.202.325-.486.527-.83.142-.224.264-.487.365-.73.02-.04.04-.081.061-.142.02-.081.061-.162.081-.223l.061-.183c.04-.202.06-.425.06-.668 0-.082 0-.183-.02-.284 0-.045-.003-.089-.008-.133l-.003-.038a1.319 1.319 0 0 1-.009-.133c0-.081-.02-.183-.04-.264a2.866 2.866 0 0 0-.081-.405l-.02-.04c-.02-.082-.041-.183-.082-.264a7.58 7.58 0 0 0-.283-.811l-.122-.304a7.912 7.912 0 0 0-.182-.406c-.02-.06-.061-.1-.082-.162-.02-.06-.06-.121-.08-.182l-.061-.122-.183-.324c-.02-.04.02-.101.06-.081l1.116.304.142.04.162.041.06.02v-.669c0-.324.264-.588.568-.588.162 0 .304.061.406.163a.566.566 0 0 1 .162.405V7.5l.121.04s.02 0 .02.02c.021.021.061.062.122.102.04.04.081.081.142.122.102.08.243.203.385.324.04.04.081.06.102.101.182.163.385.365.588.588.06.061.1.122.162.183.06.06.101.142.162.202l.075.098Zm-7.88 3.105.041-.06 2.635-4.116c.041-.06.122-.06.163.02.446.994.81 2.21.648 2.98-.08.325-.284.75-.527 1.136a.442.442 0 0 1-.101.162c-.02.02-.04.04-.081.04H6.95c-.061-.02-.102-.101-.061-.162Z" fill="currentColor"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2c5.52 0 10 4.48 10 10s-4.48 10-10 10S2 17.52 2 12 6.48 2 12 2Zm6.667 10c0-.807-.655-1.462-1.462-1.462a1.4 1.4 0 0 0-1.006.41c-.994-.714-2.374-1.182-3.895-1.24l.667-3.123 2.163.456a1.042 1.042 0 0 0 2.082-.047c0-.573-.467-1.04-1.04-1.04-.41 0-.76.233-.925.584l-2.42-.515a.291.291 0 0 0-.2.035.285.285 0 0 0-.116.164l-.737 3.486c-1.556.046-2.948.502-3.953 1.24a1.476 1.476 0 0 0-1.006-.41 1.463 1.463 0 0 0-.597 2.795c-.023.14-.035.293-.035.445 0 2.245 2.608 4.058 5.836 4.058s5.837-1.813 5.837-4.058c0-.152-.012-.293-.035-.433.48-.234.842-.748.842-1.345Zm-4.188 3.79c-.713.713-2.07.76-2.467.76-.398 0-1.766-.059-2.468-.76a.275.275 0 0 1 0-.386.275.275 0 0 1 .386 0c.444.444 1.403.608 2.093.608s1.638-.164 2.094-.609a.275.275 0 0 1 .386 0 .3.3 0 0 1-.024.386Zm-5.812-2.75c0-.572.467-1.04 1.04-1.04.574 0 1.042.468 1.042 1.04 0 .574-.468 1.042-1.041 1.042a1.043 1.043 0 0 1-1.041-1.041Zm5.625 1.042a1.043 1.043 0 0 1-1.04-1.041c0-.573.467-1.041 1.04-1.041.574 0 1.041.468 1.041 1.04 0 .574-.467 1.042-1.04 1.042Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 2c5.52 0 10 4.48 10 10s-4.48 10-10 10S2 17.52 2 12 6.48 2 12 2Zm1.598 13.51c.7 0 1.272.572 1.272 1.273 0 .7-.572 1.272-1.272 1.272-.7 0-1.273-.572-1.273-1.272V15.51h1.273ZM9.13 13.599c0-.7.572-1.273 1.272-1.273.7 0 1.273.572 1.273 1.273v3.185c0 .7-.572 1.272-1.273 1.272-.7 0-1.272-.572-1.272-1.272v-3.186Zm-.64 0c0 .7-.572 1.272-1.273 1.272-.7 0-1.272-.572-1.272-1.272 0-.7.572-1.273 1.272-1.273H8.49v1.273Zm8.293 1.272c.7 0 1.272-.572 1.272-1.272 0-.7-.572-1.273-1.272-1.273h-3.186c-.7 0-1.272.572-1.272 1.273 0 .7.572 1.272 1.273 1.272h3.185Zm0-3.195c.7 0 1.272-.572 1.272-1.273 0-.7-.572-1.272-1.272-1.272-.7 0-1.273.572-1.273 1.272v1.273h1.273Zm-1.913-1.273c0 .7-.572 1.273-1.272 1.273-.7 0-1.273-.572-1.273-1.273V7.217c0-.7.572-1.272 1.273-1.272.7 0 1.272.572 1.272 1.272v3.186Zm-4.467 1.273c.7 0 1.272-.572 1.272-1.273 0-.7-.572-1.272-1.273-1.272H7.217c-.7 0-1.272.572-1.272 1.272 0 .7.572 1.273 1.272 1.273h3.186Zm1.272-3.186V7.217c0-.7-.572-1.272-1.273-1.272-.7 0-1.272.572-1.272 1.272 0 .7.572 1.272 1.272 1.272h1.273Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.01 12c0 5.523-4.477 10-10 10s-10-4.477-10-10 4.477-10 10-10 10 4.477 10 10Zm-9.73-3.495a525.959 525.959 0 0 0-6.445 2.776c-.523.208-.797.412-.822.61-.042.337.38.47.953.65l.241.076c.564.184 1.323.398 1.718.407.358.008.757-.14 1.198-.443 3.01-2.031 4.564-3.058 4.661-3.08.069-.016.164-.036.229.022.064.057.058.166.051.195-.041.178-1.694 1.715-2.55 2.51-.267.248-.456.424-.494.464-.087.09-.175.175-.26.257-.524.505-.917.884.021 1.503.452.297.813.543 1.173.789.393.267.786.535 1.293.867.13.085.253.173.374.259.457.326.869.62 1.377.573.295-.027.6-.305.755-1.133.366-1.957 1.086-6.197 1.252-7.944a1.942 1.942 0 0 0-.019-.435.465.465 0 0 0-.157-.3c-.132-.107-.337-.13-.428-.128-.416.007-1.053.23-4.122 1.505Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 860 B

+3
View File
@@ -0,0 +1,3 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.005 22c5.523 0 10-4.477 10-10s-4.477-10-10-10-10 4.477-10 10 4.477 10 10 10Zm5.011-12.322c.483-.35.894-.774 1.234-1.27a4.938 4.938 0 0 1-1.416.38 2.39 2.39 0 0 0 1.081-1.355 4.823 4.823 0 0 1-1.56.593 2.371 2.371 0 0 0-1.798-.776c-.68 0-1.26.24-1.74.72a2.37 2.37 0 0 0-.72 1.739c0 .182.021.37.062.563a6.855 6.855 0 0 1-2.83-.757 6.971 6.971 0 0 1-2.241-1.816 2.4 2.4 0 0 0-.335 1.24 2.456 2.456 0 0 0 1.096 2.048 2.44 2.44 0 0 1-1.112-.312v.031c0 .594.187 1.115.56 1.564.373.45.844.732 1.412.849a2.542 2.542 0 0 1-.647.084c-.142 0-.297-.013-.464-.038.157.492.446.897.868 1.214a2.4 2.4 0 0 0 1.431.49 4.816 4.816 0 0 1-3.053 1.051c-.218 0-.416-.01-.594-.03a6.83 6.83 0 0 0 3.777 1.104 7.19 7.19 0 0 0 2.459-.415c.766-.277 1.421-.647 1.964-1.112a7.434 7.434 0 0 0 1.405-1.602 7.138 7.138 0 0 0 .88-1.892 6.983 6.983 0 0 0 .282-2.295Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 990 B

+69 -4
View File
@@ -1,4 +1,15 @@
import type { UserInfo, CustomAbis, PublicTags, AddressTags, TransactionTags, ApiKeys, WatchlistAddress } from 'types/api/account';
import type {
UserInfo,
CustomAbis,
PublicTags,
AddressTags,
TransactionTags,
ApiKeys,
WatchlistAddress,
VerifiedAddressResponse,
TokenInfoApplicationConfig,
TokenInfoApplications,
} from 'types/api/account';
import type {
Address,
AddressCounters,
@@ -36,14 +47,15 @@ import type {
TokenInventoryResponse,
TokenInstance,
TokenInstanceTransfersCount,
TokenVerifiedInfo,
} from 'types/api/token';
import type { TokensResponse, TokensFilters, TokenInstanceTransferResponse } from 'types/api/tokens';
import type { TokenTransferResponse, TokenTransferFilters } from 'types/api/tokenTransfer';
import type { TransactionsResponseValidated, TransactionsResponsePending, Transaction } from 'types/api/transaction';
import type { TransactionsResponseValidated, TransactionsResponsePending, Transaction, TransactionsResponseWatchlist } from 'types/api/transaction';
import type { TTxsFilters } from 'types/api/txsFilters';
import type { TxStateChanges } from 'types/api/txStateChanges';
import type { VisualizedContract } from 'types/api/visualization';
import type { WithdrawalsResponse } from 'types/api/withdrawals';
import type { WithdrawalsResponse, WithdrawalsCounters } from 'types/api/withdrawals';
import type { ArrayElement } from 'types/utils';
import appConfig from 'configs/app/config';
@@ -91,6 +103,35 @@ export const RESOURCES = {
pathParams: [ 'id' as const ],
},
// ACCOUNT: ADDRESS VERIFICATION & TOKEN INFO
address_verification: {
path: '/api/v1/chains/:chainId/verified-addresses:type',
pathParams: [ 'chainId' as const, 'type' as const ],
endpoint: appConfig.contractInfoApi.endpoint,
basePath: appConfig.contractInfoApi.basePath,
},
verified_addresses: {
path: '/api/v1/chains/:chainId/verified-addresses',
pathParams: [ 'chainId' as const ],
endpoint: appConfig.contractInfoApi.endpoint,
basePath: appConfig.contractInfoApi.basePath,
},
token_info_applications_config: {
path: '/api/v1/chains/:chainId/token-info-submissions/selectors',
pathParams: [ 'chainId' as const ],
endpoint: appConfig.adminServiceApi.endpoint,
basePath: appConfig.adminServiceApi.basePath,
},
token_info_applications: {
path: '/api/v1/chains/:chainId/token-info-submissions/:id?',
pathParams: [ 'chainId' as const, 'id' as const ],
endpoint: appConfig.adminServiceApi.endpoint,
basePath: appConfig.adminServiceApi.basePath,
},
// STATS
stats_counters: {
path: '/api/v1/counters',
@@ -148,6 +189,11 @@ export const RESOURCES = {
paginationFields: [ 'filter' as const, 'hash' as const, 'inserted_at' as const ],
filterFields: [ 'filter' as const, 'type' as const, 'method' as const ],
},
txs_watchlist: {
path: '/api/v2/transactions/watchlist',
paginationFields: [ 'filter' as const, 'hash' as const, 'inserted_at' as const ],
filterFields: [ ],
},
tx: {
path: '/api/v2/transactions/:hash',
pathParams: [ 'hash' as const ],
@@ -183,6 +229,9 @@ export const RESOURCES = {
paginationFields: [ 'index' as const, 'items_count' as const ],
filterFields: [],
},
withdrawals_counters: {
path: '/api/v2/withdrawals/counters',
},
// ADDRESSES
addresses: {
@@ -304,6 +353,12 @@ export const RESOURCES = {
path: '/api/v2/tokens/:hash',
pathParams: [ 'hash' as const ],
},
token_verified_info: {
path: '/api/v1/chains/:chainId/token-infos/:hash',
pathParams: [ 'chainId' as const, 'hash' as const ],
endpoint: appConfig.contractInfoApi.endpoint,
basePath: appConfig.contractInfoApi.basePath,
},
token_counters: {
path: '/api/v2/tokens/:hash/counters',
pathParams: [ 'hash' as const ],
@@ -373,6 +428,9 @@ export const RESOURCES = {
homepage_txs: {
path: '/api/v2/main-page/transactions',
},
homepage_txs_watchlist: {
path: '/api/v2/main-page/transactions/watchlist',
},
homepage_indexing_status: {
path: '/api/v2/main-page/indexing-status',
},
@@ -493,7 +551,7 @@ export interface ResourceError<T = unknown> {
export type ResourceErrorAccount<T> = ResourceError<{ errors: T }>
export type PaginatedResources = 'blocks' | 'block_txs' |
'txs_validated' | 'txs_pending' |
'txs_validated' | 'txs_pending' | 'txs_watchlist' |
'tx_internal_txs' | 'tx_logs' | 'tx_token_transfers' |
'addresses' |
'address_txs' | 'address_internal_txs' | 'address_token_transfers' | 'address_blocks_validated' | 'address_coin_balance' |
@@ -516,11 +574,15 @@ Q extends 'private_tags_address' ? AddressTags :
Q extends 'private_tags_tx' ? TransactionTags :
Q extends 'api_keys' ? ApiKeys :
Q extends 'watchlist' ? Array<WatchlistAddress> :
Q extends 'verified_addresses' ? VerifiedAddressResponse :
Q extends 'token_info_applications_config' ? TokenInfoApplicationConfig :
Q extends 'token_info_applications' ? TokenInfoApplications :
Q extends 'homepage_stats' ? HomeStats :
Q extends 'homepage_chart_txs' ? ChartTransactionResponse :
Q extends 'homepage_chart_market' ? ChartMarketResponse :
Q extends 'homepage_blocks' ? Array<Block> :
Q extends 'homepage_txs' ? Array<Transaction> :
Q extends 'homepage_txs_watchlist' ? Array<Transaction> :
Q extends 'homepage_deposits' ? Array<L2DepositsItem> :
Q extends 'homepage_indexing_status' ? IndexingStatus :
Q extends 'stats_counters' ? Counters :
@@ -532,6 +594,7 @@ Q extends 'block_txs' ? BlockTransactionsResponse :
Q extends 'block_withdrawals' ? BlockWithdrawalsResponse :
Q extends 'txs_validated' ? TransactionsResponseValidated :
Q extends 'txs_pending' ? TransactionsResponsePending :
Q extends 'txs_watchlist' ? TransactionsResponseWatchlist :
Q extends 'tx' ? Transaction :
Q extends 'tx_internal_txs' ? InternalTransactionsResponse :
Q extends 'tx_logs' ? LogsResponseTx :
@@ -551,6 +614,7 @@ Q extends 'address_logs' ? LogsResponseAddress :
Q extends 'address_tokens' ? AddressTokensResponse :
Q extends 'address_withdrawals' ? AddressWithdrawalsResponse :
Q extends 'token' ? TokenInfo :
Q extends 'token_verified_info' ? TokenVerifiedInfo :
Q extends 'token_counters' ? TokenCounters :
Q extends 'token_transfers' ? TokenTransferResponse :
Q extends 'token_holders' ? TokenHolders :
@@ -572,6 +636,7 @@ Q extends 'verified_contracts_counters' ? VerifiedContractsCounters :
Q extends 'visualize_sol2uml' ? VisualizedContract :
Q extends 'contract_verification_config' ? SmartContractVerificationConfig :
Q extends 'withdrawals' ? WithdrawalsResponse :
Q extends 'withdrawals_counters' ? WithdrawalsCounters :
Q extends 'l2_output_roots' ? L2OutputRootsResponse :
Q extends 'l2_withdrawals' ? L2WithdrawalsResponse :
Q extends 'l2_deposits' ? L2DepositsResponse :
+2 -2
View File
@@ -1,6 +1,6 @@
import React from 'react';
import appConfig from 'configs/app/config';
import isNeedProxy from 'lib/api/isNeedProxy';
import type { Params as FetchParams } from 'lib/hooks/useFetch';
import useFetch from 'lib/hooks/useFetch';
@@ -27,7 +27,7 @@ export default function useApiFetch() {
url,
{
credentials: 'include',
...(resource.endpoint && appConfig.host === 'localhost' ? {
...(resource.endpoint && isNeedProxy() ? {
headers: {
'x-endpoint': resource.endpoint,
},
+2
View File
@@ -33,6 +33,8 @@ export function app(): CspDev.DirectiveDescriptor {
appConfig.api.socket,
appConfig.statsApi.endpoint,
appConfig.visualizeApi.endpoint,
appConfig.contractInfoApi.endpoint,
appConfig.adminServiceApi.endpoint,
// chain RPC server
appConfig.network.rpcUrl,
+15
View File
@@ -0,0 +1,15 @@
import appConfig from 'configs/app/config';
import { useAppContext } from 'lib/appContext';
import * as cookies from 'lib/cookies';
export default function useHasAccount() {
const appProps = useAppContext();
if (!appConfig.isAccountSupported) {
return false;
}
const cookiesString = appProps.cookies;
const hasAuth = Boolean(cookies.get(cookies.NAMES.API_TOKEN, cookiesString));
return hasAuth;
}
+20 -32
View File
@@ -1,7 +1,8 @@
import { useRouter } from 'next/router';
import type { Route } from 'nextjs-routes';
import React from 'react';
import type { NavItemInternal, NavItem, NavGroupItem } from 'types/client/navigation-items';
import appConfig from 'configs/app/config';
import abiIcon from 'icons/ABI.svg';
import apiKeysIcon from 'icons/API.svg';
@@ -27,28 +28,6 @@ import verifiedIcon from 'icons/verified.svg';
import watchlistIcon from 'icons/watchlist.svg';
import { rightLineArrow } from 'lib/html-entities';
type NavItemCommon = {
text: string;
icon: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
}
type NavItemInternal = NavItemCommon & {
nextRoute: Route;
isActive?: boolean;
isNewUi?: boolean;
}
type NavItemExternal = NavItemCommon & {
url: string;
}
export type NavItem = NavItemInternal | NavItemExternal
export type NavGroupItem = NavItemCommon & {
isActive?: boolean;
subItems: Array<NavItem> | Array<Array<NavItem>>;
}
interface ReturnType {
mainNavItems: Array<NavItem | NavGroupItem>;
accountNavItems: Array<NavItem>;
@@ -135,7 +114,7 @@ export default function useNavItems(): ReturnType {
].filter(Boolean);
}
const otherNavItems: Array<NavItem> = [
const apiNavItems: Array<NavItem> = [
hasAPIDocs ? {
text: 'REST API',
nextRoute: { pathname: '/api-docs' as const },
@@ -185,20 +164,22 @@ export default function useNavItems(): ReturnType {
isNewUi: true,
} : null,
{ text: 'Charts & stats', nextRoute: { pathname: '/stats' as const }, icon: statsIcon, isActive: pathname === '/stats', isNewUi: true },
// there should be custom site sections like Stats, Faucet, More, etc but never an 'other'
// examples https://explorer-edgenet.polygon.technology/ and https://explorer.celo.org/
// at this stage custom menu items is under development, we will implement it later
otherNavItems.length > 0 ? {
{
text: 'API',
icon: apiDocsIcon,
isActive: apiNavItems.some(item => isInternalItem(item) && item.isActive),
subItems: apiNavItems,
},
appConfig.otherLinks.length > 0 ? {
text: 'Other',
icon: gearIcon,
isActive: otherNavItems.some(item => isInternalItem(item) && item.isActive),
subItems: otherNavItems,
subItems: appConfig.otherLinks,
} : null,
].filter(Boolean) as Array<NavItem | NavGroupItem>;
const accountNavItems = [
{
text: 'Watchlist',
text: 'Watch list',
nextRoute: { pathname: '/account/watchlist' as const },
icon: watchlistIcon,
isActive: pathname === '/account/watchlist',
@@ -230,7 +211,14 @@ export default function useNavItems(): ReturnType {
isActive: pathname === '/account/custom_abi',
isNewUi: true,
},
];
appConfig.contractInfoApi.endpoint && appConfig.adminServiceApi.endpoint && {
text: 'Verified addrs',
nextRoute: { pathname: '/account/verified_addresses' as const },
icon: verifiedIcon,
isActive: pathname === '/account/verified_addresses',
isNewUi: true,
},
].filter(Boolean);
const profileItem = {
text: 'My profile',
+24
View File
@@ -0,0 +1,24 @@
import { useQueryClient } from '@tanstack/react-query';
import React from 'react';
import type { UserInfo } from 'types/api/account';
import { resourceKey } from 'lib/api/resources';
import useLoginUrl from 'lib/hooks/useLoginUrl';
export default function useRedirectIfNotAuth() {
const queryClient = useQueryClient();
const profileData = queryClient.getQueryData<UserInfo>([ resourceKey('user_info') ]);
const isAuth = Boolean(profileData);
const loginUrl = useLoginUrl();
return React.useCallback(() => {
if (!isAuth) {
window.location.assign(loginUrl);
return true;
}
return false;
}, [ isAuth, loginUrl ]);
}
+21
View File
@@ -0,0 +1,21 @@
import appConfig from 'configs/app/config';
import { getServerSideProps as base } from '../getServerSideProps';
export const getServerSideProps: typeof base = async(...args) => {
if (!appConfig.isAccountSupported) {
return {
notFound: true,
};
}
return base(...args);
};
export const getServerSidePropsForVerifiedAddresses: typeof base = async(...args) => {
if (!appConfig.isAccountSupported || !appConfig.adminServiceApi.endpoint || !appConfig.contractInfoApi.endpoint) {
return {
notFound: true,
};
}
return base(...args);
};
+11
View File
@@ -0,0 +1,11 @@
export default function shortenString(string: string | null) {
if (!string) {
return '';
}
if (string.length <= 7) {
return string;
}
return string.slice(0, 4) + '...' + string.slice(-4);
}
+2
View File
@@ -1 +1,3 @@
export const EMAIL_REGEXP = /^[\w.%+-]+@[a-zA-Z\d-]+(?:\.[a-zA-Z\d-]+)+$/;
export const validator = (value: string) => EMAIL_REGEXP.test(value) ? true : 'Invalid email';
+1
View File
@@ -0,0 +1 @@
export const SIGNATURE_REGEXP = /^0x[a-fA-F\d]{130}$/;
+12
View File
@@ -0,0 +1,12 @@
export const validator = (value: string | undefined) => {
if (!value) {
return true;
}
try {
new URL(value);
return true;
} catch (error) {
return 'Incorrect URL';
}
};
+3 -1
View File
@@ -17,7 +17,9 @@ export function middleware(req: NextRequest) {
}
// we don't have any info from router here, so just do straight forward sub-string search (sorry)
const isAccountRoute = req.nextUrl.pathname.includes('/account/');
const isAccountRoute =
req.nextUrl.pathname.includes('/account/') ||
(req.nextUrl.pathname === '/txs' && req.nextUrl.searchParams.get('tab') === 'watchlist');
const isProfileRoute = req.nextUrl.pathname.includes('/auth/profile');
const apiToken = req.cookies.get(NAMES.API_TOKEN);
+164
View File
@@ -0,0 +1,164 @@
import type { TokenInfoApplication, TokenInfoApplications, VerifiedAddress, VerifiedAddressResponse } from 'types/api/account';
import type { AddressValidationResponseSuccess } from 'ui/addressVerification/types';
export const SIGNATURE = '0x96491e0cd1b99c14951552361b7f6ff64f41651b5d1c12501914342c8a6847e21e08726c3505e11ba2af9a40ac0b05c8d113e7fd1f74594224b9c7276ebb3a661b';
export const VERIFIED_ADDRESS: Record<string, VerifiedAddress> = {
NEW_ITEM: {
userId: '1',
chainId: '99',
contractAddress: '0xF822070D07067D1519490dBf49448a7E30EE9ea5',
verifiedDate: '2022-09-01',
metadata: {
tokenName: 'Test Token',
tokenSymbol: 'TT',
},
},
ITEM_1: {
userId: '1',
chainId: '99',
contractAddress: '0xd0e3010d1ecdbd17aae178b2bf36eb413d8a7441',
verifiedDate: '2022-08-01',
metadata: {
tokenName: 'My Token',
tokenSymbol: 'MYT',
},
},
ITEM_2: {
userId: '1',
chainId: '99',
contractAddress: '0xa8FCe579a11E551635b9c9CB915BEcd873C51254',
verifiedDate: '2022-09-23',
metadata: {
tokenName: 'Cat Token',
tokenSymbol: 'CATT',
},
},
};
export const ADDRESS_CHECK_RESPONSE = {
SUCCESS: {
status: 'SUCCESS',
result: {
// eslint-disable-next-line max-len
signingMessage: '[eth-goerli.blockscout.com] [2023-04-18 18:47:40] I, hereby verify that I am the owner/creator of the address [0xf822070d07067d1519490dbf49448a7e30ee9ea5]',
contractCreator: '0xd0e3010d1ecdbd17aae178b2bf36eb413d8a7441',
contractOwner: '0xa8FCe579a11E551635b9c9CB915BEcd873C51254',
},
},
SOURCE_CODE_NOT_VERIFIED_ERROR: {
status: 'SOURCE_CODE_NOT_VERIFIED_ERROR',
},
};
export const ADDRESS_VERIFY_RESPONSE: Record<string, AddressValidationResponseSuccess> = {
SUCCESS: {
status: 'SUCCESS',
result: {
verifiedAddress: VERIFIED_ADDRESS.NEW_ITEM,
},
},
INVALID_SIGNER_ERROR: {
status: 'INVALID_SIGNER_ERROR',
invalidSigner: {
signer: '0xF822070D07067D1519490dBf49448a7E30EE9ea5',
},
},
};
export const VERIFIED_ADDRESS_RESPONSE: Record<string, VerifiedAddressResponse> = {
DEFAULT: {
verifiedAddresses: [
VERIFIED_ADDRESS.ITEM_1,
VERIFIED_ADDRESS.ITEM_2,
],
},
};
export const TOKEN_INFO_APPLICATION_BASE = {
id: '1',
tokenAddress: VERIFIED_ADDRESS.ITEM_1.contractAddress,
status: 'APPROVED',
updatedAt: '2022-11-08 12:47:10.149148Z',
requesterName: 'Tom',
requesterEmail: '[email protected]',
projectName: 'My project',
projectWebsite: 'http://example.com',
projectEmail: '[email protected]',
iconUrl: 'https://placekitten.com/100',
projectDescription: 'description',
projectSector: 'DeFi',
comment: '',
docs: 'https://example.com/docs',
github: 'https://github.com',
telegram: 'https://telegram.com',
linkedin: 'https://linkedin.com',
discord: 'https://discord.com',
slack: 'https://slack.com',
twitter: 'https://twitter.com',
openSea: 'https://opensea.com',
facebook: 'https://facebook.com',
medium: 'https://medium.com',
reddit: 'https://reddit.com',
support: '[email protected]',
coinMarketCapTicker: 'https://coinmarketcap.com',
coinGeckoTicker: 'https://coingecko.com',
defiLlamaTicker: 'https://defillama.com',
};
export const TOKEN_INFO_APPLICATION: Record<string, TokenInfoApplication> = {
APPROVED: {
...TOKEN_INFO_APPLICATION_BASE,
tokenAddress: VERIFIED_ADDRESS.ITEM_1.contractAddress,
id: '1',
status: 'APPROVED',
updatedAt: '2022-11-08 12:47:10.149148Z',
},
IN_PROCESS: {
...TOKEN_INFO_APPLICATION_BASE,
tokenAddress: VERIFIED_ADDRESS.ITEM_2.contractAddress,
id: '2',
status: 'IN_PROCESS',
updatedAt: '2022-11-10 08:11:10.149148Z',
},
UPDATED_ITEM: {
...TOKEN_INFO_APPLICATION_BASE,
tokenAddress: VERIFIED_ADDRESS.ITEM_1.contractAddress,
id: '1',
status: 'IN_PROCESS',
updatedAt: '2022-11-11 05:11:10.149148Z',
},
};
export const TOKEN_INFO_APPLICATIONS_RESPONSE: Record<string, TokenInfoApplications> = {
DEFAULT: {
submissions: [
TOKEN_INFO_APPLICATION.APPROVED,
TOKEN_INFO_APPLICATION.IN_PROCESS,
],
},
FOR_UPDATE: {
submissions: [
{
...TOKEN_INFO_APPLICATION.APPROVED,
status: 'UPDATE_REQUIRED',
},
TOKEN_INFO_APPLICATION.IN_PROCESS,
],
},
};
export const TOKEN_INFO_FORM_CONFIG = {
projectSectors: [
'Infra & Dev tooling',
'DeFi',
'Data',
'Bridge',
'NFT',
'Payments',
'Faucet',
'DAO',
'Games',
'Wallet',
],
};
+5
View File
@@ -1,6 +1,7 @@
import type { AddressTokenBalance } from 'types/api/address';
import * as tokens from 'mocks/tokens/tokenInfo';
import * as tokenInstance from 'mocks/tokens/tokenInstance';
export const erc20a: AddressTokenBalance = {
token: tokens.tokenInfoERC20a,
@@ -59,24 +60,28 @@ export const erc721LongSymbol: AddressTokenBalance = {
export const erc1155a: AddressTokenBalance = {
token: tokens.tokenInfoERC1155a,
token_id: '42',
token_instance: tokenInstance.base,
value: '24',
};
export const erc1155b: AddressTokenBalance = {
token: tokens.tokenInfoERC1155b,
token_id: '100010000000001',
token_instance: tokenInstance.base,
value: '11',
};
export const erc1155withoutName: AddressTokenBalance = {
token: tokens.tokenInfoERC1155WithoutName,
token_id: '64532245',
token_instance: tokenInstance.base,
value: '42',
};
export const erc1155LongId: AddressTokenBalance = {
token: tokens.tokenInfoERC1155b,
token_id: '483200961027732618117991942553110860267520',
token_instance: tokenInstance.base,
value: '42',
};
+13
View File
@@ -9,6 +9,7 @@ export const tokenInfo: TokenInfo = {
symbol: 'ARIA',
type: 'ERC-20',
total_supply: '1235',
icon_url: null,
};
export const tokenCounters: TokenCounters = {
@@ -25,6 +26,7 @@ export const tokenInfoERC20a: TokenInfo = {
symbol: 'HyFi',
total_supply: '369000000000000000000000000',
type: 'ERC-20',
icon_url: null,
};
export const tokenInfoERC20b: TokenInfo = {
@@ -36,6 +38,7 @@ export const tokenInfoERC20b: TokenInfo = {
symbol: 'USDC',
total_supply: '900000000000000000000000000',
type: 'ERC-20',
icon_url: null,
};
export const tokenInfoERC20c: TokenInfo = {
@@ -47,6 +50,7 @@ export const tokenInfoERC20c: TokenInfo = {
symbol: 'ETH',
total_supply: '1000000000000000000000000',
type: 'ERC-20',
icon_url: null,
};
export const tokenInfoERC20d: TokenInfo = {
@@ -58,6 +62,7 @@ export const tokenInfoERC20d: TokenInfo = {
symbol: 'ZETA',
total_supply: '2100000000000000000000000000',
type: 'ERC-20',
icon_url: null,
};
export const tokenInfoERC20LongSymbol: TokenInfo = {
@@ -69,6 +74,7 @@ export const tokenInfoERC20LongSymbol: TokenInfo = {
symbol: 'ipfs://QmUpFUfVKDCWeZQk5pvDFUxnpQP9N6eLSHhNUy49T1JVtY',
total_supply: '2100000000000000000000000000',
type: 'ERC-20',
icon_url: null,
};
export const tokenInfoERC721a: TokenInfo = {
@@ -80,6 +86,7 @@ export const tokenInfoERC721a: TokenInfo = {
symbol: 'HYFI_ATHENA',
total_supply: '105',
type: 'ERC-721',
icon_url: null,
};
export const tokenInfoERC721b: TokenInfo = {
@@ -91,6 +98,7 @@ export const tokenInfoERC721b: TokenInfo = {
symbol: 'WOWG',
total_supply: null,
type: 'ERC-721',
icon_url: null,
};
export const tokenInfoERC721c: TokenInfo = {
@@ -102,6 +110,7 @@ export const tokenInfoERC721c: TokenInfo = {
symbol: 'PUMA',
total_supply: null,
type: 'ERC-721',
icon_url: null,
};
export const tokenInfoERC721LongSymbol: TokenInfo = {
@@ -113,6 +122,7 @@ export const tokenInfoERC721LongSymbol: TokenInfo = {
symbol: 'ipfs://QmUpFUfVKDCWeZQk5pvDFUxnpQP9N6eLSHhNUy49T1JVtY',
total_supply: null,
type: 'ERC-721',
icon_url: null,
};
export const tokenInfoERC1155a: TokenInfo = {
@@ -124,6 +134,7 @@ export const tokenInfoERC1155a: TokenInfo = {
symbol: 'HYFI_MEMBERSHIP',
total_supply: '482',
type: 'ERC-1155',
icon_url: null,
};
export const tokenInfoERC1155b: TokenInfo = {
@@ -135,6 +146,7 @@ export const tokenInfoERC1155b: TokenInfo = {
symbol: 'WVC',
total_supply: '4943',
type: 'ERC-1155',
icon_url: null,
};
export const tokenInfoERC1155WithoutName: TokenInfo = {
@@ -146,4 +158,5 @@ export const tokenInfoERC1155WithoutName: TokenInfo = {
symbol: null,
total_supply: '482',
type: 'ERC-1155',
icon_url: null,
};
+3
View File
@@ -30,6 +30,7 @@ export const erc20: TokenTransfer = {
symbol: 'ARIA',
type: 'ERC-20',
total_supply: '0',
icon_url: null,
},
total: {
decimals: '18',
@@ -73,6 +74,7 @@ export const erc721: TokenTransfer = {
symbol: 'AriaSA',
type: 'ERC-721',
total_supply: '0',
icon_url: null,
},
total: {
token_id: '875879856',
@@ -115,6 +117,7 @@ export const erc1155A: TokenTransfer = {
symbol: 'MY_SYMBOL_IS_VERY_LONG',
type: 'ERC-1155',
total_supply: '0',
icon_url: null,
},
total: {
token_id: '123',
+2
View File
@@ -31,6 +31,7 @@ export const mintToken: TxStateChange = {
symbol: 'nMOONBIRD',
total_supply: '10645',
type: 'ERC-721',
icon_url: null,
},
type: 'token',
};
@@ -66,6 +67,7 @@ export const receiveMintedToken: TxStateChange = {
symbol: 'nMOONBIRD',
total_supply: '10645',
type: 'ERC-721',
icon_url: null,
},
type: 'token',
};
+3 -3
View File
@@ -1,7 +1,7 @@
export const data = {
items: [
{
amount: '192175',
amount: '192175000000000',
block_number: 43242,
index: 11688,
receiver: {
@@ -15,7 +15,7 @@ export const data = {
validator_index: 49622,
},
{
amount: '192175',
amount: '192175000000000',
block_number: 43242,
index: 11687,
receiver: {
@@ -29,7 +29,7 @@ export const data = {
validator_index: 49621,
},
{
amount: '182773',
amount: '182773000000000',
block_number: 43242,
index: 11686,
receiver: {
+1 -1
View File
@@ -20,4 +20,4 @@ const ApiKeysPage: NextPage = () => {
export default ApiKeysPage;
export { getServerSideProps } from 'lib/next/getServerSideProps';
export { getServerSideProps } from 'lib/next/account/getServerSideProps';
+1 -1
View File
@@ -20,4 +20,4 @@ const CustomAbiPage: NextPage = () => {
export default CustomAbiPage;
export { getServerSideProps } from 'lib/next/getServerSideProps';
export { getServerSideProps } from 'lib/next/account/getServerSideProps';
+1 -1
View File
@@ -20,4 +20,4 @@ const PublicTagsPage: NextPage = () => {
export default PublicTagsPage;
export { getServerSideProps } from 'lib/next/getServerSideProps';
export { getServerSideProps } from 'lib/next/account/getServerSideProps';
+1 -1
View File
@@ -20,4 +20,4 @@ const AddressTagsPage: NextPage = () => {
export default AddressTagsPage;
export { getServerSideProps } from 'lib/next/getServerSideProps';
export { getServerSideProps } from 'lib/next/account/getServerSideProps';
+23
View File
@@ -0,0 +1,23 @@
import type { NextPage } from 'next';
import Head from 'next/head';
import React from 'react';
import getNetworkTitle from 'lib/networks/getNetworkTitle';
import VerifiedAddresses from 'ui/pages/VerifiedAddresses';
import Page from 'ui/shared/Page/Page';
const VerifiedAddressesPage: NextPage = () => {
const title = getNetworkTitle();
return (
<>
<Head><title>{ title }</title></Head>
<Page>
<VerifiedAddresses/>
</Page>
</>
);
};
export default VerifiedAddressesPage;
export { getServerSidePropsForVerifiedAddresses as getServerSideProps } from 'lib/next/account/getServerSideProps';
+1 -1
View File
@@ -22,4 +22,4 @@ const WatchListPage: NextPage = () => {
export default WatchListPage;
export { getServerSideProps } from 'lib/next/getServerSideProps';
export { getServerSideProps } from 'lib/next/account/getServerSideProps';
+1 -1
View File
@@ -15,7 +15,7 @@ const APIDocsPage: NextPage = () => {
return (
<Page>
<PageTitle text="API Documentation"/>
<PageTitle title="API Documentation"/>
<Head><title>{ `API for the ${ networkTitle }` }</title></Head>
<SwaggerUI/>
</Page>
+2 -2
View File
@@ -5,7 +5,7 @@ import React from 'react';
import MarketplaceApp from 'ui/pages/MarketplaceApp';
import Page from 'ui/shared/Page/Page';
const AppPage: NextPage = () => {
const MarketplaceAppPage: NextPage = () => {
return (
<Page wrapChildren={ false }>
<Head><title>Blockscout | Marketplace</title></Head>
@@ -14,6 +14,6 @@ const AppPage: NextPage = () => {
);
};
export default AppPage;
export default MarketplaceAppPage;
export { getServerSideProps } from 'lib/next/getServerSideProps';
+5 -5
View File
@@ -2,21 +2,21 @@ import type { NextPage } from 'next';
import Head from 'next/head';
import React from 'react';
import Apps from 'ui/pages/Apps';
import Marketplace from 'ui/pages/Marketplace';
import Page from 'ui/shared/Page/Page';
import PageTitle from 'ui/shared/Page/PageTitle';
const AppsPage: NextPage = () => {
const MarketplacePage: NextPage = () => {
return (
<Page>
<PageTitle text="Apps"/>
<PageTitle title="Marketplace"/>
<Head><title>Blockscout | Marketplace</title></Head>
<Apps/>
<Marketplace/>
</Page>
);
};
export default AppsPage;
export default MarketplacePage;
export { getServerSideProps } from 'lib/next/getServerSideProps';
+1 -1
View File
@@ -18,4 +18,4 @@ const MyProfilePage: NextPage = () => {
export default MyProfilePage;
export { getServerSideProps } from 'lib/next/getServerSideProps';
export { getServerSideProps } from 'lib/next/account/getServerSideProps';
+1 -1
View File
@@ -16,7 +16,7 @@ const GraphiqlPage: NextPage = () => {
return (
<Page>
<Head><title>Graph Page</title></Head>
<PageTitle text="GraphQL playground"/>
<PageTitle title="GraphQL playground"/>
<GraphQL/>
</Page>
);
+1 -1
View File
@@ -7,7 +7,7 @@ interface Env {
}
// keep in mind that all passed variables here should be present in env config files (.env.pw or .env.poa)
export default function contextWithEnvs(envs: Array<Env>): Parameters<typeof test.extend>[0]['context'] {
export default function contextWithEnvsFixture(envs: Array<Env>): Parameters<typeof test.extend>[0]['context'] {
return async({ browser }, use) => {
const context = await createContextWithEnvs(browser, envs);
+1
View File
@@ -14,6 +14,7 @@ export const TOKEN_INFO_ERC_20: TokenInfo<'ERC-20'> = {
symbol: 'STUB',
total_supply: '6000000000000000000',
type: 'ERC-20',
icon_url: null,
};
export const TOKEN_INFO_ERC_721: TokenInfo<'ERC-721'> = {
+10
View File
@@ -50,6 +50,16 @@ const colors = {
'800': 'RGBA(16, 17, 18, 0.80)',
'900': 'RGBA(16, 17, 18, 0.92)',
},
github: '#171923',
telegram: '#2775CA',
linkedin: '#1564BA',
discord: '#9747FF',
slack: '#1BA27A',
twitter: '#63B3ED',
opensea: '#2081E2',
facebook: '#4460A0',
medium: '#231F20',
reddit: '#FF4500',
};
export default colors;
+2 -1
View File
@@ -1,10 +1,11 @@
import { theme } from '@chakra-ui/react';
export const BODY_TYPEFACE = 'Inter';
export const HEADING_TYPEFACE = 'Poppins';
const typography = {
fonts: {
heading: `Poppins, ${ theme.fonts.heading }`,
heading: `${ HEADING_TYPEFACE }, ${ theme.fonts.heading }`,
body: `${ BODY_TYPEFACE }, ${ theme.fonts.body }`,
},
textStyles: {
+1 -1
View File
@@ -3,7 +3,6 @@ const zIndices = {
auto: 'auto',
base: 0,
docked: 10,
tooltip: 900,
dropdown: 1000,
sticky: 1100,
sticky1: 1101,
@@ -12,6 +11,7 @@ const zIndices = {
overlay: 1300,
modal: 1400,
popover: 1500,
tooltip: 1550, // otherwise tooltips will not be visible in modals
skipLink: 1600,
toast: 1700,
};
+55
View File
@@ -160,3 +160,58 @@ export type PublicTagErrors = {
full_name: Array<string>;
tags: Array<string>;
}
export interface VerifiedAddress {
userId: string;
chainId: string;
contractAddress: string;
verifiedDate: string;
metadata: {
tokenName: string | null;
tokenSymbol: string | null;
};
}
export interface VerifiedAddressResponse {
verifiedAddresses: Array<VerifiedAddress>;
}
export interface TokenInfoApplicationConfig {
projectSectors: Array<string>;
}
export interface TokenInfoApplication {
adminComments?: string;
coinGeckoTicker?: string;
coinMarketCapTicker?: string;
comment?: string;
defiLlamaTicker?: string;
discord?: string;
docs?: string;
facebook?: string;
github?: string;
iconUrl: string;
id: string;
linkedin?: string;
medium?: string;
openSea?: string;
projectDescription?: string;
projectEmail: string;
projectName?: string;
projectSector?: string;
projectWebsite: string;
reddit?: string;
requesterEmail: string;
requesterName: string;
slack?: string;
status: 'STATUS_UNKNOWN' | 'IN_PROCESS' | 'APPROVED' | 'REJECTED' | 'UPDATE_REQUIRED';
support?: string;
telegram?: string;
tokenAddress: string;
twitter?: string;
updatedAt: string;
}
export interface TokenInfoApplications {
submissions: Array<TokenInfoApplication>;
}
+4 -6
View File
@@ -1,12 +1,12 @@
import type { Transaction } from 'types/api/transaction';
import type { AddressTag, WatchlistName } from './addressParams';
import type { UserTags } from './addressParams';
import type { Block } from './block';
import type { InternalTransaction } from './internalTransaction';
import type { TokenInfo, TokenType } from './token';
import type { TokenInfo, TokenInstance, TokenType } from './token';
import type { TokenTransfer, TokenTransferPagination } from './tokenTransfer';
export interface Address {
export interface Address extends UserTags {
block_number_balance_updated_at: number | null;
coin_balance: string | null;
creator_address_hash: string | null;
@@ -30,11 +30,8 @@ export interface Address {
is_contract: boolean;
is_verified: boolean;
name: string | null;
private_tags: Array<AddressTag> | null;
public_tags: Array<AddressTag> | null;
token: TokenInfo | null;
watchlist_address_id: number | null;
watchlist_names: Array<WatchlistName> | null;
}
export interface AddressCounters {
@@ -48,6 +45,7 @@ export interface AddressTokenBalance {
token: TokenInfo;
token_id: string | null;
value: string;
token_instance?: TokenInstance;
}
export interface AddressTokensResponse {
+7 -4
View File
@@ -9,13 +9,16 @@ export interface WatchlistName {
display_name: string;
}
export interface AddressParam {
export interface UserTags {
private_tags: Array<AddressTag> | null;
watchlist_names: Array<WatchlistName> | null;
public_tags: Array<AddressTag> | null;
}
export interface AddressParam extends UserTags {
hash: string;
implementation_name: string | null;
name: string | null;
is_contract: boolean;
is_verified: boolean | null;
private_tags: Array<AddressTag> | null;
watchlist_names: Array<WatchlistName> | null;
public_tags: Array<AddressTag> | null;
}
+4
View File
@@ -1,3 +1,4 @@
import type { TokenInfoApplication } from './account';
import type { AddressParam } from './addressParams';
export type TokenType = 'ERC-20' | 'ERC-721' | 'ERC-1155';
@@ -11,6 +12,7 @@ export interface TokenInfo<T extends TokenType = TokenType> {
holders: string | null;
exchange_rate: string | null;
total_supply: string | null;
icon_url: string | null;
}
export interface TokenCounters {
@@ -57,3 +59,5 @@ export interface TokenInventoryResponse {
export type TokenInventoryPagination = {
unique_token: number;
}
export type TokenVerifiedInfo = Omit<TokenInfoApplication, 'id' | 'status'>;
+9
View File
@@ -70,6 +70,15 @@ export interface TransactionsResponsePending {
} | null;
}
export interface TransactionsResponseWatchlist {
items: Array<Transaction>;
next_page_params: {
inserted_at: string;
hash: string;
filter: 'pending';
} | null;
}
export type TransactionType = 'token_transfer' | 'contract_creation' | 'contract_call' | 'token_creation' | 'coin_transfer'
export type TxsResponse = TransactionsResponseValidated | TransactionsResponsePending | BlockTransactionsResponse;
+5
View File
@@ -16,3 +16,8 @@ export type WithdrawalsItem = {
timestamp: string;
validator_index: number;
}
export type WithdrawalsCounters = {
withdrawal_count: string;
withdrawal_sum: string;
}
@@ -1,14 +1,15 @@
export type AppItemPreview = {
export type MarketplaceAppPreview = {
id: string;
external?: boolean;
title: string;
logo: string;
logoDarkMode?: string;
shortDescription: string;
categories: Array<string>;
url: string;
}
export type AppItemOverview = AppItemPreview & {
export type MarketplaceAppOverview = MarketplaceAppPreview & {
author: string;
description: string;
site?: string;
@@ -17,7 +18,7 @@ export type AppItemOverview = AppItemPreview & {
github?: string;
}
export enum AppCategory {
export enum MarketplaceCategory {
ALL = 'All apps',
FAVORITES = 'Favorites',
}
+23
View File
@@ -0,0 +1,23 @@
import type { Route } from 'nextjs-routes';
type NavItemCommon = {
text: string;
icon?: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
}
export type NavItemInternal = NavItemCommon & {
nextRoute: Route;
isActive?: boolean;
isNewUi?: boolean;
}
export type NavItemExternal = NavItemCommon & {
url: string;
}
export type NavItem = NavItemInternal | NavItemExternal
export type NavGroupItem = NavItemCommon & {
isActive?: boolean;
subItems: Array<NavItem> | Array<Array<NavItem>>;
}
+2
View File
@@ -15,6 +15,8 @@ export interface NetworkExplorer {
paths: {
tx?: string;
address?: string;
token?: string;
block?: string;
};
}
+1
View File
@@ -10,6 +10,7 @@ declare module "nextjs-routes" {
| StaticRoute<"/account/custom_abi">
| StaticRoute<"/account/public_tags_request">
| StaticRoute<"/account/tag_address">
| StaticRoute<"/account/verified_addresses">
| StaticRoute<"/account/watchlist">
| StaticRoute<"/accounts">
| DynamicRoute<"/address/[hash]/contract_verification", { "hash": string }>
+8 -69
View File
@@ -1,93 +1,32 @@
import { useColorModeValue, useToken } from '@chakra-ui/react';
import {
EthereumClient,
modalConnectors,
walletConnectProvider,
} from '@web3modal/ethereum';
import { Web3Modal } from '@web3modal/react';
import React from 'react';
import type { Chain } from 'wagmi';
import { configureChains, createClient, WagmiConfig } from 'wagmi';
import type { RoutedSubTab } from 'ui/shared/RoutedTabs/types';
import type { RoutedSubTab } from 'ui/shared/Tabs/types';
import appConfig from 'configs/app/config';
import { ContractContextProvider } from 'ui/address/contract/context';
import RoutedTabs from 'ui/shared/RoutedTabs/RoutedTabs';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
import Web3ModalProvider from 'ui/shared/Web3ModalProvider';
interface Props {
tabs: Array<RoutedSubTab>;
addressHash?: string;
}
const { wagmiClient, ethereumClient } = (() => {
try {
const currentChain: Chain = {
id: Number(appConfig.network.id),
name: appConfig.network.name || '',
network: appConfig.network.name || '',
nativeCurrency: {
decimals: appConfig.network.currency.decimals,
name: appConfig.network.currency.name || '',
symbol: appConfig.network.currency.symbol || '',
},
rpcUrls: {
'default': {
http: [ appConfig.network.rpcUrl || '' ],
},
},
blockExplorers: {
'default': {
name: 'Blockscout',
url: appConfig.baseUrl,
},
},
};
const chains = [ currentChain ];
const { provider } = configureChains(chains, [
walletConnectProvider({ projectId: appConfig.walletConnect.projectId || '' }),
]);
const wagmiClient = createClient({
autoConnect: true,
connectors: modalConnectors({ appName: 'web3Modal', chains }),
provider,
});
const ethereumClient = new EthereumClient(wagmiClient, chains);
return { wagmiClient, ethereumClient };
} catch (error) {
return { wagmiClient: undefined, ethereumClient: undefined };
}
})();
const TAB_LIST_PROPS = {
columnGap: 3,
};
const AddressContract = ({ addressHash, tabs }: Props) => {
const modalZIndex = useToken<string>('zIndices', 'modal');
const web3ModalTheme = useColorModeValue('light', 'dark');
const noProviderTabs = React.useMemo(() => tabs.filter(({ id }) => id === 'contact_code'), [ tabs ]);
if (!wagmiClient || !ethereumClient) {
const fallback = React.useCallback(() => {
const noProviderTabs = tabs.filter(({ id }) => id === 'contact_code');
return <RoutedTabs tabs={ noProviderTabs } variant="outline" colorScheme="gray" size="sm" tabListProps={ TAB_LIST_PROPS }/>;
}
}, [ tabs ]);
return (
<WagmiConfig client={ wagmiClient }>
<Web3ModalProvider fallback={ fallback }>
<ContractContextProvider addressHash={ addressHash }>
<RoutedTabs tabs={ tabs } variant="outline" colorScheme="gray" size="sm" tabListProps={ TAB_LIST_PROPS }/>
</ContractContextProvider>
<Web3Modal
projectId={ appConfig.walletConnect.projectId }
ethereumClient={ ethereumClient }
themeZIndex={ Number(modalZIndex) }
themeMode={ web3ModalTheme }
themeBackground="themeColor"
/>
</WagmiConfig>
</Web3ModalProvider>
);
};
+1 -13
View File
@@ -1,4 +1,4 @@
import { Box, Flex, Text, Icon, Grid } from '@chakra-ui/react';
import { Box, Text, Icon, Grid } from '@chakra-ui/react';
import type { UseQueryResult } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { route } from 'nextjs-routes';
@@ -6,7 +6,6 @@ import React from 'react';
import type { Address as TAddress } from 'types/api/address';
import appConfig from 'configs/app/config';
import blockIcon from 'icons/block.svg';
import type { ResourceError } from 'lib/api/resources';
import useApiQuery from 'lib/api/useApiQuery';
@@ -18,7 +17,6 @@ import DataFetchAlert from 'ui/shared/DataFetchAlert';
import DetailsInfoItem from 'ui/shared/DetailsInfoItem';
import DetailsSponsoredItem from 'ui/shared/DetailsSponsoredItem';
import HashStringShortenDynamic from 'ui/shared/HashStringShortenDynamic';
import LinkExternal from 'ui/shared/LinkExternal';
import LinkInternal from 'ui/shared/LinkInternal';
import AddressBalance from './details/AddressBalance';
@@ -83,21 +81,11 @@ const AddressDetails = ({ addressQuery, scrollRef }: Props) => {
return <AddressDetailsSkeleton/>;
}
const explorers = appConfig.network.explorers.filter(({ paths }) => paths.address);
const data = addressQuery.isError ? errorData : addressQuery.data;
return (
<Box>
<AddressHeadingInfo address={ data } token={ data.token } isLinkDisabled/>
{ explorers.length > 0 && (
<Flex mt={ 8 } columnGap={ 4 } flexWrap="wrap">
<Text fontSize="sm">Verify with other explorers</Text>
{ explorers.map((explorer) => {
const url = new URL(explorer.paths.address + '/' + addressHash, explorer.baseUrl);
return <LinkExternal key={ explorer.baseUrl } href={ url.toString() }>{ explorer.title }</LinkExternal>;
}) }
</Flex>
) }
<Grid
mt={ 8 }
columnGap={ 8 }
+7 -1
View File
@@ -194,11 +194,17 @@ const AddressTokenTransfers = ({ scrollRef }: {scrollRef?: React.RefObject<HTMLD
</>
) : null;
const tokenData = React.useMemo(() => ({
address: tokenFilter || '',
name: '',
icon_url: '',
}), [ tokenFilter ]);
const tokenFilterComponent = tokenFilter && (
<Flex alignItems="center" flexWrap="wrap" mb={{ base: isActionBarHidden ? 3 : 6, lg: 0 }} mr={ 4 }>
<Text whiteSpace="nowrap" mr={ 2 } py={ 1 }>Filtered by token</Text>
<Flex alignItems="center" py={ 1 }>
<TokenLogo hash={ tokenFilter } boxSize={ 6 } mr={ 2 }/>
<TokenLogo data={ tokenData } boxSize={ 6 } mr={ 2 }/>
{ isMobile ? <HashStringShorten hash={ tokenFilter }/> : tokenFilter }
<Tooltip label="Reset filter">
<Flex>
+1 -1
View File
@@ -9,7 +9,7 @@ import useQueryWithPages from 'lib/hooks/useQueryWithPages';
import { tokenTabsByType } from 'ui/pages/Address';
import Pagination from 'ui/shared/Pagination';
import type { Props as PaginationProps } from 'ui/shared/Pagination';
import RoutedTabs from 'ui/shared/RoutedTabs/RoutedTabs';
import RoutedTabs from 'ui/shared/Tabs/RoutedTabs';
import ERC1155Tokens from './tokens/ERC1155Tokens';
import ERC20Tokens from './tokens/ERC20Tokens';
Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 27 KiB

+1 -1
View File
@@ -222,7 +222,7 @@ const ContractCode = ({ addressHash, noSocket }: Props) => {
<RawDataSnippet
data={ data.creation_bytecode }
title="Contract creation code"
rightSlot={ data.is_verified ? null : verificationButton }
rightSlot={ data.is_verified || data.is_self_destructed ? null : verificationButton }
beforeSlot={ data.is_self_destructed ? (
<Alert status="info" whiteSpace="pre-wrap" mb={ 3 }>
Contracts that self destruct in their constructors have no contract code published and cannot be verified.
+7 -2
View File
@@ -63,6 +63,12 @@ const AddressBalance = ({ data }: Props) => {
handler: handleNewCoinBalanceMessage,
});
const tokenData = React.useMemo(() => ({
address: appConfig.network.currency.address || '',
name: appConfig.network.currency.name || '',
icon_url: '',
}), [ ]);
return (
<DetailsInfoItem
title="Balance"
@@ -71,8 +77,7 @@ const AddressBalance = ({ data }: Props) => {
alignItems="flex-start"
>
<TokenLogo
hash={ appConfig.network.currency.address }
name={ appConfig.network.currency.name }
data={ tokenData }
boxSize={ 5 }
mr={ 2 }
fontSize="sm"
+5 -9
View File
@@ -3,15 +3,13 @@ import { useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import React from 'react';
import type { UserInfo } from 'types/api/account';
import starFilledIcon from 'icons/star_filled.svg';
import starOutlineIcon from 'icons/star_outline.svg';
import type { ResourceError } from 'lib/api/resources';
import { resourceKey } from 'lib/api/resources';
import { getResourceKey } from 'lib/api/useApiQuery';
import useLoginUrl from 'lib/hooks/useLoginUrl';
import usePreventFocusAfterModalClosing from 'lib/hooks/usePreventFocusAfterModalClosing';
import useRedirectIfNotAuth from 'lib/hooks/useRedirectIfNotAuth';
import useToast from 'lib/hooks/useToast';
import WatchlistAddModal from 'ui/watchlist/AddressModal/AddressModal';
import DeleteAddressModal from 'ui/watchlist/DeleteAddressModal';
@@ -29,10 +27,9 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
const router = useRouter();
const toast = useToast();
const profileData = queryClient.getQueryData<UserInfo>([ resourceKey('user_info') ]);
const redirectIfNotAuth = useRedirectIfNotAuth();
const profileState = queryClient.getQueryState<unknown, ResourceError<{ message: string }>>([ resourceKey('user_info') ]);
const isAuth = Boolean(profileData);
const loginUrl = useLoginUrl();
const handleClick = React.useCallback(() => {
if (profileState?.error?.status === 403) {
@@ -50,12 +47,11 @@ const AddressFavoriteButton = ({ className, hash, watchListId }: Props) => {
}
}
if (!isAuth) {
window.location.assign(loginUrl);
if (redirectIfNotAuth()) {
return;
}
watchListId ? deleteModalProps.onOpen() : addModalProps.onOpen();
}, [ profileState?.error, isAuth, watchListId, deleteModalProps, addModalProps, loginUrl, toast ]);
}, [ profileState, redirectIfNotAuth, watchListId, deleteModalProps, addModalProps, toast ]);
const handleAddOrDeleteSuccess = React.useCallback(async() => {
const queryKey = getResourceKey('address', { pathParams: { hash: router.query.hash?.toString() } });
+1 -1
View File
@@ -65,7 +65,7 @@ const TokenSelectItem = ({ data }: Props) => {
href={ url }
>
<Flex alignItems="center" w="100%">
<TokenLogo hash={ data.token.address } name={ data.token.name } boxSize={ 6 }/>
<TokenLogo data={ data.token } boxSize={ 6 }/>
<Text fontWeight={ 700 } ml={ 2 }>{ data.token.name || <HashStringShorten hash={ data.token.address }/> }</Text>
{ data.usd && <Text fontWeight={ 700 } ml="auto">${ data.usd.toFormat(2) }</Text> }
</Flex>
+1 -1
View File
@@ -24,7 +24,7 @@ const ERC20TokensListItem = ({ token, value }: Props) => {
return (
<ListItemMobile rowGap={ 2 }>
<Flex alignItems="center" width="100%">
<TokenLogo hash={ token.address } name={ token.name } boxSize={ 6 } mr={ 2 }/>
<TokenLogo data={ token } boxSize={ 6 } mr={ 2 }/>
<AddressLink fontWeight="700" hash={ token.address } type="token" alias={ tokenString }/>
</Flex>
<Flex alignItems="center" pl={ 8 }>
+1 -1
View File
@@ -27,7 +27,7 @@ const ERC20TokensTableItem = ({
<Tr>
<Td verticalAlign="middle">
<Flex alignItems="center">
<TokenLogo hash={ token.address } name={ token.name } boxSize={ 6 } mr={ 2 }/>
<TokenLogo data={ token } boxSize={ 6 } mr={ 2 }/>
<AddressLink fontWeight="700" hash={ token.address } type="token" alias={ tokenString }/>
</Flex>
</Td>
+6 -2
View File
@@ -1,4 +1,5 @@
import { Flex, HStack, Text } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
import type { AddressTokenBalance } from 'types/api/address';
@@ -12,14 +13,17 @@ import TokenLogo from 'ui/shared/TokenLogo';
type Props = AddressTokenBalance;
const ERC721TokensListItem = ({ token, value }: Props) => {
const router = useRouter();
const hash = router.query.hash?.toString() || '';
const tokenString = [ token.name, token.symbol && `(${ token.symbol })` ].filter(Boolean).join(' ');
return (
<ListItemMobile rowGap={ 2 }>
<Flex alignItems="center" width="100%">
<TokenLogo hash={ token.address } name={ token.name } boxSize={ 6 } mr={ 2 }/>
<AddressLink fontWeight="700" hash={ token.address } type="token" alias={ tokenString }/>
<TokenLogo data={ token } boxSize={ 6 } mr={ 2 }/>
<AddressLink fontWeight="700" hash={ hash } tokenHash={ token.address } type="address_token" alias={ tokenString }/>
</Flex>
<Flex alignItems="center" pl={ 8 }>
<AddressLink hash={ token.address } type="address" truncation="constant"/>
+5 -2
View File
@@ -1,4 +1,5 @@
import { Tr, Td, Flex } from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React from 'react';
import type { AddressTokenBalance } from 'types/api/address';
@@ -14,15 +15,17 @@ const ERC721TokensTableItem = ({
token,
value,
}: Props) => {
const router = useRouter();
const hash = router.query.hash?.toString() || '';
const tokenString = [ token.name, token.symbol && `(${ token.symbol })` ].filter(Boolean).join(' ');
return (
<Tr>
<Td verticalAlign="middle">
<Flex alignItems="center">
<TokenLogo hash={ token.address } name={ token.name } boxSize={ 6 } mr={ 2 }/>
<AddressLink fontWeight="700" hash={ token.address } type="token" alias={ tokenString }/>
<TokenLogo data={ token } boxSize={ 6 } mr={ 2 }/>
<AddressLink fontWeight="700" hash={ hash } tokenHash={ token.address } type="address_token" alias={ tokenString }/>
</Flex>
</Td>
<Td verticalAlign="middle">
+6 -7
View File
@@ -4,13 +4,13 @@ import React from 'react';
import type { AddressTokenBalance } from 'types/api/address';
import NftImage from 'ui/shared/nft/NftImage';
import NftMedia from 'ui/shared/nft/NftMedia';
import TokenLogo from 'ui/shared/TokenLogo';
import TruncatedTextTooltip from 'ui/shared/TruncatedTextTooltip';
type Props = AddressTokenBalance;
const NFTItem = ({ token, token_id: tokenId }: Props) => {
const NFTItem = ({ token, token_id: tokenId, token_instance: tokenInstance }: Props) => {
const tokenLink = route({ pathname: '/token/[hash]', query: { hash: token.address } });
return (
@@ -26,11 +26,10 @@ const NFTItem = ({ token, token_id: tokenId }: Props) => {
lineHeight="20px"
>
<LinkOverlay href={ tokenLink }>
<NftImage
<NftMedia
mb="18px"
url={ null }
fallbackPadding="30px"
cursor="pointer"
imageUrl={ tokenInstance?.image_url || null }
animationUrl={ tokenInstance?.animation_url || null }
/>
</LinkOverlay>
{ tokenId && (
@@ -50,7 +49,7 @@ const NFTItem = ({ token, token_id: tokenId }: Props) => {
) }
{ token.name && (
<Flex alignItems="center">
<TokenLogo hash={ token.address } name={ token.name } boxSize={ 6 } ml={ 1 } mr={ 1 }/>
<TokenLogo data={ token } boxSize={ 6 } ml={ 1 } mr={ 1 }/>
<TruncatedTextTooltip label={ token.name }>
<Text variant="secondary" overflow="hidden" whiteSpace="nowrap" textOverflow="ellipsis">{ token.name }</Text>
</TruncatedTextTooltip>
@@ -0,0 +1,102 @@
import { Icon, Modal, ModalBody, ModalCloseButton, ModalContent, ModalHeader, ModalOverlay, Link } from '@chakra-ui/react';
import React from 'react';
import type { AddressVerificationFormFirstStepFields, AddressCheckStatusSuccess } from './types';
import type { VerifiedAddress } from 'types/api/account';
import eastArrowIcon from 'icons/arrows/east.svg';
import Web3ModalProvider from 'ui/shared/Web3ModalProvider';
import AddressVerificationStepAddress from './steps/AddressVerificationStepAddress';
import AddressVerificationStepSignature from './steps/AddressVerificationStepSignature';
import AddressVerificationStepSuccess from './steps/AddressVerificationStepSuccess';
type StateData = AddressVerificationFormFirstStepFields & AddressCheckStatusSuccess & { isToken?: boolean };
interface Props {
isOpen: boolean;
onClose: () => void;
onSubmit: (address: VerifiedAddress) => void;
onAddTokenInfoClick: (address: string) => void;
onShowListClick: () => void;
defaultAddress?: string;
}
const AddressVerificationModal = ({ defaultAddress, isOpen, onClose, onSubmit, onAddTokenInfoClick, onShowListClick }: Props) => {
const [ stepIndex, setStepIndex ] = React.useState(0);
const [ data, setData ] = React.useState<StateData>({ address: '', signingMessage: '' });
const handleGoToSecondStep = React.useCallback((firstStepResult: typeof data) => {
setData(firstStepResult);
setStepIndex((prev) => prev + 1);
}, []);
const handleGoToThirdStep = React.useCallback((address: VerifiedAddress) => {
onSubmit(address);
setStepIndex((prev) => prev + 1);
setData((prev) => ({ ...prev, isToken: Boolean(address.metadata.tokenName) }));
}, [ onSubmit ]);
const handleGoToPrevStep = React.useCallback(() => {
setStepIndex((prev) => prev - 1);
}, []);
const handleClose = React.useCallback(() => {
onClose();
setStepIndex(0);
setData({ address: '', signingMessage: '' });
}, [ onClose ]);
const handleAddTokenInfoClick = React.useCallback(() => {
onAddTokenInfoClick(data.address);
handleClose();
}, [ handleClose, data.address, onAddTokenInfoClick ]);
const steps = [
{
title: 'Verify new address ownership',
content: <AddressVerificationStepAddress onContinue={ handleGoToSecondStep } defaultAddress={ defaultAddress }/>,
},
{
title: 'Copy and sign message',
content: <AddressVerificationStepSignature { ...data } onContinue={ handleGoToThirdStep }/>,
fallback: <AddressVerificationStepSignature { ...data } onContinue={ handleGoToThirdStep } noWeb3Provider/>,
},
{
title: 'Congrats! Address is verified.',
content: (
<AddressVerificationStepSuccess
onShowListClick={ onShowListClick }
onAddTokenInfoClick={ handleAddTokenInfoClick }
isToken={ data.isToken }
address={ data.address }
/>
),
},
];
const step = steps[stepIndex];
return (
<Modal isOpen={ isOpen } onClose={ handleClose } size={{ base: 'full', lg: 'md' }}>
<ModalOverlay/>
<ModalContent>
<ModalHeader fontWeight="500" textStyle="h3" mb={ 6 }>
{ stepIndex !== 0 && (
<Link mr={ 3 } onClick={ handleGoToPrevStep }>
<Icon as={ eastArrowIcon } boxSize={ 6 } transform="rotate(180deg)" verticalAlign="middle"/>
</Link>
) }
<span>{ step.title }</span>
</ModalHeader>
<ModalCloseButton/>
<ModalBody mb={ 0 }>
<Web3ModalProvider fallback={ step?.fallback || step.content }>
{ step.content }
</Web3ModalProvider>
</ModalBody>
</ModalContent>
</Modal>
);
};
export default React.memo(AddressVerificationModal);
@@ -0,0 +1,48 @@
import { FormControl, Input, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import type { Control, ControllerRenderProps, FormState } from 'react-hook-form';
import { Controller } from 'react-hook-form';
import type { AddressVerificationFormFirstStepFields, RootFields } from '../types';
import { ADDRESS_REGEXP, ADDRESS_LENGTH } from 'lib/validations/address';
import InputPlaceholder from 'ui/shared/InputPlaceholder';
type Fields = RootFields & AddressVerificationFormFirstStepFields;
interface Props {
formState: FormState<Fields>;
control: Control<Fields>;
}
const AddressVerificationFieldAddress = ({ formState, control }: Props) => {
const backgroundColor = useColorModeValue('white', 'gray.900');
const renderControl = React.useCallback(({ field }: {field: ControllerRenderProps<Fields, 'address'>}) => {
const error = 'address' in formState.errors ? formState.errors.address : undefined;
return (
<FormControl variant="floating" id={ field.name } isRequired size="md" backgroundColor={ backgroundColor } mt={ 8 }>
<Input
{ ...field }
required
isInvalid={ Boolean(error) }
maxLength={ ADDRESS_LENGTH }
isDisabled={ formState.isSubmitting }
autoComplete="off"
/>
<InputPlaceholder text="Smart contract address (0x...)" error={ error }/>
</FormControl>
);
}, [ formState.errors, formState.isSubmitting, backgroundColor ]);
return (
<Controller
name="address"
control={ control }
render={ renderControl }
rules={{ required: true, pattern: ADDRESS_REGEXP }}
/>
);
};
export default React.memo(AddressVerificationFieldAddress);

Some files were not shown because too many files have changed in this diff Show More