diff --git a/.env.jungle b/.env.jungle index 06d01497..51f2b382 100644 --- a/.env.jungle +++ b/.env.jungle @@ -88,3 +88,4 @@ REACT_APP_STATE_HISTORY_ENABLED=false REACT_APP_GOOGLE_ANALITIC_PAGE_ID=G-E6Y0EC9FT8 REACT_APP_PUBLIC_RE_CAPTCHA_KEY=key REACT_APP_EOS_INCLUDE_TRANSACTION= +REACT_APP_EVM_ENDPOINT=https://api.testnet.evm.eosnetwork.com diff --git a/.env.mainnet b/.env.mainnet index d55c9dc2..69c80ee4 100644 --- a/.env.mainnet +++ b/.env.mainnet @@ -88,3 +88,4 @@ REACT_APP_STATE_HISTORY_ENABLED=false REACT_APP_GOOGLE_ANALITIC_PAGE_ID=G-E6Y0EC9FT8 REACT_APP_PUBLIC_RE_CAPTCHA_KEY=key REACT_APP_EOS_INCLUDE_TRANSACTION= +REACT_APP_EVM_ENDPOINT='https://api.evm.eosnetwork.com' diff --git a/.env.telos b/.env.telos index 733d880c..8f9200cd 100644 --- a/.env.telos +++ b/.env.telos @@ -17,6 +17,7 @@ HASURA_GRAPHQL_DATABASE_URL=postgres://eoscr:password@postgres:5432/localdb HASURA_GRAPHQL_ADMIN_SECRET=myadminsecretkey HASURA_GRAPHQL_UNAUTHORIZED_ROLE=guest HASURA_GRAPHQL_ACTION_BASE_URL=http://hapi:9090 +HASURA_GRAPHQL_ACTION_EVM_URL=http://hapi-evm:9090 # hapi HAPI_EOS_API_NETWORK_NAME=telos @@ -55,6 +56,25 @@ HAPI_RE_CAPTCHA_PROJECT_ID= HAPI_PUBLIC_RE_CAPTCHA_KEY= HAPI_CREATE_ACCOUNT_ACTION_NAME= +# hapi-evm +HAPI_EVM_SERVER_PORT=9090 +HAPI_EVM_SERVER_ADDRESS=hapi-evm +HAPI_EVM_HASURA_URL=http://hasura:8080/v1/graphql +HAPI_EVM_HASURA_ADMIN_SECRET=myadminsecretkey +HAPI_EVM_DATABASE_URL=postgres://eoscr:password@postgres:5432/localdb +HAPI_EVM_ENDPOINT=https://mainnet.telos.net/evm +HAPI_EVM_API_ENDPOINTS=["https://telos.greymass.com","https://telos.eosphere.io","telos.caleos.io","mainnet.telosusa.io"] +HAPI_EVM_NETWORK_CHAIN_ID=4667b205c6838ef70ff7988f6e8257e8be0e1284a2f59699054a018f743b1d11 +HAPI_EVM_EOS_EVM_ACCOUNT=eosio.evm +HAPI_EVM_BLOCK_INTERVAL_SEC=0.5 +HAPI_EVM_OLD_BLOCK_INTERVAL_SEC=0.1 +HAPI_EVM_ATH_INTERVAL_SEC=60 +HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC=86400 +HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC=86400 +HAPI_EVM_KEEP_HISTORY_FOR_YEARS=1 +HAPI_EVM_HYPERION_API=https://telos.eosusa.io +HAPI_EVM_HYPERION_START_AT=2021-06-02T00:00:00.000+00:00 + #webapp PORT=3000 REACT_APP_VERSION=dev @@ -81,9 +101,12 @@ REACT_APP_EOS_BP_JSON_ON_CHAIN_SCOPE=producerjson REACT_APP_SYNC_TOLERANCE_INTERVAL=180000 REACT_APP_TOKEN_SYMBOL=TLOS REACT_APP_NETWORK_URL=[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}] -REACT_APP_DISABLED_MENU_ITEMS=["/missed-blocks", "/cpu-benchmark","/block-distribution"] +REACT_APP_DISABLED_MENU_ITEMS=["/missed-blocks", "/cpu-benchmark","/block-distribution","stress-test"] REACT_APP_BLOCK_EXPLORER_URL=https://explorer.telos.net/transaction/(transaction) REACT_APP_STATE_HISTORY_ENABLED=false REACT_APP_GOOGLE_ANALITIC_PAGE_ID=G-E6Y0EC9FT8 REACT_APP_PUBLIC_RE_CAPTCHA_KEY=key REACT_APP_EOS_INCLUDE_TRANSACTION= +REACT_APP_EVM_ENDPOINT=https://mainnet.telos.net/evm +REACT_APP_EVM_BLOCK_EXPLORER_URL=https://www.teloscan.io/block/(block) +REACT_APP_EVM_ENDPOINTS=["https://mainnet.telos.net/evm","https://rpc1.eu.telos.net/evm","https://rpc1.us.telos.net/evm","https://rpc2.us.telos.net/evm","https://api.kainosbp.com/evm","https://rpc2.eu.telos.net/evm","https://evm.teloskorea.com/evm","https://rpc2.teloskorea.com/evm","https://rpc01.us.telosunlimited.io/evm"] diff --git a/.env.telostestnet b/.env.telostestnet index 61abd7d3..335da79c 100644 --- a/.env.telostestnet +++ b/.env.telostestnet @@ -17,6 +17,7 @@ HASURA_GRAPHQL_DATABASE_URL=postgres://eoscr:password@postgres:5432/localdb HASURA_GRAPHQL_ADMIN_SECRET=myadminsecretkey HASURA_GRAPHQL_UNAUTHORIZED_ROLE=guest HASURA_GRAPHQL_ACTION_BASE_URL=http://hapi:9090 +HASURA_GRAPHQL_ACTION_EVM_URL=http://hapi-evm:9090 # hapi HAPI_EOS_API_NETWORK_NAME=telos @@ -56,6 +57,25 @@ HAPI_RE_CAPTCHA_PROJECT_ID= HAPI_PUBLIC_RE_CAPTCHA_KEY= HAPI_CREATE_ACCOUNT_ACTION_NAME= +# hapi-evm +HAPI_EVM_SERVER_PORT=9090 +HAPI_EVM_SERVER_ADDRESS=hapi-evm +HAPI_EVM_HASURA_URL=http://hasura:8080/v1/graphql +HAPI_EVM_HASURA_ADMIN_SECRET=myadminsecretkey +HAPI_EVM_DATABASE_URL=postgres://eoscr:password@postgres:5432/localdb +HAPI_EVM_ENDPOINT=https://testnet.telos.net/evm +HAPI_EVM_API_ENDPOINTS=["https://telos-testnet.edenia.cloud","https://telos-testnet.cryptolions.io","https://testnet.telos.eosrio.io","https://test.telos.eosusa.io"] +HAPI_EVM_NETWORK_CHAIN_ID=1eaa0824707c8c16bd25145493bf062aecddfeb56c736f6ba6397f3195f33c9f +HAPI_EVM_EOS_EVM_ACCOUNT=eosio.evm +HAPI_EVM_BLOCK_INTERVAL_SEC=0.5 +HAPI_EVM_OLD_BLOCK_INTERVAL_SEC=0.1 +HAPI_EVM_ATH_INTERVAL_SEC=60 +HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC=86400 +HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC=86400 +HAPI_EVM_KEEP_HISTORY_FOR_YEARS=1 +HAPI_EVM_HYPERION_API=https://test.telos.eosusa.io +HAPI_EVM_HYPERION_START_AT=2021-06-02T00:00:00.000+00:00 + #webapp PORT=3000 REACT_APP_VERSION=dev @@ -82,9 +102,12 @@ REACT_APP_EOS_BP_JSON_ON_CHAIN_SCOPE=producerjson REACT_APP_SYNC_TOLERANCE_INTERVAL=180000 REACT_APP_TOKEN_SYMBOL=TLOS REACT_APP_NETWORK_URL=[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}] -REACT_APP_DISABLED_MENU_ITEMS=["/missed-blocks", "/cpu-benchmark","/block-distribution"] +REACT_APP_DISABLED_MENU_ITEMS=["/missed-blocks", "/cpu-benchmark","/block-distribution","/stress-test"] REACT_APP_BLOCK_EXPLORER_URL=https://explorer-test.telos.net/transaction/(transaction) REACT_APP_STATE_HISTORY_ENABLED=false REACT_APP_GOOGLE_ANALITIC_PAGE_ID=G-E6Y0EC9FT8 REACT_APP_PUBLIC_RE_CAPTCHA_KEY=key -REACT_APP_EOS_INCLUDE_TRANSACTION= \ No newline at end of file +REACT_APP_EOS_INCLUDE_TRANSACTION= +REACT_APP_EVM_ENDPOINT=https://testnet.telos.net/evm +REACT_APP_EVM_BLOCK_EXPLORER_URL=https://testnet.teloscan.io/block/(block) +REACT_APP_EVM_ENDPOINTS=["https://testnet.telos.net/evm"] \ No newline at end of file diff --git a/.github/workflows/deploy-jungle-testnet.yaml b/.github/workflows/deploy-jungle-testnet.yaml index 24338047..12217ce8 100644 --- a/.github/workflows/deploy-jungle-testnet.yaml +++ b/.github/workflows/deploy-jungle-testnet.yaml @@ -52,11 +52,12 @@ jobs: REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000 REACT_APP_TOKEN_SYMBOL: 'EOS' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks","/block-distribution","/cpu-benchmark","/stress-test"]' + REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks","/block-distribution","/cpu-benchmark","/stress-test","/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://jungle4.eosq.eosnation.io/tx/(transaction)' REACT_APP_STATE_HISTORY_ENABLED: 'false' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' REACT_APP_PUBLIC_RE_CAPTCHA_KEY: ${{ secrets.REACT_APP_PUBLIC_RE_CAPTCHA_KEY }} + REACT_APP_EVM_ENDPOINT: 'https://api.testnet.evm.eosnetwork.com' - name: Build kubernetes files id: build_kubernetes_files diff --git a/.github/workflows/deploy-lacchain.yaml b/.github/workflows/deploy-lacchain.yaml index d84ac43a..f11576d4 100644 --- a/.github/workflows/deploy-lacchain.yaml +++ b/.github/workflows/deploy-lacchain.yaml @@ -54,7 +54,7 @@ jobs: REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000 REACT_APP_TOKEN_SYMBOL: '' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '["/undiscoverable-bps","/stress-test"]' + REACT_APP_DISABLED_MENU_ITEMS: '["/undiscoverable-bps","/stress-test","/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://eosio-explorer.lacchain.net/transaction/(transaction)' REACT_APP_STATE_HISTORY_ENABLED: 'true' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' diff --git a/.github/workflows/deploy-libre-testnet.yaml b/.github/workflows/deploy-libre-testnet.yaml index 4b28efa9..b125167b 100644 --- a/.github/workflows/deploy-libre-testnet.yaml +++ b/.github/workflows/deploy-libre-testnet.yaml @@ -56,7 +56,7 @@ jobs: REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000 REACT_APP_TOKEN_SYMBOL: 'LIBRE' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '[]' + REACT_APP_DISABLED_MENU_ITEMS: '["/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://testnet.libre.org/v2/explore/transaction/(transaction)' REACT_APP_STATE_HISTORY_ENABLED: 'true' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' diff --git a/.github/workflows/deploy-libre.yaml b/.github/workflows/deploy-libre.yaml index ca0d264a..06e2207b 100644 --- a/.github/workflows/deploy-libre.yaml +++ b/.github/workflows/deploy-libre.yaml @@ -56,7 +56,7 @@ jobs: REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000 REACT_APP_TOKEN_SYMBOL: 'LIBRE' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '["/stress-test"]' + REACT_APP_DISABLED_MENU_ITEMS: '["/stress-test","/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://www.libreblocks.io/tx/(transaction)' REACT_APP_STATE_HISTORY_ENABLED: 'true' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' diff --git a/.github/workflows/deploy-mainnet.yaml b/.github/workflows/deploy-mainnet.yaml index d612b9c1..093ac736 100644 --- a/.github/workflows/deploy-mainnet.yaml +++ b/.github/workflows/deploy-mainnet.yaml @@ -53,11 +53,12 @@ jobs: REACT_APP_EOS_API_NETWORK_LOGO: 'https://antelope.tools/images/eos.png' REACT_APP_TOKEN_SYMBOL: 'EOS' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks", "/cpu-benchmark","/block-distribution","/stress-test"]' + REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks", "/cpu-benchmark","/block-distribution","/stress-test","/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://bloks.io/transaction/(transaction)' REACT_APP_STATE_HISTORY_ENABLED: 'false' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' REACT_APP_PUBLIC_RE_CAPTCHA_KEY: ${{ secrets.REACT_APP_PUBLIC_RE_CAPTCHA_KEY }} + REACT_APP_EVM_ENDPOINT: 'https://api.evm.eosnetwork.com' - name: Build and deploy kubernetes files id: build_kubernetes_files diff --git a/.github/workflows/deploy-proton-testnet.yaml b/.github/workflows/deploy-proton-testnet.yaml index 3996b2a4..d7b85d06 100644 --- a/.github/workflows/deploy-proton-testnet.yaml +++ b/.github/workflows/deploy-proton-testnet.yaml @@ -56,7 +56,7 @@ jobs: REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000 REACT_APP_TOKEN_SYMBOL: 'XPR' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks","/block-distribution","/cpu-benchmark","/stress-test"]' + REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks","/block-distribution","/cpu-benchmark","/stress-test","/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://testnet.protonscan.io/transaction/(transaction)' REACT_APP_STATE_HISTORY_ENABLED: 'false' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' diff --git a/.github/workflows/deploy-proton.yaml b/.github/workflows/deploy-proton.yaml index 72d62eab..4ed7fe13 100644 --- a/.github/workflows/deploy-proton.yaml +++ b/.github/workflows/deploy-proton.yaml @@ -56,7 +56,7 @@ jobs: REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000 REACT_APP_TOKEN_SYMBOL: 'XPR' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks","/block-distribution","/cpu-benchmark","/stress-test"]' + REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks","/block-distribution","/cpu-benchmark","/stress-test","/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://www.protonscan.io/transaction/(transaction)' REACT_APP_STATE_HISTORY_ENABLED: 'false' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' diff --git a/.github/workflows/deploy-telos-testnet.yaml b/.github/workflows/deploy-telos-testnet.yaml index c4d18507..3cbd1e9a 100644 --- a/.github/workflows/deploy-telos-testnet.yaml +++ b/.github/workflows/deploy-telos-testnet.yaml @@ -61,12 +61,16 @@ jobs: REACT_APP_STATE_HISTORY_ENABLED=: 'false' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' REACT_APP_PUBLIC_RE_CAPTCHA_KEY: ${{ secrets.REACT_APP_PUBLIC_RE_CAPTCHA_KEY }} + REACT_APP_EVM_ENDPOINT: 'https://testnet.telos.net/evm' + REACT_APP_EVM_BLOCK_EXPLORER_URL: 'https://testnet.teloscan.io/block/(block)' + REACT_APP_EVM_ENDPOINTS: '[\"https://testnet.telos.net/evm\"]' - name: Build and deploy kubernetes files id: build_kubernetes_files run: | make \ - build-kubernetes + build-kubernetes \ + build-kubernetes-evm env: # general NAMESPACE: telos-testnet-dashboard @@ -104,12 +108,31 @@ jobs: HAPI_EOS_EXCHANGE_RATE_API: 'https://api.coingecko.com/api/v3/simple/price?ids=telos&vs_currencies=usd' HAPI_COINGECKO_API_TOKEN_ID: telos HAPI_REWARDS_TOKEN: TLOS + # hapi-evm + HAPI_EVM_SERVER_PORT: '9090' + HAPI_EVM_SERVER_ADDRESS: '0.0.0.0' + HAPI_EVM_HASURA_URL: 'http://dashboard-hasura:8080/v1/graphql' + HAPI_EVM_HASURA_ADMIN_SECRET: ${{ secrets.HAPI_EVM_HASURA_ADMIN_SECRET }} + HAPI_EVM_DATABASE_URL: ${{ secrets.HAPI_EVM_DATABASE_URL }} + HAPI_EVM_ENDPOINT: 'https://testnet.telos.net/evm' + HAPI_EVM_API_ENDPOINTS: '["https://telos-testnet.edenia.cloud","https://telos-testnet.cryptolions.io","https://testnet.telos.eosrio.io","https://test.telos.eosusa.io"]' + HAPI_EVM_NETWORK_CHAIN_ID: 1eaa0824707c8c16bd25145493bf062aecddfeb56c736f6ba6397f3195f33c9f + HAPI_EVM_EOS_EVM_ACCOUNT: ${{ secrets.HAPI_EVM_EOS_EVM_ACCOUNT }} + HAPI_EVM_BLOCK_INTERVAL_SEC: ${{ secrets.HAPI_EVM_BLOCK_INTERVAL_SEC }} + HAPI_EVM_OLD_BLOCK_INTERVAL_SEC: ${{ secrets.HAPI_EVM_OLD_BLOCK_INTERVAL_SEC }} + HAPI_EVM_ATH_INTERVAL_SEC: ${{ secrets.HAPI_EVM_ATH_INTERVAL_SEC }} + HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC: ${{ secrets.HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC }} + HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC: ${{ secrets.HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC }} + HAPI_EVM_KEEP_HISTORY_FOR_YEARS: ${{ secrets.HAPI_EVM_KEEP_HISTORY_FOR_YEARS }} + HAPI_EVM_HYPERION_API: ${{ secrets.HAPI_EVM_HYPERION_API }} + HAPI_EVM_HYPERION_START_AT: ${{ secrets.HAPI_EVM_HYPERION_START_AT }} # hasura HASURA_GRAPHQL_ENABLE_CONSOLE: 'true' HASURA_GRAPHQL_DATABASE_URL: ${{ secrets.HASURA_GRAPHQL_DATABASE_URL }} HASURA_GRAPHQL_ADMIN_SECRET: ${{ secrets.HASURA_GRAPHQL_ADMIN_SECRET }} HASURA_GRAPHQL_UNAUTHORIZED_ROLE: guest HASURA_GRAPHQL_ACTION_BASE_URL: http://dashboard-hapi:9090 + HASURA_GRAPHQL_ACTION_EVM_URL: http://dashboard-hapi-evm:9090 - name: Setup and deploy kubernetes environment uses: steebchen/kubectl@v1.1.0 diff --git a/.github/workflows/deploy-telos.yaml b/.github/workflows/deploy-telos.yaml index eaff756e..3cf0807e 100644 --- a/.github/workflows/deploy-telos.yaml +++ b/.github/workflows/deploy-telos.yaml @@ -61,12 +61,16 @@ jobs: REACT_APP_STATE_HISTORY_ENABLED=: 'false' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' REACT_APP_PUBLIC_RE_CAPTCHA_KEY: ${{ secrets.REACT_APP_PUBLIC_RE_CAPTCHA_KEY }} + REACT_APP_EVM_ENDPOINT: 'https://mainnet.telos.net/evm' + REACT_APP_EVM_BLOCK_EXPLORER_URL: 'https://www.teloscan.io/block/(block)' + REACT_APP_EVM_ENDPOINTS: '[\"https://rpc1.eu.telos.net/evm\",\"https://api.kainosbp.com/evm\",\"https://mainnet.telos.net/evm\",\"https://rpc1.us.telos.net/evm\",\"https://rpc2.eu.telos.net/evm\",\"https://rpc2.us.telos.net/evm\",\"https://evm.teloskorea.com/evm\",\"https://rpc2.teloskorea.com/evm\",\"https://rpc01.us.telosunlimited.io/evm\"]' - name: Build and deploy kubernetes files id: build_kubernetes_files run: | make \ - build-kubernetes + build-kubernetes \ + build-kubernetes-evm env: # general NAMESPACE: telos-dashboard @@ -104,12 +108,31 @@ jobs: HAPI_EOS_EXCHANGE_RATE_API: 'https://api.coingecko.com/api/v3/simple/price?ids=telos&vs_currencies=usd' HAPI_COINGECKO_API_TOKEN_ID: telos HAPI_REWARDS_TOKEN: TLOS + # hapi-evm + HAPI_EVM_SERVER_PORT: '9090' + HAPI_EVM_SERVER_ADDRESS: '0.0.0.0' + HAPI_EVM_HASURA_URL: 'http://dashboard-hasura:8080/v1/graphql' + HAPI_EVM_HASURA_ADMIN_SECRET: ${{ secrets.HAPI_EVM_HASURA_ADMIN_SECRET }} + HAPI_EVM_DATABASE_URL: ${{ secrets.HAPI_EVM_DATABASE_URL }} + HAPI_EVM_ENDPOINT: 'https://mainnet.telos.net/evm' + HAPI_EVM_API_ENDPOINTS: '["https://telos.greymass.com","https://telos.eosphere.io","telos.caleos.io","mainnet.telosusa.io"]' + HAPI_EVM_NETWORK_CHAIN_ID: 4667b205c6838ef70ff7988f6e8257e8be0e1284a2f59699054a018f743b1d11 + HAPI_EVM_EOS_EVM_ACCOUNT: ${{ secrets.HAPI_EVM_EOS_EVM_ACCOUNT }} + HAPI_EVM_BLOCK_INTERVAL_SEC: ${{ secrets.HAPI_EVM_BLOCK_INTERVAL_SEC }} + HAPI_EVM_OLD_BLOCK_INTERVAL_SEC: ${{ secrets.HAPI_EVM_OLD_BLOCK_INTERVAL_SEC }} + HAPI_EVM_ATH_INTERVAL_SEC: ${{ secrets.HAPI_EVM_ATH_INTERVAL_SEC }} + HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC: ${{ secrets.HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC }} + HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC: ${{ secrets.HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC }} + HAPI_EVM_KEEP_HISTORY_FOR_YEARS: ${{ secrets.HAPI_EVM_KEEP_HISTORY_FOR_YEARS }} + HAPI_EVM_HYPERION_API: ${{ secrets.HAPI_EVM_HYPERION_API }} + HAPI_EVM_HYPERION_START_AT: ${{ secrets.HAPI_EVM_HYPERION_START_AT }} # hasura HASURA_GRAPHQL_ENABLE_CONSOLE: 'true' HASURA_GRAPHQL_DATABASE_URL: ${{ secrets.HASURA_GRAPHQL_DATABASE_URL }} HASURA_GRAPHQL_ADMIN_SECRET: ${{ secrets.HASURA_GRAPHQL_ADMIN_SECRET }} HASURA_GRAPHQL_UNAUTHORIZED_ROLE: guest HASURA_GRAPHQL_ACTION_BASE_URL: http://dashboard-hapi:9090 + HASURA_GRAPHQL_ACTION_EVM_URL: http://dashboard-hapi-evm:9090 - name: Setup and deploy kubernetes environment uses: steebchen/kubectl@v1.1.0 diff --git a/.github/workflows/deploy-ultra-testnet.yaml b/.github/workflows/deploy-ultra-testnet.yaml index 064324f4..f50f3d34 100644 --- a/.github/workflows/deploy-ultra-testnet.yaml +++ b/.github/workflows/deploy-ultra-testnet.yaml @@ -56,7 +56,7 @@ jobs: REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000 REACT_APP_TOKEN_SYMBOL: 'UOS' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '["/block-producers","/nodes","/missed-blocks","/endpoints","/bpjson","/ricardian-contract","/block-distribution","/nodes-distribution","/cpu-benchmark","/rewards-distribution","/undiscoverable-bps","/endpoints-stats","/stress-test"]' + REACT_APP_DISABLED_MENU_ITEMS: '["/block-producers","/nodes","/missed-blocks","/endpoints","/bpjson","/ricardian-contract","/block-distribution","/nodes-distribution","/cpu-benchmark","/rewards-distribution","/undiscoverable-bps","/endpoints-stats","/stress-test","/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://explorer.testnet.ultra.io/tx/(transaction)' REACT_APP_STATE_HISTORY_ENABLED: 'false' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' diff --git a/.github/workflows/deploy-wax-testnet.yaml b/.github/workflows/deploy-wax-testnet.yaml index 44c346ad..46b05413 100644 --- a/.github/workflows/deploy-wax-testnet.yaml +++ b/.github/workflows/deploy-wax-testnet.yaml @@ -56,7 +56,7 @@ jobs: REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000 REACT_APP_TOKEN_SYMBOL: 'WAX' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks", "/cpu-benchmark","/block-distribution","/stress-test"]' + REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks", "/cpu-benchmark","/block-distribution","/stress-test","/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://wax-test.bloks.io/transaction/(transaction)' REACT_APP_STATE_HISTORY_ENABLED=: 'false' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' diff --git a/.github/workflows/deploy-wax.yaml b/.github/workflows/deploy-wax.yaml index 25b618d2..f968f730 100644 --- a/.github/workflows/deploy-wax.yaml +++ b/.github/workflows/deploy-wax.yaml @@ -56,7 +56,7 @@ jobs: REACT_APP_SYNC_TOLERANCE_INTERVAL: 180000 REACT_APP_TOKEN_SYMBOL: 'WAX' REACT_APP_NETWORK_URL: '[{"label":"EOS","value":"https://eos.antelope.tools","mainnet":true,"pair":"eos","icon":"eos","order":5},{"label":"Proton","value":"https://proton.antelope.tools","mainnet":true,"pair":"proton","icon":"proton","order":3},{"label":"WAX","value":"https://wax.antelope.tools","mainnet":true,"pair":"wax","icon":"wax","order":4},{"label":"Telos","value":"https://telos.antelope.tools","mainnet":true,"pair":"telos","icon":"telos","order":1},{"label":"Libre","value":"https://libre.antelope.tools","mainnet":true,"pair":"libre","icon":"libre","order":2},{"label":"LACChain EOSIO","value":"https://lacchain.antelope.tools","mainnet":true,"pair":null,"icon":"lacchain","order":6},{"label":"Jungle4 Testnet","value":"https://jungle.antelope.tools","mainnet":false,"pair":"eos","icon":"jungle","order":5},{"label":"Proton Testnet","value":"https://proton-testnet.antelope.tools","mainnet":false,"pair":"proton","icon":"proton","order":3},{"label":"WAX Testnet","value":"https://wax-testnet.antelope.tools","mainnet":false,"pair":"wax","icon":"wax","order":4},{"label":"Telos Testnet","value":"https://telos-testnet.antelope.tools","mainnet":false,"pair":"telos","icon":"telos","order":1},{"label":"Libre Testnet","value":"https://libre-testnet.antelope.tools","mainnet":false,"pair":"libre","icon":"libre","order":2},{"label":"Ultra Testnet","value":"https://ultra-testnet.antelope.tools","mainnet":false,"pair":"ultra","icon":"ultra","order":6}]' - REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks", "/cpu-benchmark","/block-distribution","/stress-test"]' + REACT_APP_DISABLED_MENU_ITEMS: '["/missed-blocks", "/cpu-benchmark","/block-distribution","/stress-test","/evm","/evm-rpc-endpoints"]' REACT_APP_BLOCK_EXPLORER_URL: 'https://wax.bloks.io/transaction/(transaction)' REACT_APP_STATE_HISTORY_ENABLED=: 'false' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: 'G-E6Y0EC9FT8' diff --git a/docker-compose.yaml b/docker-compose.yaml index 621bc166..805e5ffd 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -72,6 +72,35 @@ services: HAPI_EOS_MAX_CPU_BLOCK: '${HAPI_EOS_MAX_CPU_BLOCK}' HAPI_EOS_MAX_NET_BLOCK: '${HAPI_EOS_MAX_NET_BLOCK}' HAPI_EOS_MISSED_BLOCKS_ENABLED: '${HAPI_EOS_MISSED_BLOCKS_ENABLED}' + hapi-evm: + container_name: '${STAGE}-${APP_NAME}-hapi-evm' + build: ./hapi-evm + ports: + - '9091:9090' + volumes: + - type: bind + source: ./hapi-evm + target: /app + working_dir: /app + command: bash -c "yarn && yarn start:dev" + environment: + HAPI_EVM_SERVER_PORT: '${HAPI_EVM_SERVER_PORT}' + HAPI_EVM_SERVER_ADDRESS: '${HAPI_EVM_SERVER_ADDRESS}' + HAPI_EVM_HASURA_URL: '${HAPI_EVM_HASURA_URL}' + HAPI_EVM_HASURA_ADMIN_SECRET: '${HAPI_EVM_HASURA_ADMIN_SECRET}' + HAPI_EVM_DATABASE_URL: '${HAPI_EVM_DATABASE_URL}' + HAPI_EVM_ENDPOINT: '${HAPI_EVM_ENDPOINT}' + HAPI_EVM_API_ENDPOINTS: '${HAPI_EVM_API_ENDPOINTS}' + HAPI_EVM_NETWORK_CHAIN_ID: '${HAPI_EVM_NETWORK_CHAIN_ID}' + HAPI_EVM_EOS_EVM_ACCOUNT: '${HAPI_EVM_EOS_EVM_ACCOUNT}' + HAPI_EVM_BLOCK_INTERVAL_SEC: '${HAPI_EVM_BLOCK_INTERVAL_SEC}' + HAPI_EVM_HYPERION_API: '${HAPI_EVM_HYPERION_API}' + HAPI_EVM_HYPERION_START_AT: '${HAPI_EVM_HYPERION_START_AT}' + HAPI_EVM_OLD_BLOCK_INTERVAL_SEC: '${HAPI_EVM_OLD_BLOCK_INTERVAL_SEC}' + HAPI_EVM_ATH_INTERVAL_SEC: '${HAPI_EVM_ATH_INTERVAL_SEC}' + HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC: '${HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC}' + HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC: '${HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC}' + HAPI_EVM_KEEP_HISTORY_FOR_YEARS: '${HAPI_EVM_KEEP_HISTORY_FOR_YEARS}' hasura: container_name: '${STAGE}-${APP_NAME}-hasura' image: hasura/graphql-engine:v2.16.0.cli-migrations-v3 @@ -86,6 +115,7 @@ services: HASURA_GRAPHQL_METADATA_DIR: /metadata HASURA_GRAPHQL_SEEDS_DIR: /seeds HASURA_GRAPHQL_ACTION_BASE_URL: '${HASURA_GRAPHQL_ACTION_BASE_URL}' + HASURA_GRAPHQL_ACTION_EVM_URL: '${HASURA_GRAPHQL_ACTION_EVM_URL}' HASURA_GRAPHQL_ENABLE_CONSOLE: 'true' # Local Development Configurations It is recommended to disable this in production HASURA_GRAPHQL_DEV_MODE: 'true' @@ -136,5 +166,8 @@ services: REACT_APP_GOOGLE_ANALITIC_PAGE_ID: '${REACT_APP_GOOGLE_ANALITIC_PAGE_ID}' REACT_APP_PUBLIC_RE_CAPTCHA_KEY: '${REACT_APP_PUBLIC_RE_CAPTCHA_KEY}' REACT_APP_SYNC_TOLERANCE_INTERVAL: '${REACT_APP_SYNC_TOLERANCE_INTERVAL}' + REACT_APP_EVM_ENDPOINT: '${REACT_APP_EVM_ENDPOINT}' + REACT_APP_EVM_BLOCK_EXPLORER_URL: '${REACT_APP_EVM_BLOCK_EXPLORER_URL}' + REACT_APP_EVM_ENDPOINTS: '${REACT_APP_EVM_ENDPOINTS}' volumes: postgres_data: diff --git a/hapi-evm/.dockerignore b/hapi-evm/.dockerignore new file mode 100644 index 00000000..9ed8767f --- /dev/null +++ b/hapi-evm/.dockerignore @@ -0,0 +1,5 @@ +node_modules/ +.git/ +.gitignore +.eslintrc +Dockerfile diff --git a/hapi-evm/.eslintignore b/hapi-evm/.eslintignore new file mode 100644 index 00000000..f06235c4 --- /dev/null +++ b/hapi-evm/.eslintignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/hapi-evm/.eslintrc b/hapi-evm/.eslintrc new file mode 100644 index 00000000..b15054c9 --- /dev/null +++ b/hapi-evm/.eslintrc @@ -0,0 +1,16 @@ +{ + // "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended" + ], + "parserOptions": { + "ecmaVersion": 2020 + } +} \ No newline at end of file diff --git a/hapi-evm/.gitignore b/hapi-evm/.gitignore new file mode 100644 index 00000000..9aac2c75 --- /dev/null +++ b/hapi-evm/.gitignore @@ -0,0 +1,11 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules + +yarn-debug.log* +yarn-error.log* + +resources/**/* +# yarn +dist \ No newline at end of file diff --git a/hapi-evm/.husky/pre-commit b/hapi-evm/.husky/pre-commit new file mode 100755 index 00000000..2e1ac1ea --- /dev/null +++ b/hapi-evm/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +cd hapi && yarn lint-staged diff --git a/hapi-evm/.prettierrc b/hapi-evm/.prettierrc new file mode 100644 index 00000000..e4b0ccf0 --- /dev/null +++ b/hapi-evm/.prettierrc @@ -0,0 +1,8 @@ +{ + "trailingComma": "none", + "endOfLine": "auto", + "tabWidth": 2, + "singleQuote": true, + "semi": false, + "arrowParens": "avoid" +} diff --git a/hapi-evm/Dockerfile b/hapi-evm/Dockerfile new file mode 100644 index 00000000..76e473de --- /dev/null +++ b/hapi-evm/Dockerfile @@ -0,0 +1,17 @@ +# ---------- Base ---------- +FROM node:16.20.0 as base +WORKDIR /app + +# ---------- Builder ---------- +FROM base AS builder +COPY package.json yarn.lock ./ +RUN yarn --ignore-optional +COPY ./ ./ +RUN yarn build + +# ---------- Release ---------- +FROM base AS release +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/dist ./src +USER node +CMD ["node", "./src/index.js"] diff --git a/hapi-evm/LICENSE b/hapi-evm/LICENSE new file mode 100644 index 00000000..ea23db29 --- /dev/null +++ b/hapi-evm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 EOS Costa Rica + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/hapi-evm/makefile b/hapi-evm/makefile new file mode 100644 index 00000000..f5c9a0e0 --- /dev/null +++ b/hapi-evm/makefile @@ -0,0 +1,42 @@ +include ../utils/meta.mk ../utils/help.mk + +LATEST_TAG ?= latest + +install: ##@local Install all dependencies +install: + @npm install + +clean-install: ##@local Reinstalls all dependencies +clean-install: + @rm -Rf node_modules + @npm install + +run: ##@local Run the project locally (without docker) +run: node_modules + @$(SHELL_EXPORT) npm run dev + +build-docker: ##@devops Build the docker image +build-docker: ./Dockerfile + @docker pull $(DOCKER_REGISTRY)/$(IMAGE_NAME_HAPI_EVM):$(VERSION) || true + @docker build \ + --target release \ + -t $(DOCKER_REGISTRY)/$(IMAGE_NAME_HAPI_EVM):$(VERSION) \ + -t $(DOCKER_REGISTRY)/$(IMAGE_NAME_HAPI_EVM):$(LATEST_TAG) \ + . + +pull-image: ##@devops Pull the latest image from registry for caching +pull-image: + @docker pull $(DOCKER_REGISTRY)/$(IMAGE_NAME_HAPI_EVM):$(LATEST_TAG) || true + +build-docker-cached: ##@devops Build the docker image using cached layers +build-docker-cached: ./Dockerfile + @docker build \ + --target prod-stage \ + --cache-from $(DOCKER_REGISTRY)/$(IMAGE_NAME_HAPI_EVM):$(LATEST_TAG) \ + -t $(DOCKER_REGISTRY)/$(IMAGE_NAME_HAPI_EVM):$(VERSION) \ + -t $(DOCKER_REGISTRY)/$(IMAGE_NAME_HAPI_EVM):$(LATEST_TAG) \ + . + +push-image: ##@devops Push the freshly built image and tag with release or latest tag +push-image: + @docker push $(DOCKER_REGISTRY)/$(IMAGE_NAME_HAPI_EVM):$(VERSION) diff --git a/hapi-evm/nodemon.json b/hapi-evm/nodemon.json new file mode 100644 index 00000000..07b2f249 --- /dev/null +++ b/hapi-evm/nodemon.json @@ -0,0 +1,6 @@ +{ + "watch": ["src"], + "ext": ".ts,.js", + "ignore": [], + "exec": "ts-node ./src/index.ts" +} \ No newline at end of file diff --git a/hapi-evm/package.json b/hapi-evm/package.json new file mode 100644 index 00000000..6b8ee294 --- /dev/null +++ b/hapi-evm/package.json @@ -0,0 +1,51 @@ +{ + "name": "evm-backend", + "version": "1.0.0", + "description": "EVM Dashbaord Backend Service", + "main": "dist/index.js", + "author": "edenia.com", + "license": "MIT", + "scripts": { + "build": "tsc", + "start": "tsc && node dist/index.js", + "start:dev": "nodemon", + "prepare": "cd .. && husky install hapi/.husky" + }, + "lint-staged": { + "*.ts": [ + "eslint . --ext .ts", + "prettier --write" + ] + }, + "dependencies": { + "@hapi/boom": "^10.0.1", + "@hapi/hapi": "^21.3.2", + "@types/web3": "^1.2.2", + "axios": "^1.4.0", + "eosjs": "^22.1.0", + "eosjs-api": "^7.0.4", + "graphql": "16", + "graphql-request": "^6.0.0", + "joi": "^17.9.2", + "moment": "^2.29.4", + "node-fetch": "^3.3.1", + "pg": "^8.6.0", + "sequelize": "^6.32.1", + "web3": "^4.0.3", + "websocket": "^1.0.34" + }, + "devDependencies": { + "@types/node": "^20.1.5", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.40.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^5.0.0", + "husky": "^8.0.3", + "lint-staged": "^13.2.2", + "nodemon": "^3.0.1", + "prettier": "^3.0.0", + "ts-node": "^10.9.1", + "typescript": "^5.0.4" + } +} diff --git a/hapi-evm/src/cache/index.ts b/hapi-evm/src/cache/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/hapi-evm/src/cache/v1/index.ts b/hapi-evm/src/cache/v1/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/hapi-evm/src/config/hasura.config.ts b/hapi-evm/src/config/hasura.config.ts new file mode 100644 index 00000000..0bcdd0b1 --- /dev/null +++ b/hapi-evm/src/config/hasura.config.ts @@ -0,0 +1,7 @@ +export const url = process.env.HAPI_EVM_HASURA_URL || '' +export const adminSecret = process.env.HAPI_EVM_HASURA_ADMIN_SECRET || '' +export const databaseURL = process.env.HAPI_EVM_DATABASE_URL || '' + +if (!url || !adminSecret || !databaseURL) { + throw new Error('Missing required hasura env variables') +} diff --git a/hapi-evm/src/config/hyperion.config.ts b/hapi-evm/src/config/hyperion.config.ts new file mode 100644 index 00000000..5852e926 --- /dev/null +++ b/hapi-evm/src/config/hyperion.config.ts @@ -0,0 +1,4 @@ +export const api = + process.env.HAPI_EVM_HYPERION_API || 'https://test.telos.eosusa.io' +export const startAt = + process.env.HAPI_EVM_HYPERION_START_AT || '2021-06-02T00:00:00.000+00:00' diff --git a/hapi-evm/src/config/index.ts b/hapi-evm/src/config/index.ts new file mode 100644 index 00000000..0f6d6dc9 --- /dev/null +++ b/hapi-evm/src/config/index.ts @@ -0,0 +1,4 @@ +export * as serverConfig from './server.config' +export * as hasuraConfig from './hasura.config' +export * as networkConfig from './network.config' +export * as hyperionConfig from './hyperion.config' diff --git a/hapi-evm/src/config/network.config.ts b/hapi-evm/src/config/network.config.ts new file mode 100644 index 00000000..e97f6b72 --- /dev/null +++ b/hapi-evm/src/config/network.config.ts @@ -0,0 +1,24 @@ +export const evmEndpoint = + process.env.HAPI_EVM_ENDPOINT || 'http://localhost/evm' +export const chainId = process.env.HAPI_EVM_NETWORK_CHAIN_ID || 'chainid1' +export const evmAccount = process.env.HAPI_EVM_EOS_EVM_ACCOUNT || 'eosio.evm' +export const eosEndpoints = + process.env.HAPI_EVM_EOS_EVM_ACCOUNT?.split(',') || [] +export const blockIntervalSec = parseFloat( + process.env.HAPI_EVM_BLOCK_INTERVAL_SEC || '0.5' +) +export const oldBlockIntervalSec = parseFloat( + process.env.HAPI_EVM_OLD_BLOCK_INTERVAL_SEC || '0.1' +) +export const ATHIntervalSec = parseFloat( + process.env.HAPI_EVM_ATH_INTERVAL_SEC || '60' +) +export const cleanOldBlockIntervalSec = parseFloat( + process.env.HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC || '86400' +) +export const cleanOldTransferIntervalSec = parseFloat( + process.env.HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC || '86400' +) +export const keepHistoryForYears = parseInt( + process.env.HAPI_EVM_KEEP_HISTORY_FOR_YEARS || '1' +) diff --git a/hapi-evm/src/config/server.config.ts b/hapi-evm/src/config/server.config.ts new file mode 100644 index 00000000..a6ea4c5a --- /dev/null +++ b/hapi-evm/src/config/server.config.ts @@ -0,0 +1,2 @@ +export const port = process.env.HAPI_EVM_SERVER_PORT +export const host = process.env.HAPI_EVM_SERVER_ADDRESS diff --git a/hapi-evm/src/index.ts b/hapi-evm/src/index.ts new file mode 100644 index 00000000..51a2d106 --- /dev/null +++ b/hapi-evm/src/index.ts @@ -0,0 +1,36 @@ +import Hapi from '@hapi/hapi' +import { Server } from '@hapi/hapi' + +import routes from './routes' +import { serverConfig } from './config' +import workerService from './services/worker' + +const init = async () => { + const server: Server = Hapi.server({ + port: serverConfig.port, + host: serverConfig.host, + routes: { + cors: { origin: ['*'] } + }, + debug: { request: ['handler'] } + }) + + routes(server) + + await server.start() + + workerService.init() + + console.log(`馃殌 Server ready at ${server.info.uri}`) + server.table().forEach(route => console.log(`${route.method}\t${route.path}`)) +} + +process.on('uncaughtException', (err, origin) => { + console.log('Uncaught Exception:', err, 'Exception origin:', origin) +}) + +process.on('unhandledRejection', (reason, promise) => { + console.log('Unhandled Rejection:', promise, 'reason:', reason) +}) + +init() diff --git a/hapi-evm/src/models/block/index.ts b/hapi-evm/src/models/block/index.ts new file mode 100644 index 00000000..5e08e0f1 --- /dev/null +++ b/hapi-evm/src/models/block/index.ts @@ -0,0 +1,2 @@ +export * as interfaces from './interfaces' +export * as queries from './queries' diff --git a/hapi-evm/src/models/block/interfaces.ts b/hapi-evm/src/models/block/interfaces.ts new file mode 100644 index 00000000..46b4d811 --- /dev/null +++ b/hapi-evm/src/models/block/interfaces.ts @@ -0,0 +1,9 @@ +import { TransactionHash, TransactionInfo } from 'web3-types' + +export interface CappedBlock { + hash: string + gas_used: number + transactions: TransactionHash[] | TransactionInfo[] + number: number + timestamp: Date +} diff --git a/hapi-evm/src/models/block/queries.ts b/hapi-evm/src/models/block/queries.ts new file mode 100644 index 00000000..5fbfcbfb --- /dev/null +++ b/hapi-evm/src/models/block/queries.ts @@ -0,0 +1,153 @@ +import moment from 'moment' +import { gql } from 'graphql-request' + +import { networkConfig } from '../../config' +import { coreUtil } from '../../utils' +import { OperationType, TableType, Operation } from '../default.model' +import { CappedBlock } from './interfaces' + +interface BlockAggregateResponse { + evm_block_aggregate: { + aggregate: { + count: number + } + } +} + +interface BlockResponse { + evm_block: CappedBlock[] +} + +interface BlockInsertOneResponse { + insert_evm_block_one: { + hash: string + } +} + +interface BlockDeleteResponse { + delete_evm_block: { + affected_rows: number + } +} + +const internal_get = async ( + type: OperationType = Operation.query, + table: TableType, + parameters: string, + // TODO: not only accept where but also additional content + // such as limit, order, etc + where: object, + order: object | null, + attributes: string, + operation?: string +): Promise => { + const query = gql` + ${type} (${parameters}) { + ${table}${ + operation ? `_${operation}` : '' + }(where: $where, order_by: $order) { + ${attributes} + } + } + ` + + return await coreUtil.hasura.default.request(query, { + where, + order + }) +} + +export const exist = async (hashOrNumber: string | number) => { + const result = await internal_get( + 'query', + 'evm_block', + '$where: evm_block_bool_exp!, $order: [evm_block_order_by!]', + { + [typeof hashOrNumber === 'string' ? 'hash' : 'number']: { + _eq: hashOrNumber + } + }, + null, + 'aggregate { count }', + 'aggregate' + ) + + return result.evm_block_aggregate.aggregate.count > 0 +} + +const get = async ( + where: object, + order: object | null = null, + many = false +) => { + const result = await internal_get( + 'query', + 'evm_block', + '$where: evm_block_bool_exp!, $order: [evm_block_order_by!]', + where, + order, + 'hash, gas_used, transactions, number, timestamp' + ) + + return many ? result.evm_block : result.evm_block[0] +} + +const getCustom = async (query: string) => { + const data = await coreUtil.hasura.default.request(query) + + return data.evm_block +} + +const getNextBlock = async (block: number) => { + const query = gql` + query { + evm_block( + limit: 1 + order_by: { number: asc } + where: { number: { _gt: ${block} } } + ) { + number + } + } + ` + + return await getCustom(query) +} + +export const add_or_modify = async (block: CappedBlock) => { + const mutation = gql` + mutation ($evm_block: evm_block_insert_input!) { + insert_evm_block_one(object: $evm_block) { + hash + } + } + ` + const { insert_evm_block_one: data } = + await coreUtil.hasura.default.request(mutation, { + evm_block: block + }) + + return data +} + +export const deleteOldBlocks = async () => { + const mutation = gql` + mutation ($date: timestamptz) { + delete_evm_block(where: { timestamp: { _lt: $date } }) { + affected_rows + } + } + ` + + await coreUtil.hasura.default.request(mutation, { + date: moment() + .subtract(networkConfig.keepHistoryForYears, 'years') + .format('YYYY-MM-DD') + }) +} + +export default { + exist, + get, + getNextBlock +} diff --git a/hapi-evm/src/models/default.model.ts b/hapi-evm/src/models/default.model.ts new file mode 100644 index 00000000..4e2cf927 --- /dev/null +++ b/hapi-evm/src/models/default.model.ts @@ -0,0 +1,20 @@ +export const Operation = { + query: 'query', + mutation: 'mutation', + subscription: 'subscription' +} as const + +export type OperationType = keyof typeof Operation + +export const Tables = { + evm_block: 'evm_block', + evm_transaction: 'evm_transaction' +} as const + +export type TableType = keyof typeof Tables + +export interface Worker { + name: string + intervalSec?: number + action: () => Promise +} diff --git a/hapi-evm/src/models/historical-stats/index.ts b/hapi-evm/src/models/historical-stats/index.ts new file mode 100644 index 00000000..5e08e0f1 --- /dev/null +++ b/hapi-evm/src/models/historical-stats/index.ts @@ -0,0 +1,2 @@ +export * as interfaces from './interfaces' +export * as queries from './queries' diff --git a/hapi-evm/src/models/historical-stats/interfaces.ts b/hapi-evm/src/models/historical-stats/interfaces.ts new file mode 100644 index 00000000..69998a62 --- /dev/null +++ b/hapi-evm/src/models/historical-stats/interfaces.ts @@ -0,0 +1,17 @@ +export interface HistoricalStats { + id?: string + total_transactions?: number + total_incoming_token?: number + total_outgoing_token?: number + tps_all_time_high?: { + blocks: string[] + transactions_count: number + gas_used: number + } +} + +export interface HistoricalStatsIncInput { + total_transactions?: number + total_incoming_token?: number + total_outgoing_token?: number +} diff --git a/hapi-evm/src/models/historical-stats/queries.ts b/hapi-evm/src/models/historical-stats/queries.ts new file mode 100644 index 00000000..875c0220 --- /dev/null +++ b/hapi-evm/src/models/historical-stats/queries.ts @@ -0,0 +1,138 @@ +import { gql } from 'graphql-request' + +import { coreUtil } from '../../utils' +import { HistoricalStats, HistoricalStatsIncInput } from './interfaces' + +interface HistoricalStatsResponse { + evm_historical_stats: HistoricalStats[] +} + +interface HistoricalStatsOneResponse { + insert_evm_historical_stats_one: { + id: string + } +} + +const defaultHistoricalStats = { + id: '00000000-0000-0000-0000-000000000000', + total_transactions: 0, + total_incoming_token: 0, + total_outgoing_token: 0, + tps_all_time_high: { + blocks: [], + transactions_count: 0, + gas_used: 0 + } +} + +const save = async (payload: HistoricalStats) => { + const mutation = gql` + mutation ($payload: evm_historical_stats_insert_input!) { + insert_evm_historical_stats_one(object: $payload) { + id + } + } + ` + + const data = + await coreUtil.hasura.default.request( + mutation, + { + payload + } + ) + + return data.insert_evm_historical_stats_one +} + +const update = async ( + id: string, + inc: HistoricalStatsIncInput, + payload: HistoricalStats +) => { + const mutation = gql` + mutation ( + $id: uuid! + $inc: evm_historical_stats_inc_input + $payload: evm_historical_stats_set_input + ) { + update_evm_historical_stats_by_pk( + _inc: $inc + pk_columns: { id: $id } + _set: $payload + ) { + id + } + } + ` + + await coreUtil.hasura.default.request(mutation, { + id, + inc, + payload + }) +} + +export const getState = async () => { + const query = gql` + query { + evm_historical_stats( + where: { id: { _neq: "00000000-0000-0000-0000-000000000000" } } + limit: 1 + ) { + id + total_transactions + total_incoming_token + total_outgoing_token + tps_all_time_high + } + } + ` + const data = await coreUtil.hasura.default.request( + query + ) + + if (!data.evm_historical_stats.length) { + return defaultHistoricalStats + } + + const state = data.evm_historical_stats[0] + + return { + id: state.id || defaultHistoricalStats.id, + total_transactions: + state.total_transactions || defaultHistoricalStats.total_transactions, + total_incoming_token: + state.total_incoming_token || defaultHistoricalStats.total_incoming_token, + total_outgoing_token: + state.total_outgoing_token || defaultHistoricalStats.total_outgoing_token, + tps_all_time_high: + state.tps_all_time_high || defaultHistoricalStats.tps_all_time_high + } +} + +export const saveOrUpdate = async (payload: HistoricalStats): Promise => { + const currentState = await getState() + + if (currentState === defaultHistoricalStats) { + await save(payload) + + return + } + + await update(currentState.id, {}, payload) +} + +export const saveOrIncrement = async ( + payload: HistoricalStatsIncInput +): Promise => { + const currentState = await getState() + + if (currentState === defaultHistoricalStats) { + await save(payload) + + return + } + + await update(currentState.id, payload, {}) +} diff --git a/hapi-evm/src/models/history-payload/index.ts b/hapi-evm/src/models/history-payload/index.ts new file mode 100644 index 00000000..c48e15f3 --- /dev/null +++ b/hapi-evm/src/models/history-payload/index.ts @@ -0,0 +1 @@ +export * as interfaces from './interfaces' diff --git a/hapi-evm/src/models/history-payload/interfaces.ts b/hapi-evm/src/models/history-payload/interfaces.ts new file mode 100644 index 00000000..3244d913 --- /dev/null +++ b/hapi-evm/src/models/history-payload/interfaces.ts @@ -0,0 +1,7 @@ +export interface HistoryQuery { + payload: { + input: { + range: string + } + } +} diff --git a/hapi-evm/src/models/hyperion-state/index.ts b/hapi-evm/src/models/hyperion-state/index.ts new file mode 100644 index 00000000..5e08e0f1 --- /dev/null +++ b/hapi-evm/src/models/hyperion-state/index.ts @@ -0,0 +1,2 @@ +export * as interfaces from './interfaces' +export * as queries from './queries' diff --git a/hapi-evm/src/models/hyperion-state/interfaces.ts b/hapi-evm/src/models/hyperion-state/interfaces.ts new file mode 100644 index 00000000..63ef36a0 --- /dev/null +++ b/hapi-evm/src/models/hyperion-state/interfaces.ts @@ -0,0 +1,4 @@ +export interface HyperionState { + id: string + last_synced_at: string +} diff --git a/hapi-evm/src/models/hyperion-state/queries.ts b/hapi-evm/src/models/hyperion-state/queries.ts new file mode 100644 index 00000000..9a02199f --- /dev/null +++ b/hapi-evm/src/models/hyperion-state/queries.ts @@ -0,0 +1,94 @@ +import { gql } from 'graphql-request' + +import { coreUtil } from '../../utils' +import { HyperionState } from './interfaces' + +interface HyperionStateResponse { + evm_hyperion_state: HyperionState[] +} + +interface HyperionStateInsertOneResponse { + insert_evm_hyperion_state_one: { + id: string + } +} + +export const save = async (lastSyncedAt: string) => { + const mutation = gql` + mutation ($payload: evm_hyperion_state_insert_input!) { + insert_evm_hyperion_state_one(object: $payload) { + id + } + } + ` + + const data = + await coreUtil.hasura.default.request( + mutation, + { + payload: { + last_synced_at: lastSyncedAt + } + } + ) + + return data.insert_evm_hyperion_state_one +} + +export const update = async (id: string, lastSyncedAt: string) => { + const mutation = gql` + mutation ($id: uuid!, $payload: evm_hyperion_state_set_input) { + update_evm_hyperion_state_by_pk(pk_columns: { id: $id }, _set: $payload) { + id + last_synced_at + } + } + ` + + await coreUtil.hasura.default.request(mutation, { + id, + payload: { + last_synced_at: lastSyncedAt + } + }) +} + +export const getState = async () => { + const query = gql` + query { + evm_hyperion_state( + where: { id: { _neq: "00000000-0000-0000-0000-000000000000" } } + limit: 1 + ) { + id + last_synced_at + } + } + ` + const data = await coreUtil.hasura.default.request( + query + ) + + if (!data.evm_hyperion_state.length) { + return + } + + const state = data.evm_hyperion_state[0] + + return { + id: state.id, + lastSyncedAt: state.last_synced_at + } +} + +export const saveOrUpdate = async (lastSyncedAt: string) => { + const currentState = await getState() + + if (!currentState) { + await save(lastSyncedAt) + + return + } + + await update(currentState.id, lastSyncedAt) +} diff --git a/hapi-evm/src/models/index.ts b/hapi-evm/src/models/index.ts new file mode 100644 index 00000000..28294e7c --- /dev/null +++ b/hapi-evm/src/models/index.ts @@ -0,0 +1,9 @@ +export * as defaultModel from './default.model' +export * as blockModel from './block' +export * as transactionModel from './transaction' +export * as hyperionStateModel from './hyperion-state' +export * as transferModel from './transfer' +export * as paramModel from './param' +export * as historyPayloadModel from './history-payload' +export * as historicalStatsModel from './historical-stats' +export * as StatsModel from './stats' diff --git a/hapi-evm/src/models/param/index.ts b/hapi-evm/src/models/param/index.ts new file mode 100644 index 00000000..5e08e0f1 --- /dev/null +++ b/hapi-evm/src/models/param/index.ts @@ -0,0 +1,2 @@ +export * as interfaces from './interfaces' +export * as queries from './queries' diff --git a/hapi-evm/src/models/param/interfaces.ts b/hapi-evm/src/models/param/interfaces.ts new file mode 100644 index 00000000..08e89a86 --- /dev/null +++ b/hapi-evm/src/models/param/interfaces.ts @@ -0,0 +1,5 @@ +export interface Param { + id: string + next_block: number + is_synced: boolean +} diff --git a/hapi-evm/src/models/param/queries.ts b/hapi-evm/src/models/param/queries.ts new file mode 100644 index 00000000..4f7eb709 --- /dev/null +++ b/hapi-evm/src/models/param/queries.ts @@ -0,0 +1,109 @@ +import { gql } from 'graphql-request' + +import { coreUtil } from '../../utils' +import { Param } from './interfaces' + +interface ParamResponse { + evm_param: Param[] +} + +interface ParamOneResponse { + insert_evm_param_one: { + id: string + } +} + +const defaultParam = { + id: '00000000-0000-0000-0000-000000000000', + nextBlock: 0, + isSynced: false +} + +export const save = async (nextBlock: number, isSynced: boolean = false) => { + const mutation = gql` + mutation ($payload: evm_param_insert_input!) { + insert_evm_param_one(object: $payload) { + id + } + } + ` + + const data = await coreUtil.hasura.default.request( + mutation, + { + payload: { + next_block: nextBlock, + is_synced: isSynced + } + } + ) + + return data.insert_evm_param_one +} + +export const update = async ( + id: string, + nextBlock: number, + isSynced: boolean = false +) => { + const mutation = gql` + mutation ($id: uuid!, $payload: evm_param_set_input) { + update_evm_param_by_pk(pk_columns: { id: $id }, _set: $payload) { + id + next_block + is_synced + } + } + ` + + await coreUtil.hasura.default.request(mutation, { + id, + payload: { + next_block: nextBlock, + is_synced: isSynced + } + }) +} + +export const getState = async () => { + const query = gql` + query { + evm_param( + where: { id: { _neq: "00000000-0000-0000-0000-000000000000" } } + limit: 1 + ) { + id + next_block + is_synced + } + } + ` + const data = await coreUtil.hasura.default.request(query) + + if (!data.evm_param.length) { + return defaultParam + } + + const state = data.evm_param[0] + + return { + id: state.id, + nextBlock: state.next_block, + isSynced: state.is_synced + } +} + +export const saveOrUpdate = async ( + nextBlock: number, + isSynced: boolean +): Promise => { + const currentState = await getState() + + if (currentState === defaultParam) { + await save(nextBlock, isSynced) + + return + } + + await update(currentState.id, nextBlock, isSynced) +} diff --git a/hapi-evm/src/models/stats/index.ts b/hapi-evm/src/models/stats/index.ts new file mode 100644 index 00000000..5e08e0f1 --- /dev/null +++ b/hapi-evm/src/models/stats/index.ts @@ -0,0 +1,2 @@ +export * as interfaces from './interfaces' +export * as queries from './queries' diff --git a/hapi-evm/src/models/stats/interfaces.ts b/hapi-evm/src/models/stats/interfaces.ts new file mode 100644 index 00000000..ab41d856 --- /dev/null +++ b/hapi-evm/src/models/stats/interfaces.ts @@ -0,0 +1,5 @@ +export interface Stats { + ath_blocks: string + ath_transactions_count: number + ath_gas_used: number +} diff --git a/hapi-evm/src/models/stats/queries.ts b/hapi-evm/src/models/stats/queries.ts new file mode 100644 index 00000000..18ca4935 --- /dev/null +++ b/hapi-evm/src/models/stats/queries.ts @@ -0,0 +1,24 @@ +import { gql } from 'graphql-request' + +import { coreUtil } from '../../utils' +import { Stats } from './interfaces' + +interface StatsResponse { + evm_stats: Stats[] +} + +export const getPartialATH = async () => { + const query = gql` + query { + evm_stats(limit: 1) { + ath_blocks + ath_transactions_count + ath_gas_used + } + } + ` + const data = await coreUtil.hasura.default.request(query) + const state = data.evm_stats[0] + + return state +} diff --git a/hapi-evm/src/models/transaction/index.ts b/hapi-evm/src/models/transaction/index.ts new file mode 100644 index 00000000..5e08e0f1 --- /dev/null +++ b/hapi-evm/src/models/transaction/index.ts @@ -0,0 +1,2 @@ +export * as interfaces from './interfaces' +export * as queries from './queries' diff --git a/hapi-evm/src/models/transaction/interfaces.ts b/hapi-evm/src/models/transaction/interfaces.ts new file mode 100644 index 00000000..a353326f --- /dev/null +++ b/hapi-evm/src/models/transaction/interfaces.ts @@ -0,0 +1,9 @@ +import { TransactionHash, Address } from 'web3-types' + +export interface CappedTransaction { + block_hash: Address + block_number: number + gas: number + gas_price: number + hash: TransactionHash +} diff --git a/hapi-evm/src/models/transaction/queries.ts b/hapi-evm/src/models/transaction/queries.ts new file mode 100644 index 00000000..a5ba8686 --- /dev/null +++ b/hapi-evm/src/models/transaction/queries.ts @@ -0,0 +1,97 @@ +import { gql } from 'graphql-request' + +import { coreUtil } from '../../utils' +import { OperationType, TableType, Operation } from '../default.model' + +import { CappedTransaction } from './interfaces' + +interface TransactionResponse { + evm_transaction: CappedTransaction[] +} + +interface TransactionAggregateResponse { + evm_transaction_aggregate: { + aggregate: { + count: number + } + } +} + +interface TransactionInsertOneResponse { + insert_evm_transaction_one: { + hash: string + } +} + +const internal_get = async ( + type: OperationType = Operation.query, + table: TableType, + parameters: string, + // TODO: not only accept where but also additional content + // such as limit, order, etc + where: object, + attributes: string, + operation?: string +): Promise => { + const gqlObj = gql` + ${type} (${parameters}) { + ${table}${operation ? `_${operation}` : ''}(where: $where) { + ${attributes} + } + } + ` + + return await coreUtil.hasura.default.request(gqlObj, { + where + }) +} + +export const exist = async (hash: string) => { + const result = await internal_get( + Operation.query, + 'evm_transaction', + '$where: evm_transaction_bool_exp!', + { hash: { _eq: hash } }, + 'aggregate { count }', + 'aggregate' + ) + + return result.evm_transaction_aggregate.aggregate.count > 0 +} + +const get = async (where: object, many = false) => { + const result = await internal_get( + 'query', + 'evm_transaction', + '$where: evm_transaction_bool_exp!', + where, + 'hash, gas_used, transactions, number, timestamp' + ) + + return many ? result.evm_transaction : result.evm_transaction[0] +} + +export const add_or_modify = async (transaction: CappedTransaction) => { + const mutation = gql` + mutation ($evm_transaction: evm_transaction_insert_input!) { + insert_evm_transaction_one(object: $evm_transaction) { + hash + } + } + ` + const { insert_evm_transaction_one: data } = + await coreUtil.hasura.default.request( + mutation, + { + evm_transaction: transaction + } + ) + + return data +} + +export default { + exist, + get, + add_or_modify +} diff --git a/hapi-evm/src/models/transfer/index.ts b/hapi-evm/src/models/transfer/index.ts new file mode 100644 index 00000000..5e08e0f1 --- /dev/null +++ b/hapi-evm/src/models/transfer/index.ts @@ -0,0 +1,2 @@ +export * as interfaces from './interfaces' +export * as queries from './queries' diff --git a/hapi-evm/src/models/transfer/interfaces.ts b/hapi-evm/src/models/transfer/interfaces.ts new file mode 100644 index 00000000..7e93f6d9 --- /dev/null +++ b/hapi-evm/src/models/transfer/interfaces.ts @@ -0,0 +1,20 @@ +export const Type = { + incoming: 'incoming', + outgoing: 'outgoing' +} as const + +export type TransferType = keyof typeof Type + +export interface Transfer { + id?: string + block: number + transaction_id: string + from: string + to: string + amount: number + symbol: string + memo: string + quantity: string + timestamp: string + type: TransferType +} diff --git a/hapi-evm/src/models/transfer/queries.ts b/hapi-evm/src/models/transfer/queries.ts new file mode 100644 index 00000000..7d6b454c --- /dev/null +++ b/hapi-evm/src/models/transfer/queries.ts @@ -0,0 +1,67 @@ +import moment from 'moment' +import { gql } from 'graphql-request' + +import { networkConfig } from '../../config' +import { coreUtil } from '../../utils' +import { Transfer, Type } from './interfaces' +import { historicalStatsModel } from '..' + +// interface TransferResponse { +// evm_transfer: Transfer[] +// } + +interface TransferInsertOneResponse { + insert_evm_transfer_one: { + id: string + } +} + +interface TransferDeleteResponse { + delete_evm_transfer: { + affected_rows: number + } +} + +export const save = async (payload: Transfer) => { + const mutation = gql` + mutation ($payload: evm_transfer_insert_input!) { + insert_evm_transfer_one(object: $payload) { + id + } + } + ` + + await historicalStatsModel.queries.saveOrIncrement({ + total_incoming_token: Number(payload.type === Type.incoming), + total_outgoing_token: Number(payload.type === Type.outgoing) + }) + + if (moment(payload.timestamp).isBefore(moment().subtract(1, 'years'))) { + return + } + + const data = await coreUtil.hasura.default.request( + mutation, + { + payload + } + ) + + return data.insert_evm_transfer_one +} + +export const deleteOldTransfers = async () => { + const mutation = gql` + mutation ($date: timestamptz) { + delete_evm_transfer(where: { timestamp: { _lt: $date } }) { + affected_rows + } + } + ` + + await coreUtil.hasura.default.request(mutation, { + date: moment() + .subtract(networkConfig.keepHistoryForYears, 'years') + .format('YYYY-MM-DD') + }) +} diff --git a/hapi-evm/src/routes/index.ts b/hapi-evm/src/routes/index.ts new file mode 100644 index 00000000..ee065564 --- /dev/null +++ b/hapi-evm/src/routes/index.ts @@ -0,0 +1,13 @@ +import { Server } from '@hapi/hapi' + +import * as serverRoute from './server.route' +import * as transactionsRoute from './transactions.route' +import * as tokenHistoryRoute from './token-history.route' + +const routes = (server: Server) => { + serverRoute.routes(server) + transactionsRoute.routes(server) + tokenHistoryRoute.routes(server) +} + +export default routes diff --git a/hapi-evm/src/routes/server.route.ts b/hapi-evm/src/routes/server.route.ts new file mode 100644 index 00000000..bd1f2cbe --- /dev/null +++ b/hapi-evm/src/routes/server.route.ts @@ -0,0 +1,11 @@ +import { Server } from '@hapi/hapi' + +export const routes = (server: Server) => { + server.route({ + method: 'GET', + path: '/healthz', + handler: () => { + return 'OK' + } + }) +} diff --git a/hapi-evm/src/routes/token-history.route.ts b/hapi-evm/src/routes/token-history.route.ts new file mode 100644 index 00000000..ad3c0a60 --- /dev/null +++ b/hapi-evm/src/routes/token-history.route.ts @@ -0,0 +1,26 @@ +import { Server } from '@hapi/hapi' +import Joi from 'joi' + +import { historyPayloadModel } from '../models' +import { getTokenHistory } from '../services/token-history.service' + +export const routes = (server: Server) => { + server.route({ + method: 'POST', + path: '/evm-token-history', + handler: ({ + payload: { input } + }: historyPayloadModel.interfaces.HistoryQuery) => + getTokenHistory(input?.range), + options: { + validate: { + payload: Joi.object({ + input: Joi.object({ + range: Joi.string().required() + }).required() + }).options({ stripUnknown: true }) + }, + auth: false + } + }) +} diff --git a/hapi-evm/src/routes/transactions.route.ts b/hapi-evm/src/routes/transactions.route.ts new file mode 100644 index 00000000..ebf0a6ad --- /dev/null +++ b/hapi-evm/src/routes/transactions.route.ts @@ -0,0 +1,26 @@ +import { Server } from '@hapi/hapi' +import Joi from 'joi' + +import { historyPayloadModel } from '../models' +import { getTransactions } from '../services/transactions.service' + +export const routes = (server: Server) => { + server.route({ + method: 'POST', + path: '/evm-transactions-history', + handler: ({ + payload: { input } + }: historyPayloadModel.interfaces.HistoryQuery) => + getTransactions(input?.range), + options: { + validate: { + payload: Joi.object({ + input: Joi.object({ + range: Joi.string().required() + }).required() + }).options({ stripUnknown: true }) + }, + auth: false + } + }) +} diff --git a/hapi-evm/src/routes/v1/index.ts b/hapi-evm/src/routes/v1/index.ts new file mode 100644 index 00000000..ad108971 --- /dev/null +++ b/hapi-evm/src/routes/v1/index.ts @@ -0,0 +1,9 @@ +import { Server } from '@hapi/hapi' + +// import * as exampleRoutes from './example.route' + +const baseRoute = '/v1' + +export default (server: Server) => { + // exampleRoutes.routes(server, baseRoute) +} diff --git a/hapi-evm/src/services/block.service.ts b/hapi-evm/src/services/block.service.ts new file mode 100644 index 00000000..55feedcb --- /dev/null +++ b/hapi-evm/src/services/block.service.ts @@ -0,0 +1,215 @@ +import { Web3 } from 'web3' +import { Block, TransactionInfo, TransactionHash } from 'web3-types' + +import { + defaultModel, + blockModel, + transactionModel, + paramModel, + historicalStatsModel, + StatsModel +} from '../models' +import { networkConfig } from '../config' +import moment from 'moment' + +const httpProvider = new Web3.providers.HttpProvider(networkConfig.evmEndpoint) +const web3 = new Web3(httpProvider) + +// const test = async () => { +// const tempBlock: Block = await web3.eth.getBlock(0) +// console.log('馃殌 ~ tempBlock:', tempBlock) + +// const trx: TransactionInfo = await web3.eth.getTransaction( +// '0x4b00d79018d46210b31829285541ae72653e03229a9cff67f362416e5a1c274c' +// ) +// console.log('馃殌 ~ trx:', trx) +// console.log('馃殌 ~ gas:', Number(trx.gas)) +// } + +// test() + +// TODO: syncronize passed blocks +const syncFullBlock = async (blockNumber: number | bigint) => { + const block: Block = await web3.eth.getBlock(blockNumber) + + if (!block.hash) { + throw new Error('Wrong block format') + } + + const blockExist = await blockModel.queries.exist(block.hash.toString()) + + if (blockExist) return + + const transactionsCount = block.transactions?.length + + if (transactionsCount) { + await historicalStatsModel.queries.saveOrIncrement({ + total_transactions: transactionsCount + }) + } + + const blockTimestamp = new Date(Number(block.timestamp) * 1000) + const isBefore = moment(blockTimestamp).isBefore( + moment().subtract(networkConfig.keepHistoryForYears, 'years') + ) + + if (isBefore) return + + const cappedBlock = { + hash: block.hash.toString(), + gas_used: Number(block.gasUsed), + transactions: (block.transactions || []) as TransactionHash[], + number: Number(block.number), + timestamp: blockTimestamp + } + + await blockModel.queries.add_or_modify(cappedBlock) + + // TODO: review this logic + + const transactionsPromises = [ + cappedBlock.transactions.reduce( + async ( + acc: Promise, + trxHash: TransactionHash + ): Promise => { + const transactionExist = await transactionModel.queries.exist(trxHash) + + if (transactionExist) { + return acc + } + + const trx: TransactionInfo = await web3.eth.getTransaction( + trxHash.toString() + ) + + const customTrx: transactionModel.interfaces.CappedTransaction = { + block_hash: trx.blockHash!.toString(), + block_number: Number(trx.blockNumber), + gas: Number(trx.gas), + gas_price: Number(trx.gasPrice), + hash: trx.hash.toString() + } + + await transactionModel.queries.add_or_modify(customTrx) + + return [...(await acc), customTrx] + }, + Promise.resolve([]) + ) + ] + + await Promise.all(transactionsPromises) +} + +const getBlock = async () => { + let blockNumber: bigint + const lastBlockInDB = (await blockModel.queries.default.get( + { timestamp: { _gt: moment().subtract(30, 'minutes') } }, + { number: 'desc' } + )) as blockModel.interfaces.CappedBlock + + if (!lastBlockInDB) { + blockNumber = await web3.eth.getBlockNumber() + } else { + blockNumber = BigInt(lastBlockInDB.number + 1) + } + + await syncFullBlock(blockNumber) +} + +const syncOldBlocks = async (): Promise => { + const paramStats = await paramModel.queries.getState() + + if (paramStats.isSynced) return + + const nextBlock = paramStats.nextBlock + const isUpToDate = await blockModel.queries.default.get({ + number: { _eq: nextBlock } + }) + + if (!isUpToDate) { + const nextBlockTo = await blockModel.queries.default.getNextBlock(nextBlock) + const nextBlockToNumber = nextBlockTo[0]?.number || 0 + + if (nextBlockToNumber > nextBlock) { + console.log( + `馃殾 Syncing blocks behind, pending ${nextBlockToNumber - nextBlock} ` + ) + } + + await syncFullBlock(nextBlock) + } + + await paramModel.queries.saveOrUpdate( + nextBlock + 1 * Number(!isUpToDate), + !!isUpToDate + ) +} + +const blockWorker = async () => { + getBlock() +} + +const cleanOldBlocks = async () => { + await blockModel.queries.deleteOldBlocks() +} + +const syncATH = async () => { + const currentState = await historicalStatsModel.queries.getState() + const partialATH = await StatsModel.queries.getPartialATH() + + if (!partialATH) return + + if ( + currentState.tps_all_time_high.transactions_count || + 0 < partialATH.ath_transactions_count + ) { + await historicalStatsModel.queries.saveOrUpdate({ + tps_all_time_high: { + blocks: partialATH.ath_blocks.split(','), + transactions_count: partialATH.ath_transactions_count, + gas_used: partialATH.ath_gas_used + } + }) + } +} + +const syncBlockWorker = (): defaultModel.Worker => { + return { + name: 'SYNC BLOCK WORKER', + intervalSec: networkConfig.blockIntervalSec, + action: blockWorker + } +} + +const syncOldBlockWorker = (): defaultModel.Worker => { + return { + name: 'SYNC OLD BLOCK WORKER', + intervalSec: networkConfig.oldBlockIntervalSec, + action: syncOldBlocks + } +} + +const syncATHWorker = (): defaultModel.Worker => { + return { + name: 'SYNC ATH WORKER', + intervalSec: networkConfig.ATHIntervalSec, + action: syncATH + } +} + +const cleanOldBlocksWorker = (): defaultModel.Worker => { + return { + name: 'CLEAN UP OLD BLOCKS WORKER', + intervalSec: networkConfig.cleanOldBlockIntervalSec, + action: cleanOldBlocks + } +} + +export default { + syncBlockWorker, + syncOldBlockWorker, + cleanOldBlocksWorker, + syncATHWorker +} diff --git a/hapi-evm/src/services/hyperion/index.ts b/hapi-evm/src/services/hyperion/index.ts new file mode 100644 index 00000000..59c18092 --- /dev/null +++ b/hapi-evm/src/services/hyperion/index.ts @@ -0,0 +1,170 @@ +import moment, { DurationInputArg2 } from 'moment' + +import { hyperionConfig } from '../../config' +import { coreUtil, timeUtil } from '../../utils' +import { hyperionStateModel } from '../../models' + +import updaters from './updaters' + +interface GetActionsParams { + after: string + before: string + skip: number +} + +interface GetActionsResponse { + hasMore: boolean + actions: any[] +} + +const TIME_BEFORE_IRREVERSIBILITY = 164 + +const getLastSyncedAt = async () => { + const state = await hyperionStateModel.queries.getState() + + if (state) { + return state.lastSyncedAt + } + + await hyperionStateModel.queries.saveOrUpdate(hyperionConfig.startAt) + + return hyperionConfig.startAt +} + +const getGap = (lastSyncedAt: string) => { + if (moment().diff(moment(lastSyncedAt), 'days') > 0) { + return { + amount: 1, + unit: 'day' + } + } + + if (moment().diff(moment(lastSyncedAt), 'hours') > 0) { + return { + amount: 1, + unit: 'hour' + } + } + + if ( + moment().diff(moment(lastSyncedAt), 'seconds') >= + TIME_BEFORE_IRREVERSIBILITY * 2 + ) { + return { + amount: TIME_BEFORE_IRREVERSIBILITY, + unit: 'seconds' + } + } + + if ( + moment().diff(moment(lastSyncedAt), 'seconds') >= + TIME_BEFORE_IRREVERSIBILITY + 10 + ) { + return { + amount: 10, + unit: 'seconds' + } + } + + return { + amount: 1, + unit: 'seconds' + } +} + +const getActions = async ( + params: GetActionsParams +): Promise => { + const limit = 100 + const { data } = await coreUtil.axios.default.get( + `${hyperionConfig.api}/v2/history/get_actions`, + { + params: { + ...params, + account: 'eosio.evm', // TODO: get it from updater using the notified_account field + limit, + filter: updaters.map(updater => updater.type).join(','), + sort: 'asc', + simple: true, + checkLib: true + } + } + ) + + const notIrreversible = data.simple_actions.find( + (item: any) => !item.irreversible + ) + + if (notIrreversible) { + await timeUtil.sleep(1) + + return getActions(params) + } + + return { + hasMore: data.total.value > limit + params.skip || false, + actions: data.simple_actions + } +} + +const runUpdaters = async (actions: any[]) => { + for (let index = 0; index < actions.length; index++) { + const action = actions[index] + const updater = updaters.find(item => + item.type.startsWith(`${action.contract}:${action.action}`) + ) + + if (!updater) { + continue + } + + await updater.apply(action) + } +} + +const sync = async (): Promise => { + console.log('SYNCING') + await coreUtil.hasura.hasuraAssembled() + const lastSyncedAt = await getLastSyncedAt() + const gap = getGap(lastSyncedAt) + const after = moment(lastSyncedAt).toISOString() + const before = moment(after) + .add(gap.amount, gap.unit as DurationInputArg2) + .toISOString() + const diff = moment().diff(moment(before), 'seconds') + let skip = 0 + let hasMore = true + let actions = [] + + if (diff < TIME_BEFORE_IRREVERSIBILITY) { + await timeUtil.sleep(TIME_BEFORE_IRREVERSIBILITY - diff) + + return sync() + } + + try { + while (hasMore) { + ;({ hasMore, actions } = await getActions({ after, before, skip })) + skip += actions.length + await runUpdaters(actions) + } + } catch (error: any) { + console.error('hyperion error', error.message) + await timeUtil.sleep(5) + + return sync() + } + + await hyperionStateModel.queries.saveOrUpdate(before) + + return sync() +} + +const syncWorker = () => { + return { + name: 'SYNC ACTIONS', + action: sync + } +} + +export default { syncWorker } diff --git a/hapi-evm/src/services/hyperion/updaters/eosio-evm-transfer.updater.ts b/hapi-evm/src/services/hyperion/updaters/eosio-evm-transfer.updater.ts new file mode 100644 index 00000000..2cfe96f2 --- /dev/null +++ b/hapi-evm/src/services/hyperion/updaters/eosio-evm-transfer.updater.ts @@ -0,0 +1,32 @@ +import { transferModel } from '../../../models' + +// TODO: handle this as a network function, for example, base on the +// network config, the action type and logic will be different + +// TODO: move this to env +const defaultMemo = 'Withdraw balance for' + +export default { + type: `eosio.evm:withdraw`, + notified_account: `eosio.evm`, + apply: async (action: any) => { + const [amount, symbol] = action.data.quantity.split(' ') + + try { + await transferModel.queries.save({ + block: action.block, + transaction_id: action.transaction_id, + timestamp: action.timestamp, + from: 'eosio.evm', + to: action.data.to, + amount: amount, + symbol: symbol, + memo: `${defaultMemo}: ${action.data.to}`, + quantity: action.data.quantity, + type: transferModel.interfaces.Type.outgoing + }) + } catch (error: any) { + console.error(`error to sync ${action.action}: ${error.message}`) + } + } +} diff --git a/hapi-evm/src/services/hyperion/updaters/index.ts b/hapi-evm/src/services/hyperion/updaters/index.ts new file mode 100644 index 00000000..0565f3f8 --- /dev/null +++ b/hapi-evm/src/services/hyperion/updaters/index.ts @@ -0,0 +1,4 @@ +import tokenTransferUpdater from './token-transfer.updater' +import eosioEvmWithdrawUpdater from './eosio-evm-transfer.updater' + +export default [tokenTransferUpdater, eosioEvmWithdrawUpdater] diff --git a/hapi-evm/src/services/hyperion/updaters/token-transfer.updater.ts b/hapi-evm/src/services/hyperion/updaters/token-transfer.updater.ts new file mode 100644 index 00000000..f546f401 --- /dev/null +++ b/hapi-evm/src/services/hyperion/updaters/token-transfer.updater.ts @@ -0,0 +1,33 @@ +import { isAddress } from 'web3-validator' + +import { transferModel } from '../../../models' + +// TODO: handle this as a network function, for example, base on the +// network config, the action type and logic will be different + +export default { + type: `eosio.token:transfer,act.data.to=eosio.evm`, + notified_account: `eosio.evm`, + apply: async (action: any) => { + if (!isAddress(action.data.memo)) { + return + } + + try { + await transferModel.queries.save({ + block: action.block, + transaction_id: action.transaction_id, + timestamp: action.timestamp, + from: action.data.from, + to: action.data.to, + amount: action.data.amount, + symbol: action.data.symbol, + memo: action.data.memo, + quantity: action.data.quantity, + type: transferModel.interfaces.Type.incoming + }) + } catch (error: any) { + console.error(`error to sync ${action.action}: ${error.message}`) + } + } +} diff --git a/hapi-evm/src/services/index.ts b/hapi-evm/src/services/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/hapi-evm/src/services/token-history.service.ts b/hapi-evm/src/services/token-history.service.ts new file mode 100644 index 00000000..b22ea549 --- /dev/null +++ b/hapi-evm/src/services/token-history.service.ts @@ -0,0 +1,32 @@ +import { sequelizeUtil } from '../utils' + +import { getGranularityFromRange } from '../utils/get-granularity-from-range' + +export const getTokenHistory = async (range: string) => { + const granularity = getGranularityFromRange(range) + const [rows] = await sequelizeUtil.sequelize.query(` + WITH interval AS ( + SELECT generate_series( + date_trunc('${granularity}', now()) - '${range}'::interval, + date_trunc('${granularity}', now()), + '1 ${granularity}'::interval + ) AS value + ) + + SELECT + interval.value as datetime, + COUNT(CASE WHEN transfer.type = 'incoming' THEN 1 END) as incoming, + COUNT(CASE WHEN transfer.type = 'outgoing' THEN 1 END) as outgoing + FROM + interval + LEFT JOIN + ( SELECT amount, timestamp, type FROM evm.transfer WHERE amount > 0 ) + AS transfer ON date_trunc('${granularity}', transfer.timestamp) = interval.value + GROUP BY + 1 + ORDER BY + 1 ASC + `) + + return rows +} diff --git a/hapi-evm/src/services/transactions.service.ts b/hapi-evm/src/services/transactions.service.ts new file mode 100644 index 00000000..110cb7a5 --- /dev/null +++ b/hapi-evm/src/services/transactions.service.ts @@ -0,0 +1,44 @@ +import Web3 from 'web3' + +import { sequelizeUtil } from '../utils' +import { networkConfig } from '../config' +import { getGranularityFromRange } from '../utils/get-granularity-from-range' + +export const getTransactions = async (range: string) => { + const granularity = getGranularityFromRange(range) + const httpProvider = new Web3.providers.HttpProvider( + networkConfig.evmEndpoint + ) + const web3 = new Web3(httpProvider) + const lastBlock = await web3.eth.getBlock('latest') + const gasLimit = Number(lastBlock?.gasLimit) || 1000000000 + + const [rows] = await sequelizeUtil.sequelize.query(` + WITH interval AS ( + SELECT generate_series( + date_trunc('${granularity}', now()) - '${range}'::interval, + date_trunc('${granularity}', now()), + '1 ${granularity}'::interval + ) AS value + ) + + SELECT + interval.value AS datetime, + sum(transactions_count) AS transactions_count, + avg(block.gas_used)::numeric(6,3) AS avg_gas_used + FROM + interval + LEFT JOIN + ( SELECT transactions_count, timestamp, gas_used / ${gasLimit} * 100 AS gas_used + FROM ( SELECT block_hash, count(1) AS transactions_count + FROM evm.transaction GROUP BY block_hash) + AS subquery INNER JOIN evm.block ON evm.block.hash = block_hash) + AS block ON date_trunc('${granularity}', block.timestamp) = interval.value + GROUP BY + 1 + ORDER BY + 1 ASC + `) + + return rows +} diff --git a/hapi-evm/src/services/transfer.service.ts b/hapi-evm/src/services/transfer.service.ts new file mode 100644 index 00000000..a8013094 --- /dev/null +++ b/hapi-evm/src/services/transfer.service.ts @@ -0,0 +1,16 @@ +import { defaultModel, transferModel } from '../models' +import { networkConfig } from '../config' + +const cleanOldTransfersWorker = (): defaultModel.Worker => { + return { + name: 'CLEAN UP OLD TRANSFER WORKER', + intervalSec: networkConfig.cleanOldTransferIntervalSec, + action: async () => { + await transferModel.queries.deleteOldTransfers() + } + } +} + +export default { + cleanOldTransfersWorker +} diff --git a/hapi-evm/src/services/worker/index.ts b/hapi-evm/src/services/worker/index.ts new file mode 100644 index 00000000..8da10122 --- /dev/null +++ b/hapi-evm/src/services/worker/index.ts @@ -0,0 +1,35 @@ +import { timeUtil, coreUtil } from '../../utils' +import { defaultModel } from '../../models' +import blockService from '../block.service' +import transferService from '../transfer.service' +import hyperionService from '../hyperion' + +const run = async (worker: defaultModel.Worker) => { + try { + await worker.action() + } catch (error: any) { + console.log(`${worker.name} ERROR =>`, error.message) + } + + if (!worker.intervalSec) { + return + } + + await timeUtil.sleep(worker.intervalSec) + run(worker) +} + +const init = async () => { + await coreUtil.hasura.hasuraAssembled() + + run(blockService.syncBlockWorker()) + run(blockService.syncOldBlockWorker()) + run(blockService.syncATHWorker()) + run(blockService.cleanOldBlocksWorker()) + run(transferService.cleanOldTransfersWorker()) + run(hyperionService.syncWorker()) +} + +export default { + init +} diff --git a/hapi-evm/src/utils/core/axios.core.ts b/hapi-evm/src/utils/core/axios.core.ts new file mode 100644 index 00000000..ee20909a --- /dev/null +++ b/hapi-evm/src/utils/core/axios.core.ts @@ -0,0 +1,11 @@ +import axios from 'axios' +import https from 'https' + +const instance = axios.create({ + timeout: 15000, + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) +}) + +export default instance diff --git a/hapi-evm/src/utils/core/hasura.core.ts b/hapi-evm/src/utils/core/hasura.core.ts new file mode 100644 index 00000000..50cb55e3 --- /dev/null +++ b/hapi-evm/src/utils/core/hasura.core.ts @@ -0,0 +1,33 @@ +import { GraphQLClient } from 'graphql-request' + +import { hasuraConfig } from '../../config' + +import { sleep } from '../time.util' + +import axiosUtil from './axios.core' + +export const hasuraAssembled = async () => { + let hasuraReady = false + + while (!hasuraReady) { + try { + await axiosUtil.get(hasuraConfig.url.replace('/v1/graphql', '/healthz')) + hasuraReady = true + } catch (error) { + hasuraReady = false + console.log( + 'waiting for hasura...', + hasuraConfig.url.replace('/v1/graphql', '/healthz') + ) + await sleep(5) + } + } +} + +const instance = new GraphQLClient(hasuraConfig.url, { + headers: { + 'x-hasura-admin-secret': hasuraConfig.adminSecret + } +}) + +export default instance diff --git a/hapi-evm/src/utils/core/index.ts b/hapi-evm/src/utils/core/index.ts new file mode 100644 index 00000000..2e940f83 --- /dev/null +++ b/hapi-evm/src/utils/core/index.ts @@ -0,0 +1,2 @@ +export * as axios from './axios.core' +export * as hasura from './hasura.core' diff --git a/hapi-evm/src/utils/get-granularity-from-range.ts b/hapi-evm/src/utils/get-granularity-from-range.ts new file mode 100644 index 00000000..12529da0 --- /dev/null +++ b/hapi-evm/src/utils/get-granularity-from-range.ts @@ -0,0 +1,33 @@ +export const getGranularityFromRange = (range: string) => { + let granularity + + switch (range) { + case '3 Hours': + case '6 Hours': + case '12 Hours': + granularity = 'minute' + break + case '1 Day': + case '2 Days': + case '4 Days': + case '7 Days': + case '14 Days': + granularity = 'hour' + break + case '1 Month': + case '2 Months': + case '3 Months': + case '6 Months': + granularity = 'day' + break + case '1 Year': + case 'all': + granularity = 'month' + break + default: + granularity = 'minute' + break + } + + return granularity +} diff --git a/hapi-evm/src/utils/index.ts b/hapi-evm/src/utils/index.ts new file mode 100644 index 00000000..c72b461d --- /dev/null +++ b/hapi-evm/src/utils/index.ts @@ -0,0 +1,3 @@ +export * as coreUtil from './core' +export * as timeUtil from './time.util' +export * as sequelizeUtil from './sequelize.util' diff --git a/hapi-evm/src/utils/sequelize.util.ts b/hapi-evm/src/utils/sequelize.util.ts new file mode 100644 index 00000000..e641a5ea --- /dev/null +++ b/hapi-evm/src/utils/sequelize.util.ts @@ -0,0 +1,10 @@ +import { Sequelize } from 'sequelize' + +import { hasuraConfig } from '../config' + +export const sequelize = new Sequelize(hasuraConfig.databaseURL, { + dialectOptions: { + connectTimeout: 60000000 + }, + logging: false +}) diff --git a/hapi-evm/src/utils/time.util.ts b/hapi-evm/src/utils/time.util.ts new file mode 100644 index 00000000..7b5eebb4 --- /dev/null +++ b/hapi-evm/src/utils/time.util.ts @@ -0,0 +1,3 @@ +export const sleep = (seconds: number) => { + return new Promise(resolve => setTimeout(resolve, seconds * 1000)) +} diff --git a/hapi-evm/tsconfig.json b/hapi-evm/tsconfig.json new file mode 100644 index 00000000..0218363e --- /dev/null +++ b/hapi-evm/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + + /* Language and Environment */ + "target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + "rootDir": "./src" /* Specify the root folder within your source files. */, + "outDir": "./dist" /* Specify an output folder for all emitted files. */, + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + "strict": true, + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/hapi-evm/yarn.lock b/hapi-evm/yarn.lock new file mode 100644 index 00000000..b12f9a55 --- /dev/null +++ b/hapi-evm/yarn.lock @@ -0,0 +1,3226 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@adraffy/ens-normalize@^1.8.8": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz#60111a5d9db45b2e5cbb6231b0bb8d97e8659316" + integrity sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.3.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.5.0": + version "4.5.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" + integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== + +"@eslint/eslintrc@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.0.tgz#82256f164cc9e0b59669efc19d57f8092706841d" + integrity sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.44.0": + version "8.44.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.44.0.tgz#961a5903c74139390478bdc808bcde3fc45ab7af" + integrity sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw== + +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + +"@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@graphql-typed-document-node/core@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + +"@hapi/accept@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/accept/-/accept-6.0.1.tgz#36378307a67fe38a626fbfaf7f130cdb654d0385" + integrity sha512-aLkYj7zzgC3CSlEVOs84eBOEE3i9xZK2tdQEP+TOj2OFzMWCi9zjkRet82V3GGjecE//zFrCLKIykuaE0uM4bg== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/ammo@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/ammo/-/ammo-6.0.1.tgz#1bc9f7102724ff288ca03b721854fc5393ad123a" + integrity sha512-pmL+nPod4g58kXrMcsGLp05O2jF4P2Q3GiL8qYV7nKYEh3cGf+rV4P5Jyi2Uq0agGhVU63GtaSAfBEZOlrJn9w== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/b64@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/b64/-/b64-6.0.1.tgz#786b47dc070e14465af49e2428c1025bd06ed3df" + integrity sha512-ZvjX4JQReUmBheeCq+S9YavcnMMHWqx3S0jHNXWIM1kQDxB9cyfSycpVvjfrKcIS8Mh5N3hmu/YKo4Iag9g2Kw== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/boom@^10.0.0", "@hapi/boom@^10.0.1": + version "10.0.1" + resolved "https://registry.yarnpkg.com/@hapi/boom/-/boom-10.0.1.tgz#ebb14688275ae150aa6af788dbe482e6a6062685" + integrity sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/bounce@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@hapi/bounce/-/bounce-3.0.1.tgz#25a51bf95733749c557c6bf948048bffa66435e4" + integrity sha512-G+/Pp9c1Ha4FDP+3Sy/Xwg2O4Ahaw3lIZFSX+BL4uWi64CmiETuZPxhKDUD4xBMOUZbBlzvO8HjiK8ePnhBadA== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/bourne@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-3.0.0.tgz#f11fdf7dda62fe8e336fa7c6642d9041f30356d7" + integrity sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w== + +"@hapi/call@^9.0.1": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@hapi/call/-/call-9.0.1.tgz#569b87d5b67abf0e58fb82a3894a61aaed3ca92e" + integrity sha512-uPojQRqEL1GRZR4xXPqcLMujQGaEpyVPRyBlD8Pp5rqgIwLhtveF9PkixiKru2THXvuN8mUrLeet5fqxKAAMGg== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/catbox-memory@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/catbox-memory/-/catbox-memory-6.0.1.tgz#8f6b04c0cf2ce25da470324df360bd4e8d68b6ec" + integrity sha512-sVb+/ZxbZIvaMtJfAbdyY+QJUQg9oKTwamXpEg/5xnfG5WbJLTjvEn4kIGKz9pN3ENNbIL/bIdctmHmqi/AdGA== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/catbox@^12.1.1": + version "12.1.1" + resolved "https://registry.yarnpkg.com/@hapi/catbox/-/catbox-12.1.1.tgz#9339dca0a5b18b3ca0a825ac5dfc916dbc5bab83" + integrity sha512-hDqYB1J+R0HtZg4iPH3LEnldoaBsar6bYp0EonBmNQ9t5CO+1CqgCul2ZtFveW1ReA5SQuze9GPSU7/aecERhw== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + "@hapi/podium" "^5.0.0" + "@hapi/validate" "^2.0.1" + +"@hapi/content@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@hapi/content/-/content-6.0.0.tgz#2427af3bac8a2f743512fce2a70cbdc365af29df" + integrity sha512-CEhs7j+H0iQffKfe5Htdak5LBOz/Qc8TRh51cF+BFv0qnuph3Em4pjGVzJMkI2gfTDdlJKWJISGWS1rK34POGA== + dependencies: + "@hapi/boom" "^10.0.0" + +"@hapi/cryptiles@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/cryptiles/-/cryptiles-6.0.1.tgz#7868a9d4233567ed66f0a9caf85fdcc56e980621" + integrity sha512-9GM9ECEHfR8lk5ASOKG4+4ZsEzFqLfhiryIJ2ISePVB92OHLp/yne4m+zn7z9dgvM98TLpiFebjDFQ0UHcqxXQ== + dependencies: + "@hapi/boom" "^10.0.1" + +"@hapi/file@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@hapi/file/-/file-3.0.0.tgz#f1fd824493ac89a6fceaf89c824afc5ae2121c09" + integrity sha512-w+lKW+yRrLhJu620jT3y+5g2mHqnKfepreykvdOcl9/6up8GrQQn+l3FRTsjHTKbkbfQFkuksHpdv2EcpKcJ4Q== + +"@hapi/hapi@^21.3.2": + version "21.3.2" + resolved "https://registry.yarnpkg.com/@hapi/hapi/-/hapi-21.3.2.tgz#f9f94c1c28ccad1444c838d04070fa1cd0409b33" + integrity sha512-tbm0zmsdUj8iw4NzFV30FST/W4qzh/Lsw6Q5o5gAhOuoirWvxm8a4G3o60bqBw8nXvRNJ8uLtE0RKLlZINxHcQ== + dependencies: + "@hapi/accept" "^6.0.1" + "@hapi/ammo" "^6.0.1" + "@hapi/boom" "^10.0.1" + "@hapi/bounce" "^3.0.1" + "@hapi/call" "^9.0.1" + "@hapi/catbox" "^12.1.1" + "@hapi/catbox-memory" "^6.0.1" + "@hapi/heavy" "^8.0.1" + "@hapi/hoek" "^11.0.2" + "@hapi/mimos" "^7.0.1" + "@hapi/podium" "^5.0.1" + "@hapi/shot" "^6.0.1" + "@hapi/somever" "^4.1.1" + "@hapi/statehood" "^8.1.1" + "@hapi/subtext" "^8.1.0" + "@hapi/teamwork" "^6.0.0" + "@hapi/topo" "^6.0.1" + "@hapi/validate" "^2.0.1" + +"@hapi/heavy@^8.0.1": + version "8.0.1" + resolved "https://registry.yarnpkg.com/@hapi/heavy/-/heavy-8.0.1.tgz#e2be4a6a249005b5a587f7604aafa8ed02461fb6" + integrity sha512-gBD/NANosNCOp6RsYTsjo2vhr5eYA3BEuogk6cxY0QdhllkkTaJFYtTXv46xd6qhBVMbMMqcSdtqey+UQU3//w== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/hoek" "^11.0.2" + "@hapi/validate" "^2.0.1" + +"@hapi/hoek@^11.0.2": + version "11.0.2" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-11.0.2.tgz#cb3ea547daac7de5c9cf1d960c3f35c34f065427" + integrity sha512-aKmlCO57XFZ26wso4rJsW4oTUnrgTFw2jh3io7CAtO9w4UltBNwRXvXIVzzyfkaaLRo3nluP/19msA8vDUUuKw== + +"@hapi/hoek@^9.0.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" + integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== + +"@hapi/iron@^7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@hapi/iron/-/iron-7.0.1.tgz#f74bace8dad9340c7c012c27c078504f070f14b5" + integrity sha512-tEZnrOujKpS6jLKliyWBl3A9PaE+ppuL/+gkbyPPDb/l2KSKQyH4lhMkVb+sBhwN+qaxxlig01JRqB8dk/mPxQ== + dependencies: + "@hapi/b64" "^6.0.1" + "@hapi/boom" "^10.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/cryptiles" "^6.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/mimos@^7.0.1": + version "7.0.1" + resolved "https://registry.yarnpkg.com/@hapi/mimos/-/mimos-7.0.1.tgz#5b65c76bb9da28ba34b0092215891f2c72bc899d" + integrity sha512-b79V+BrG0gJ9zcRx1VGcCI6r6GEzzZUgiGEJVoq5gwzuB2Ig9Cax8dUuBauQCFKvl2YWSWyOc8mZ8HDaJOtkew== + dependencies: + "@hapi/hoek" "^11.0.2" + mime-db "^1.52.0" + +"@hapi/nigel@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@hapi/nigel/-/nigel-5.0.1.tgz#a6dfe357e9d48d944e2ffc552bd95cb701d79ee9" + integrity sha512-uv3dtYuB4IsNaha+tigWmN8mQw/O9Qzl5U26Gm4ZcJVtDdB1AVJOwX3X5wOX+A07qzpEZnOMBAm8jjSqGsU6Nw== + dependencies: + "@hapi/hoek" "^11.0.2" + "@hapi/vise" "^5.0.1" + +"@hapi/pez@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@hapi/pez/-/pez-6.1.0.tgz#64d9f95580fc7d8f1d13437ee4a8676709954fda" + integrity sha512-+FE3sFPYuXCpuVeHQ/Qag1b45clR2o54QoonE/gKHv9gukxQ8oJJZPR7o3/ydDTK6racnCJXxOyT1T93FCJMIg== + dependencies: + "@hapi/b64" "^6.0.1" + "@hapi/boom" "^10.0.1" + "@hapi/content" "^6.0.0" + "@hapi/hoek" "^11.0.2" + "@hapi/nigel" "^5.0.1" + +"@hapi/podium@^5.0.0", "@hapi/podium@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@hapi/podium/-/podium-5.0.1.tgz#f292b4c0ca3118747394a102c6c3340bda96662f" + integrity sha512-eznFTw6rdBhAijXFIlBOMJJd+lXTvqbrBIS4Iu80r2KTVIo4g+7fLy4NKp/8+UnSt5Ox6mJtAlKBU/Sf5080TQ== + dependencies: + "@hapi/hoek" "^11.0.2" + "@hapi/teamwork" "^6.0.0" + "@hapi/validate" "^2.0.1" + +"@hapi/shot@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@hapi/shot/-/shot-6.0.1.tgz#ea84d1810b7c8599d5517c23b4ec55a529d7dc16" + integrity sha512-s5ynMKZXYoDd3dqPw5YTvOR/vjHvMTxc388+0qL0jZZP1+uwXuUD32o9DuuuLsmTlyXCWi02BJl1pBpwRuUrNA== + dependencies: + "@hapi/hoek" "^11.0.2" + "@hapi/validate" "^2.0.1" + +"@hapi/somever@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@hapi/somever/-/somever-4.1.1.tgz#b492c78408303c72cd1a39c5060f35d18a404b27" + integrity sha512-lt3QQiDDOVRatS0ionFDNrDIv4eXz58IibQaZQDOg4DqqdNme8oa0iPWcE0+hkq/KTeBCPtEOjDOBKBKwDumVg== + dependencies: + "@hapi/bounce" "^3.0.1" + "@hapi/hoek" "^11.0.2" + +"@hapi/statehood@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@hapi/statehood/-/statehood-8.1.1.tgz#db4bd14c90810a1389763cb0b0b8f221aa4179c1" + integrity sha512-YbK7PSVUA59NArAW5Np0tKRoIZ5VNYUicOk7uJmWZF6XyH5gGL+k62w77SIJb0AoAJ0QdGQMCQ/WOGL1S3Ydow== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/bounce" "^3.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/cryptiles" "^6.0.1" + "@hapi/hoek" "^11.0.2" + "@hapi/iron" "^7.0.1" + "@hapi/validate" "^2.0.1" + +"@hapi/subtext@^8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@hapi/subtext/-/subtext-8.1.0.tgz#58733020a6655bc4d978df9e2f75e31696ff3f91" + integrity sha512-PyaN4oSMtqPjjVxLny1k0iYg4+fwGusIhaom9B2StinBclHs7v46mIW706Y+Wo21lcgulGyXbQrmT/w4dus6ww== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/content" "^6.0.0" + "@hapi/file" "^3.0.0" + "@hapi/hoek" "^11.0.2" + "@hapi/pez" "^6.1.0" + "@hapi/wreck" "^18.0.1" + +"@hapi/teamwork@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@hapi/teamwork/-/teamwork-6.0.0.tgz#b3a173cf811ba59fc6ee22318a1b51f4561f06e0" + integrity sha512-05HumSy3LWfXpmJ9cr6HzwhAavrHkJ1ZRCmNE2qJMihdM5YcWreWPfyN0yKT2ZjCM92au3ZkuodjBxOibxM67A== + +"@hapi/topo@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@hapi/topo@^6.0.1": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-6.0.2.tgz#f219c1c60da8430228af4c1f2e40c32a0d84bbb4" + integrity sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/validate@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@hapi/validate/-/validate-2.0.1.tgz#45cf228c4c8cfc61ba2da7e0a5ba93ff3b9afff1" + integrity sha512-NZmXRnrSLK8MQ9y/CMqE9WSspgB9xA41/LlYR0k967aSZebWr4yNrpxIbov12ICwKy4APSlWXZga9jN5p6puPA== + dependencies: + "@hapi/hoek" "^11.0.2" + "@hapi/topo" "^6.0.1" + +"@hapi/vise@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@hapi/vise/-/vise-5.0.1.tgz#5c9f16bcf1c039ddd4b6cad5f32d71eeb6bb7dac" + integrity sha512-XZYWzzRtINQLedPYlIkSkUr7m5Ddwlu99V9elh8CSygXstfv3UnWIXT0QD+wmR0VAG34d2Vx3olqcEhRRoTu9A== + dependencies: + "@hapi/hoek" "^11.0.2" + +"@hapi/wreck@^18.0.1": + version "18.0.1" + resolved "https://registry.yarnpkg.com/@hapi/wreck/-/wreck-18.0.1.tgz#6df04532be25fd128c5244e72ccc21438cf8bb65" + integrity sha512-OLHER70+rZxvDl75xq3xXOfd3e8XIvz8fWY0dqg92UvhZ29zo24vQgfqgHSYhB5ZiuFpSLeriOisAlxAo/1jWg== + dependencies: + "@hapi/boom" "^10.0.1" + "@hapi/bourne" "^3.0.0" + "@hapi/hoek" "^11.0.2" + +"@humanwhocodes/config-array@^0.11.10": + version "0.11.10" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" + integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@noble/curves@1.1.0", "@noble/curves@~1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" + integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA== + dependencies: + "@noble/hashes" "1.3.1" + +"@noble/hashes@1.3.1", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" + integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgr/utils@^2.3.1": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" + integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw== + dependencies: + cross-spawn "^7.0.3" + fast-glob "^3.3.0" + is-glob "^4.0.3" + open "^9.1.0" + picocolors "^1.0.0" + tslib "^2.6.0" + +"@scure/base@~1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" + integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== + +"@scure/bip32@1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.1.tgz#7248aea723667f98160f593d621c47e208ccbb10" + integrity sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A== + dependencies: + "@noble/curves" "~1.1.0" + "@noble/hashes" "~1.3.1" + "@scure/base" "~1.1.0" + +"@scure/bip39@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a" + integrity sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg== + dependencies: + "@noble/hashes" "~1.3.0" + "@scure/base" "~1.1.0" + +"@sideway/address@^4.1.3": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" + integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" + integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/debug@^4.1.8": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317" + integrity sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ== + dependencies: + "@types/ms" "*" + +"@types/json-schema@^7.0.11": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + +"@types/node@*", "@types/node@^20.1.5": + version "20.4.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.2.tgz#129cc9ae69f93824f92fac653eebfb4812ab4af9" + integrity sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw== + +"@types/semver@^7.3.12": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + +"@types/validator@^13.7.17": + version "13.11.1" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.11.1.tgz#6560af76ed54490e68c42f717ab4e742ba7be74b" + integrity sha512-d/MUkJYdOeKycmm75Arql4M5+UuXmf4cHdHKsyw1GcvnNgL6s77UkgSgJ8TE/rI5PYsnwYq5jkcWBLuN/MpQ1A== + +"@types/web3@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/web3/-/web3-1.2.2.tgz#d95a101547ce625c5ebd0470baa5dbd4b9f3c015" + integrity sha512-eFiYJKggNrOl0nsD+9cMh2MLk4zVBfXfGnVeRFbpiZzBE20eet4KLA3fXcjSuHaBn0RnQzwLAGdgzgzdet4C0A== + dependencies: + web3 "*" + +"@types/ws@^8.5.3": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" + integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== + dependencies: + "@types/node" "*" + +"@typescript-eslint/eslint-plugin@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.0.0.tgz#19ff4f1cab8d6f8c2c1825150f7a840bc5d9bdc4" + integrity sha512-xuv6ghKGoiq856Bww/yVYnXGsKa588kY3M0XK7uUW/3fJNNULKRfZfSBkMTSpqGG/8ZCXCadfh8G/z/B4aqS/A== + dependencies: + "@eslint-community/regexpp" "^4.5.0" + "@typescript-eslint/scope-manager" "6.0.0" + "@typescript-eslint/type-utils" "6.0.0" + "@typescript-eslint/utils" "6.0.0" + "@typescript-eslint/visitor-keys" "6.0.0" + debug "^4.3.4" + grapheme-splitter "^1.0.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + natural-compare-lite "^1.4.0" + semver "^7.5.0" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.0.0.tgz#46b2600fd1f67e62fc00a28093a75f41bf7effc4" + integrity sha512-TNaufYSPrr1U8n+3xN+Yp9g31vQDJqhXzzPSHfQDLcaO4tU+mCfODPxCwf4H530zo7aUBE3QIdxCXamEnG04Tg== + dependencies: + "@typescript-eslint/scope-manager" "6.0.0" + "@typescript-eslint/types" "6.0.0" + "@typescript-eslint/typescript-estree" "6.0.0" + "@typescript-eslint/visitor-keys" "6.0.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.0.0.tgz#8ede47a37cb2b7ed82d329000437abd1113b5e11" + integrity sha512-o4q0KHlgCZTqjuaZ25nw5W57NeykZT9LiMEG4do/ovwvOcPnDO1BI5BQdCsUkjxFyrCL0cSzLjvIMfR9uo7cWg== + dependencies: + "@typescript-eslint/types" "6.0.0" + "@typescript-eslint/visitor-keys" "6.0.0" + +"@typescript-eslint/type-utils@6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.0.0.tgz#0478d8a94f05e51da2877cc0500f1b3c27ac7e18" + integrity sha512-ah6LJvLgkoZ/pyJ9GAdFkzeuMZ8goV6BH7eC9FPmojrnX9yNCIsfjB+zYcnex28YO3RFvBkV6rMV6WpIqkPvoQ== + dependencies: + "@typescript-eslint/typescript-estree" "6.0.0" + "@typescript-eslint/utils" "6.0.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/types@6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.0.0.tgz#19795f515f8decbec749c448b0b5fc76d82445a1" + integrity sha512-Zk9KDggyZM6tj0AJWYYKgF0yQyrcnievdhG0g5FqyU3Y2DRxJn4yWY21sJC0QKBckbsdKKjYDV2yVrrEvuTgxg== + +"@typescript-eslint/typescript-estree@6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.0.0.tgz#1e09aab7320e404fb9f83027ea568ac24e372f81" + integrity sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ== + dependencies: + "@typescript-eslint/types" "6.0.0" + "@typescript-eslint/visitor-keys" "6.0.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.5.0" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.0.0.tgz#27a16d0d8f2719274a39417b9782f7daa3802db0" + integrity sha512-SOr6l4NB6HE4H/ktz0JVVWNXqCJTOo/mHnvIte1ZhBQ0Cvd04x5uKZa3zT6tiodL06zf5xxdK8COiDvPnQ27JQ== + dependencies: + "@eslint-community/eslint-utils" "^4.3.0" + "@types/json-schema" "^7.0.11" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "6.0.0" + "@typescript-eslint/types" "6.0.0" + "@typescript-eslint/typescript-estree" "6.0.0" + eslint-scope "^5.1.1" + semver "^7.5.0" + +"@typescript-eslint/visitor-keys@6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.0.0.tgz#0b49026049fbd096d2c00c5e784866bc69532a31" + integrity sha512-cvJ63l8c0yXdeT5POHpL0Q1cZoRcmRKFCtSjNGJxPkcP571EfZMcNbzWAc7oK3D1dRzm/V5EwtkANTZxqvuuUA== + dependencies: + "@typescript-eslint/types" "6.0.0" + eslint-visitor-keys "^3.4.1" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1, acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +axios@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" + integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +big-integer@^1.6.44: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bn.js@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +bplist-parser@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" + integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== + dependencies: + big-integer "^1.6.44" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + +bufferutil@^4.0.1: + version "4.0.7" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad" + integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw== + dependencies: + node-gyp-build "^4.3.0" + +bundle-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a" + integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== + dependencies: + run-applescript "^5.0.0" + +call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + integrity sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w== + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +chalk@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" + integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^3.5.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cli-truncate@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" + integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== + dependencies: + slice-ansi "^5.0.0" + string-width "^5.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.19: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +crc-32@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-fetch@^3.1.5: + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== + dependencies: + node-fetch "^2.6.12" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +data-uri-to-buffer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" + integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== + +debug@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +default-browser-id@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c" + integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== + dependencies: + bplist-parser "^0.2.0" + untildify "^4.0.0" + +default-browser@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da" + integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== + dependencies: + bundle-name "^3.0.0" + default-browser-id "^3.0.0" + execa "^7.1.1" + titleize "^3.0.0" + +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dottie@^2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.6.tgz#34564ebfc6ec5e5772272d466424ad5b696484d4" + integrity sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA== + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +encoding@^0.1.11: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +eosjs-api@^7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/eosjs-api/-/eosjs-api-7.0.4.tgz#dc3a7206d4ac3e6818f0a950b8d24333175ac7c9" + integrity sha512-oLbM39rcyWYkqu6nIEQ50I92yT2vvD7WZPZ3FujbydG2ssR5Re/uSvbkFfZTB02g3I4D+UDUA1jd65HlM7r3MQ== + dependencies: + camel-case "^3.0.0" + isomorphic-fetch "^2.2.1" + +eosjs@^22.1.0: + version "22.1.0" + resolved "https://registry.yarnpkg.com/eosjs/-/eosjs-22.1.0.tgz#7ac40e2f1f959fab70539c30ac8ae46c9038aa3c" + integrity sha512-Ka8KO7akC3RxNdSg/3dkGWuUWUQESTzSUzQljBdVP16UG548vmQoBqSGnZdnjlZyfcab8VOu2iEt+JjyfYc5+A== + dependencies: + bn.js "5.2.0" + elliptic "6.5.4" + hash.js "1.1.7" + pako "2.0.3" + +es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.62" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" + integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^8.8.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== + +eslint-plugin-prettier@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz#6887780ed95f7708340ec79acfdf60c35b9be57a" + integrity sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.8.5" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.2.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.1.tgz#936821d3462675f25a18ac5fd88a67cc15b393bd" + integrity sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== + +eslint@^8.40.0: + version "8.45.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.45.0.tgz#bab660f90d18e1364352c0a6b7c6db8edb458b78" + integrity sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.1.0" + "@eslint/js" "8.44.0" + "@humanwhocodes/config-array" "^0.11.10" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.0" + eslint-visitor-keys "^3.4.1" + espree "^9.6.0" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +ethereum-cryptography@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz#18fa7108622e56481157a5cb7c01c0c6a672eb67" + integrity sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug== + dependencies: + "@noble/curves" "1.1.0" + "@noble/hashes" "1.3.1" + "@scure/bip32" "1.3.1" + "@scure/bip39" "1.2.1" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +execa@^7.0.0, execa@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43" + integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + +ext@^1.1.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +fast-glob@^3.2.9, fast-glob@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.0.tgz#7c40cb491e1e2ed5664749e87bfb516dbe8727c0" + integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +fetch-blob@^3.1.2, fetch-blob@^3.1.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" + integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +formdata-polyfill@^4.0.10: + version "4.0.10" + resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" + integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== + dependencies: + fetch-blob "^3.1.2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +generate-function@^2.0.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" + integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== + dependencies: + is-property "^1.0.2" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + integrity sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ== + dependencies: + is-property "^1.0.0" + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.3: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +get-stream@^6.0.0, get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +graphql-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f" + integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw== + dependencies: + "@graphql-typed-document-node/core" "^3.2.0" + cross-fetch "^3.1.5" + +graphql@16: + version "16.7.1" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.7.1.tgz#11475b74a7bff2aefd4691df52a0eca0abd9b642" + integrity sha512-DRYR9tf+UGU0KOsMcKAlXeFfX89UiiIZ0dRU3mR0yJfu6OjZqUcp68NnFLnqQU5RexygFoDy1EW+ccOYcPfmHg== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== + +husky@^8.0.3: + version "8.0.3" + resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" + integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== + +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +ignore-by-default@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== + +ignore@^5.2.0, ignore@^5.2.4: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflection@^1.13.4: + version "1.13.4" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.13.4.tgz#65aa696c4e2da6225b148d7a154c449366633a32" + integrity sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-callable@^1.1.3: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + +is-my-ip-valid@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz#f7220d1146257c98672e6fba097a9f3f2d348442" + integrity sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg== + +is-my-json-valid@^2.20.6: + version "2.20.6" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz#a9d89e56a36493c77bda1440d69ae0dc46a08387" + integrity sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw== + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + is-my-ip-valid "^1.0.0" + jsonpointer "^5.0.0" + xtend "^4.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-property@^1.0.0, is-property@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g== + +is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +is-typed-array@^1.1.10, is-typed-array@^1.1.3: + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isomorphic-fetch@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + integrity sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA== + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +isomorphic-ws@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" + integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== + +joi@^17.9.2: + version "17.9.2" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.9.2.tgz#8b2e4724188369f55451aebd1d0b1d9482470690" + integrity sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.1" + "@sideway/pinpoint" "^2.0.0" + +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +jsonpointer@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" + integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lint-staged@^13.2.2: + version "13.2.3" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.2.3.tgz#f899aad6c093473467e9c9e316e3c2d8a28f87a7" + integrity sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg== + dependencies: + chalk "5.2.0" + cli-truncate "^3.1.0" + commander "^10.0.0" + debug "^4.3.4" + execa "^7.0.0" + lilconfig "2.1.0" + listr2 "^5.0.7" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-inspect "^1.12.3" + pidtree "^0.6.0" + string-argv "^0.3.1" + yaml "^2.2.2" + +listr2@^5.0.7: + version "5.0.8" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-5.0.8.tgz#a9379ffeb4bd83a68931a65fb223a11510d6ba23" + integrity sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.19" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.8.0" + through "^2.3.8" + wrap-ansi "^7.0.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + integrity sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0, mime-db@^1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +moment-timezone@^0.5.43: + version "0.5.43" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.43.tgz#3dd7f3d0c67f78c23cd1906b9b2137a09b3c4790" + integrity sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ== + dependencies: + moment "^2.29.4" + +moment@^2.29.4: + version "2.29.4" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== + dependencies: + lower-case "^1.1.1" + +node-domexception@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-fetch@^2.6.12: + version "2.6.12" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" + integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.1.tgz#b3eea7b54b3a48020e46f4f88b9c5a7430d20b2e" + integrity sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow== + dependencies: + data-uri-to-buffer "^4.0.0" + fetch-blob "^3.1.4" + formdata-polyfill "^4.0.10" + +node-gyp-build@^4.3.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + +nodemon@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.0.1.tgz#affe822a2c5f21354466b2fc8ae83277d27dadc7" + integrity sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw== + dependencies: + chokidar "^3.5.2" + debug "^3.2.7" + ignore-by-default "^1.0.1" + minimatch "^3.1.2" + pstree.remy "^1.1.8" + semver "^7.5.3" + simple-update-notifier "^2.0.0" + supports-color "^5.5.0" + touch "^3.1.0" + undefsafe "^2.0.5" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg== + dependencies: + abbrev "1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + +object-inspect@^1.12.3: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +open@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6" + integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== + dependencies: + default-browser "^4.0.0" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + is-wsl "^2.2.0" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + +pako@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.3.tgz#cdf475e31b678565251406de9e759196a0ea7a43" + integrity sha512-WjR1hOeg+kki3ZIOjaf4b5WVcay1jaliKSYiEaB1XzwhMQZJxRdQRv0V31EKBYlxb4T7SK3hjfc/jxyU64BoSw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pg-cloudflare@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98" + integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== + +pg-connection-string@^2.6.0, pg-connection-string@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.2.tgz#713d82053de4e2bd166fab70cd4f26ad36aab475" + integrity sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.1.tgz#5a902eda79a8d7e3c928b77abf776b3cb7d351f7" + integrity sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og== + +pg-protocol@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.0.tgz#4c91613c0315349363af2084608db843502f8833" + integrity sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^8.6.0: + version "8.11.2" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.11.2.tgz#1a23f6de7bfb65ba56e4dd15df96668d319900c4" + integrity sha512-l4rmVeV8qTIrrPrIR3kZQqBgSN93331s9i6wiUiLOSk0Q7PmUxZD/m1rQI622l3NfqBby9Ar5PABfS/SulfieQ== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.6.2" + pg-pool "^3.6.1" + pg-protocol "^1.6.0" + pg-types "^2.1.0" + pgpass "1.x" + optionalDependencies: + pg-cloudflare "^1.1.1" + +pgpass@1.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pidtree@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.0.tgz#e7b19f691245a21d618c68bc54dc06122f6105ae" + integrity sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g== + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +pstree.remy@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" + integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +retry-as-promised@^7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-7.0.4.tgz#9df73adaeea08cb2948b9d34990549dc13d800a2" + integrity sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-applescript@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c" + integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== + dependencies: + execa "^5.0.0" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.8.0: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^7.5.0, semver@^7.5.1, semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +sequelize-pool@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/sequelize-pool/-/sequelize-pool-7.1.0.tgz#210b391af4002762f823188fd6ecfc7413020768" + integrity sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg== + +sequelize@^6.32.1: + version "6.32.1" + resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-6.32.1.tgz#8e8669a8d6cf711d2d94b33cc721928fad7487f6" + integrity sha512-3Iv0jruv57Y0YvcxQW7BE56O7DC1BojcfIrqh6my+IQwde+9u/YnuYHzK+8kmZLhLvaziRT1eWu38nh9yVwn/g== + dependencies: + "@types/debug" "^4.1.8" + "@types/validator" "^13.7.17" + debug "^4.3.4" + dottie "^2.0.4" + inflection "^1.13.4" + lodash "^4.17.21" + moment "^2.29.4" + moment-timezone "^0.5.43" + pg-connection-string "^2.6.0" + retry-as-promised "^7.0.4" + semver "^7.5.1" + sequelize-pool "^7.1.0" + toposort-class "^1.0.1" + uuid "^8.3.2" + validator "^13.9.0" + wkx "^0.5.0" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +simple-update-notifier@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb" + integrity sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w== + dependencies: + semver "^7.5.3" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + +split2@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +string-argv@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +synckit@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3" + integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q== + dependencies: + "@pkgr/utils" "^2.3.1" + tslib "^2.5.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +titleize@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" + integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toposort-class@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" + integrity sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg== + +touch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" + integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== + dependencies: + nopt "~1.0.10" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-api-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.1.tgz#8144e811d44c749cd65b2da305a032510774452d" + integrity sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A== + +ts-node@^10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@^2.1.0, tslib@^2.5.0, tslib@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" + integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" + integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typescript@^5.0.4: + version "5.1.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" + integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== + +undefsafe@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" + integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== + +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + integrity sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +utf-8-validate@^5.0.2: + version "5.0.10" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" + integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== + dependencies: + node-gyp-build "^4.3.0" + +util@^0.12.5: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +validator@^13.9.0: + version "13.11.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" + integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== + +web-streams-polyfill@^3.0.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" + integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== + +web3-core@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-4.0.3.tgz#eab6cc23a43ff202d8f38bbd9801a7a2ec750cc2" + integrity sha512-KJaH1+ajm/gelvhImkXZx8HrBaGZDERqhOCRpikuwReVDTf4X3TlXqF+oKt153qf5HUXWR4CUL6NkNKNQWjhbA== + dependencies: + web3-errors "^1.0.2" + web3-eth-iban "^4.0.3" + web3-providers-http "^4.0.3" + web3-providers-ws "^4.0.3" + web3-types "^1.0.2" + web3-utils "^4.0.3" + web3-validator "^1.0.2" + optionalDependencies: + web3-providers-ipc "^4.0.3" + +web3-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/web3-errors/-/web3-errors-1.0.2.tgz#e8ce6e22dfdfd9aeaf8d7535653e55b094b5accd" + integrity sha512-LtRUASAQKeCKyxHRhfyU5xiE9asUmo7KJ9bEzzaPlkVYLl5lzhUXzd6lvnQfSaSXJnlzoUXvhI5I0Hpzc8Lohg== + dependencies: + web3-types "^1.0.2" + +web3-eth-abi@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-4.0.3.tgz#cc06cc39868d8bcc181528aa46ae9d5c80ed93b6" + integrity sha512-is1sKkTna5LQri25iRbxJ43kQ6qlFR/Syi6dnpwsFua0qAyKuDTxLZDoMaBfdH8NvxvjuGWFUWALwuSk8gk5Xg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + web3-errors "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + +web3-eth-accounts@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-4.0.3.tgz#7e570b3170aca052b358975235637a94b5313826" + integrity sha512-qS4r25weJYlKzHPIneL3g33LG+I6QkRCs25ZtooK6elurlZY4HyRE04BIWv12xZswtsvdmMt4HysMUNKgLrgPg== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + crc-32 "^1.2.2" + ethereum-cryptography "^2.0.0" + web3-errors "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + web3-validator "^1.0.2" + +web3-eth-contract@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-4.0.3.tgz#667e8f8052034f49a9130e0f286976bcf43c5d77" + integrity sha512-x8YsIVVUeONwLCnUmswk5KD3luYxaKuN/xnSzxpb8fE4/KBA6eJswYcIGPrK9QILrVR26yDV/QQpgLU1IJS14g== + dependencies: + web3-core "^4.0.3" + web3-errors "^1.0.2" + web3-eth "^4.0.3" + web3-eth-abi "^4.0.3" + web3-types "^1.0.2" + web3-utils "^4.0.3" + web3-validator "^1.0.2" + +web3-eth-ens@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-4.0.3.tgz#9b17bdcdc262ddcb5b9fd0b4893c0a9a56bf07ca" + integrity sha512-1tk1WWJB6lsViRFxHR9kt8qgfMV0cySeNBa8H/bZ9/HZ1G8L/c2cboVrG4D0QsPO1im1jQl4Cf3ceKH0PW1KZg== + dependencies: + "@adraffy/ens-normalize" "^1.8.8" + web3-core "^4.0.3" + web3-errors "^1.0.2" + web3-eth "^4.0.3" + web3-eth-contract "^4.0.3" + web3-net "^4.0.3" + web3-types "^1.0.2" + web3-utils "^4.0.3" + web3-validator "^1.0.2" + +web3-eth-iban@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-4.0.3.tgz#3fca87323c00a29f1b3870d397153803eb0bcf4e" + integrity sha512-9gn6fb034fh3DvQeutuhaG3J9+ZSriPC/O/H7K+lgUWJZh/lpaZy5A06nhHzNcleCWC07Q6J7d7VZlNjaBPtOA== + dependencies: + web3-errors "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + web3-validator "^1.0.2" + +web3-eth-personal@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-4.0.3.tgz#df4c59bf2a0e07cd6966259d1312be6b5b61846e" + integrity sha512-Gugz45w/D4wlUNbUth8iHWkv0c5fFZGWZqFvpACJul0z9h0Ou8HzuJMUv3U0xFOQJF5fniVegfp6l0FJQ3hGrQ== + dependencies: + web3-core "^4.0.3" + web3-eth "^4.0.3" + web3-rpc-methods "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + web3-validator "^1.0.2" + +web3-eth@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-4.0.3.tgz#b7f311eba95151f547ccce285893af9917da9e35" + integrity sha512-4t1+lpqzk3ljubr0CKE9Ila82p2Pim6Bn7ZIruVfMt9AOA5wL6M0OeMTy0fWBODLJiZJ7R77Ugm0kvEVWD3lqg== + dependencies: + setimmediate "^1.0.5" + web3-core "^4.0.3" + web3-errors "^1.0.2" + web3-eth-abi "^4.0.3" + web3-eth-accounts "^4.0.3" + web3-net "^4.0.3" + web3-providers-ws "^4.0.3" + web3-rpc-methods "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + web3-validator "^1.0.2" + +web3-net@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-4.0.3.tgz#9aeed6fa3d48adcf63d8377900acbe3e64020154" + integrity sha512-qe+stvVgYhO8AiPgDykZW5gS4mZ3GRWdQ8xn3eTvderresIMvdZYSAoUla2jWl1CgpcqzaoOSO9Pf8t43fr8SA== + dependencies: + web3-core "^4.0.3" + web3-rpc-methods "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + +web3-providers-http@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-4.0.3.tgz#c6c8364ed56c4183e6bed58de20c1972f513c7ae" + integrity sha512-5E6nKjWrwlJdhGImOxyTnFDT6UcZu4waO6AJrENBRh2vdoCfP/Piiv3PLywHs71gwTMsAjy6CNPL5lZdGf+JQA== + dependencies: + cross-fetch "^3.1.5" + web3-errors "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + +web3-providers-ipc@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-4.0.3.tgz#d7af699a2afae0f7396d08ef8cc82b5ab4374398" + integrity sha512-v+Ugp5XXUVcAQju/u4ThdjI3FM9lq674F6cJ7yz3R6uTel+wNPDiT47Se8hvm5grgHid7z3MbVYCQpDCiiAFHw== + dependencies: + web3-errors "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + +web3-providers-ws@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-4.0.3.tgz#c611a0ae81ac022d8ccb01f71da761f7b4decd85" + integrity sha512-V2bYiMvhv+xBYxFdf8V1zGTwhJoAkBQNMECVGNjQIz1qBKuqu6hXHasmkYSJV780LD6qoL58KlfTggjf4SUSaA== + dependencies: + "@types/ws" "^8.5.3" + isomorphic-ws "^5.0.0" + web3-errors "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + ws "^8.8.1" + +web3-rpc-methods@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/web3-rpc-methods/-/web3-rpc-methods-1.0.2.tgz#3ff35c5d4e38ad31ef3cf77eb3fe2fd08e2a3f4a" + integrity sha512-VhLHvgR62JUNgo0op8hP4LcRkvdF0WaHD9xhcEKGLcri9VfYvR1yTZ3CVh6NTgRCmfDePObbp5blHfbla1cC5Q== + dependencies: + web3-core "^4.0.3" + web3-types "^1.0.2" + web3-validator "^1.0.2" + +web3-types@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/web3-types/-/web3-types-1.0.2.tgz#1655a400d31984153fc26ca1f8960f547ca1f2df" + integrity sha512-tLzA9vevGGWdHlxXvPRJjEIIR0UnZBI5Kq9qiENRS/vSekTHAHp7u+WGDxt+6kP105gKlbep50TogQIvJqLfnA== + +web3-utils@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-4.0.3.tgz#80c077e56c0841528ea4513c67d83e460217b379" + integrity sha512-clBvm/vWR2mAc9nPnsPYBZMikIhVG9RAsXdrxvXI4e2jAQ3DTtHKMhqy+Cl214dQaAdAEYyVb5ILW5lKKqk2vA== + dependencies: + ethereum-cryptography "^2.0.0" + web3-errors "^1.0.2" + web3-types "^1.0.2" + web3-validator "^1.0.2" + +web3-validator@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/web3-validator/-/web3-validator-1.0.2.tgz#ca7d247b49f4f690db86e5b953272a627dc5950a" + integrity sha512-orx1CQAEnwJUnl/8iF2II2zSA4wiooNJvFmVE0Dbmt/kE370SugIDViQP76snhxtouG2AXzz4GyKbPCMlLGh/A== + dependencies: + ethereum-cryptography "^2.0.0" + is-my-json-valid "^2.20.6" + util "^0.12.5" + web3-errors "^1.0.2" + web3-types "^1.0.2" + +web3@*, web3@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/web3/-/web3-4.0.3.tgz#afeb977c9f883ff683d630ab9f5937eb56bc7cf4" + integrity sha512-rUMxui5f52yPWjiMRQV6xqIrTQSovYM2CNhl57y+xj/fGXNLbI1D5FsLPnUMZjMaFHJBTteaBxq/sTEaw/1jNA== + dependencies: + web3-core "^4.0.3" + web3-errors "^1.0.2" + web3-eth "^4.0.3" + web3-eth-abi "^4.0.3" + web3-eth-accounts "^4.0.3" + web3-eth-contract "^4.0.3" + web3-eth-ens "^4.0.3" + web3-eth-iban "^4.0.3" + web3-eth-personal "^4.0.3" + web3-net "^4.0.3" + web3-providers-http "^4.0.3" + web3-providers-ws "^4.0.3" + web3-rpc-methods "^1.0.2" + web3-types "^1.0.2" + web3-utils "^4.0.3" + web3-validator "^1.0.2" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +websocket@^1.0.34: + version "1.0.34" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" + integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.50" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + +whatwg-fetch@>=0.10.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which-typed-array@^1.1.2: + version "1.1.10" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.10.tgz#74baa2789991905c2076abb317103b866c64e69e" + integrity sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wkx@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.5.0.tgz#c6c37019acf40e517cc6b94657a25a3d4aa33e8c" + integrity sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg== + dependencies: + "@types/node" "*" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^8.8.1: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^2.2.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" + integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/hasura/metadata/actions.graphql b/hasura/metadata/actions.graphql index 0b70dfb6..fa62826d 100644 --- a/hasura/metadata/actions.graphql +++ b/hasura/metadata/actions.graphql @@ -22,6 +22,18 @@ type Query { eosrate_stats: [EOSRateStats] } +type Query { + evm_token_history( + range: String! + ): [EVMTokenHistory] +} + +type Query { + evm_transactions_history( + range: String! + ): [EVMTransaction] +} + type Mutation { getProducersInfo( bpParams: GetProducersInfoInput! @@ -113,3 +125,15 @@ type EOSRateStats { trustiness: Float } +type EVMTransaction { + datetime: String + transactions_count: Int + avg_gas_used: Float +} + +type EVMTokenHistory { + datetime: String + incoming: Float + outgoing: Float +} + diff --git a/hasura/metadata/actions.yaml b/hasura/metadata/actions.yaml index a11591bd..a4fdf99e 100644 --- a/hasura/metadata/actions.yaml +++ b/hasura/metadata/actions.yaml @@ -26,6 +26,14 @@ actions: handler: '{{HASURA_GRAPHQL_ACTION_BASE_URL}}/get-eos-rate' permissions: - role: guest + - name: evm_token_history + definition: + kind: "" + handler: '{{HASURA_GRAPHQL_ACTION_EVM_URL}}/evm-token-history' + - name: evm_transactions_history + definition: + kind: "" + handler: '{{HASURA_GRAPHQL_ACTION_EVM_URL}}/evm-transactions-history' - name: getProducersInfo definition: kind: synchronous @@ -72,4 +80,6 @@ custom_types: - name: TransferFaucetTokensOutput - name: GetProducersInfoOutput - name: EOSRateStats + - name: EVMTransaction + - name: EVMTokenHistory scalars: [] diff --git a/hasura/metadata/databases/databases.yaml b/hasura/metadata/databases/databases.yaml index 65adeb32..e0f5d8a9 100644 --- a/hasura/metadata/databases/databases.yaml +++ b/hasura/metadata/databases/databases.yaml @@ -2,14 +2,14 @@ kind: postgres configuration: connection_info: - use_prepared_statements: true database_url: from_env: HASURA_GRAPHQL_DATABASE_URL isolation_level: read-committed pool_settings: connection_lifetime: 600 - retries: 1 idle_timeout: 180 max_connections: 50 + retries: 1 + use_prepared_statements: true tables: "!include default/tables/tables.yaml" functions: "!include default/functions/functions.yaml" diff --git a/hasura/metadata/databases/default/functions/public_block_history_by_producer.yaml b/hasura/metadata/databases/default/functions/public_block_history_by_producer.yaml index 6b3aa64f..5d2adcb9 100644 --- a/hasura/metadata/databases/default/functions/public_block_history_by_producer.yaml +++ b/hasura/metadata/databases/default/functions/public_block_history_by_producer.yaml @@ -1,3 +1,3 @@ function: - schema: public name: block_history_by_producer + schema: public diff --git a/hasura/metadata/databases/default/tables/evm_block.yaml b/hasura/metadata/databases/default/tables/evm_block.yaml new file mode 100644 index 00000000..4cc9e58a --- /dev/null +++ b/hasura/metadata/databases/default/tables/evm_block.yaml @@ -0,0 +1,13 @@ +table: + name: block + schema: evm +object_relationships: + - name: BlockToTransaction + using: + manual_configuration: + column_mapping: + hash: block_hash + insertion_order: null + remote_table: + name: transaction + schema: evm diff --git a/hasura/metadata/databases/default/tables/evm_historical_stats.yaml b/hasura/metadata/databases/default/tables/evm_historical_stats.yaml new file mode 100644 index 00000000..db99c245 --- /dev/null +++ b/hasura/metadata/databases/default/tables/evm_historical_stats.yaml @@ -0,0 +1,13 @@ +table: + name: historical_stats + schema: evm +select_permissions: + - role: guest + permission: + columns: + - id + - total_transactions + - tps_all_time_high + - total_incoming_token + - total_outgoing_token + filter: {} diff --git a/hasura/metadata/databases/default/tables/evm_hyperion_state.yaml b/hasura/metadata/databases/default/tables/evm_hyperion_state.yaml new file mode 100644 index 00000000..4dd64e45 --- /dev/null +++ b/hasura/metadata/databases/default/tables/evm_hyperion_state.yaml @@ -0,0 +1,3 @@ +table: + name: hyperion_state + schema: evm diff --git a/hasura/metadata/databases/default/tables/evm_incoming_transfer.yaml b/hasura/metadata/databases/default/tables/evm_incoming_transfer.yaml new file mode 100644 index 00000000..8f2369de --- /dev/null +++ b/hasura/metadata/databases/default/tables/evm_incoming_transfer.yaml @@ -0,0 +1,3 @@ +table: + name: incoming_transfer + schema: evm diff --git a/hasura/metadata/databases/default/tables/evm_param.yaml b/hasura/metadata/databases/default/tables/evm_param.yaml new file mode 100644 index 00000000..e5a5d86b --- /dev/null +++ b/hasura/metadata/databases/default/tables/evm_param.yaml @@ -0,0 +1,3 @@ +table: + name: param + schema: evm diff --git a/hasura/metadata/databases/default/tables/evm_params.yaml b/hasura/metadata/databases/default/tables/evm_params.yaml new file mode 100644 index 00000000..51c501a4 --- /dev/null +++ b/hasura/metadata/databases/default/tables/evm_params.yaml @@ -0,0 +1,3 @@ +table: + name: params + schema: evm diff --git a/hasura/metadata/databases/default/tables/evm_stats.yaml b/hasura/metadata/databases/default/tables/evm_stats.yaml new file mode 100644 index 00000000..ef1561bd --- /dev/null +++ b/hasura/metadata/databases/default/tables/evm_stats.yaml @@ -0,0 +1,10 @@ +table: + name: stats + schema: evm +select_permissions: + - role: guest + permission: + columns: + - block_gas_avg + - daily_transaction_count + filter: {} diff --git a/hasura/metadata/databases/default/tables/evm_transaction.yaml b/hasura/metadata/databases/default/tables/evm_transaction.yaml new file mode 100644 index 00000000..b455b1c6 --- /dev/null +++ b/hasura/metadata/databases/default/tables/evm_transaction.yaml @@ -0,0 +1,3 @@ +table: + name: transaction + schema: evm diff --git a/hasura/metadata/databases/default/tables/evm_transfer.yaml b/hasura/metadata/databases/default/tables/evm_transfer.yaml new file mode 100644 index 00000000..c7fc82a0 --- /dev/null +++ b/hasura/metadata/databases/default/tables/evm_transfer.yaml @@ -0,0 +1,3 @@ +table: + name: transfer + schema: evm diff --git a/hasura/metadata/databases/default/tables/public_block_history_by_producer_type.yaml b/hasura/metadata/databases/default/tables/public_block_history_by_producer_type.yaml index 4f117ad6..7784dd2d 100644 --- a/hasura/metadata/databases/default/tables/public_block_history_by_producer_type.yaml +++ b/hasura/metadata/databases/default/tables/public_block_history_by_producer_type.yaml @@ -1,3 +1,3 @@ table: - schema: public name: block_history_by_producer_type + schema: public diff --git a/hasura/metadata/databases/default/tables/public_cpu.yaml b/hasura/metadata/databases/default/tables/public_cpu.yaml index 2c1b954b..69cd8e50 100644 --- a/hasura/metadata/databases/default/tables/public_cpu.yaml +++ b/hasura/metadata/databases/default/tables/public_cpu.yaml @@ -1,3 +1,3 @@ table: - schema: public name: cpu + schema: public diff --git a/hasura/metadata/databases/default/tables/public_demux_state.yaml b/hasura/metadata/databases/default/tables/public_demux_state.yaml index 0a9123ab..3cd0819b 100644 --- a/hasura/metadata/databases/default/tables/public_demux_state.yaml +++ b/hasura/metadata/databases/default/tables/public_demux_state.yaml @@ -1,3 +1,3 @@ table: - schema: public name: demux_state + schema: public diff --git a/hasura/metadata/databases/default/tables/public_endpoint.yaml b/hasura/metadata/databases/default/tables/public_endpoint.yaml index 625a45d1..5a39a0c7 100644 --- a/hasura/metadata/databases/default/tables/public_endpoint.yaml +++ b/hasura/metadata/databases/default/tables/public_endpoint.yaml @@ -1,6 +1,6 @@ table: - schema: public name: endpoint + schema: public object_relationships: - name: node using: diff --git a/hasura/metadata/databases/default/tables/public_node.yaml b/hasura/metadata/databases/default/tables/public_node.yaml index e102efe0..c6ef2985 100644 --- a/hasura/metadata/databases/default/tables/public_node.yaml +++ b/hasura/metadata/databases/default/tables/public_node.yaml @@ -1,6 +1,6 @@ table: - schema: public name: node + schema: public object_relationships: - name: producer using: @@ -11,15 +11,15 @@ array_relationships: foreign_key_constraint_on: column: node_id table: - schema: public name: endpoint + schema: public - name: node_info using: foreign_key_constraint_on: column: node_id table: - schema: public name: node_info + schema: public select_permissions: - role: guest permission: diff --git a/hasura/metadata/databases/default/tables/public_node_info.yaml b/hasura/metadata/databases/default/tables/public_node_info.yaml index 1a7e0039..bfb39b25 100644 --- a/hasura/metadata/databases/default/tables/public_node_info.yaml +++ b/hasura/metadata/databases/default/tables/public_node_info.yaml @@ -1,6 +1,6 @@ table: - schema: public name: node_info + schema: public object_relationships: - name: node using: diff --git a/hasura/metadata/databases/default/tables/public_round_history.yaml b/hasura/metadata/databases/default/tables/public_round_history.yaml index 2d2e8e84..c2e29e4e 100644 --- a/hasura/metadata/databases/default/tables/public_round_history.yaml +++ b/hasura/metadata/databases/default/tables/public_round_history.yaml @@ -1,3 +1,3 @@ table: - schema: public name: round_history + schema: public diff --git a/hasura/metadata/databases/default/tables/public_schedule_history.yaml b/hasura/metadata/databases/default/tables/public_schedule_history.yaml index be1c7fa7..d68a13b9 100644 --- a/hasura/metadata/databases/default/tables/public_schedule_history.yaml +++ b/hasura/metadata/databases/default/tables/public_schedule_history.yaml @@ -1,3 +1,3 @@ table: - schema: public name: schedule_history + schema: public diff --git a/hasura/metadata/databases/default/tables/public_setting.yaml b/hasura/metadata/databases/default/tables/public_setting.yaml index 404f9387..1db17336 100644 --- a/hasura/metadata/databases/default/tables/public_setting.yaml +++ b/hasura/metadata/databases/default/tables/public_setting.yaml @@ -1,6 +1,6 @@ table: - schema: public name: setting + schema: public select_permissions: - role: guest permission: diff --git a/hasura/metadata/databases/default/tables/tables.yaml b/hasura/metadata/databases/default/tables/tables.yaml index 244cf61c..daa73701 100644 --- a/hasura/metadata/databases/default/tables/tables.yaml +++ b/hasura/metadata/databases/default/tables/tables.yaml @@ -1,3 +1,10 @@ +- "!include evm_block.yaml" +- "!include evm_historical_stats.yaml" +- "!include evm_hyperion_state.yaml" +- "!include evm_param.yaml" +- "!include evm_stats.yaml" +- "!include evm_transaction.yaml" +- "!include evm_transfer.yaml" - "!include public_block_history.yaml" - "!include public_block_history_by_producer_type.yaml" - "!include public_check_history_by_endpoint.yaml" diff --git a/hasura/metadata/rest_endpoints.yaml b/hasura/metadata/rest_endpoints.yaml index eb7fac18..7578e851 100644 --- a/hasura/metadata/rest_endpoints.yaml +++ b/hasura/metadata/rest_endpoints.yaml @@ -1,9 +1,9 @@ -- definition: +- comment: null + definition: query: collection_name: allowed-queries query_name: get-producers-info - url: get-producers-info methods: - POST name: get-producers-info - comment: null + url: get-producers-info diff --git a/hasura/migrations/default/1689614416757_create_schema_evm/down.sql b/hasura/migrations/default/1689614416757_create_schema_evm/down.sql new file mode 100644 index 00000000..5cc73238 --- /dev/null +++ b/hasura/migrations/default/1689614416757_create_schema_evm/down.sql @@ -0,0 +1 @@ +drop schema "evm" cascade; diff --git a/hasura/migrations/default/1689614416757_create_schema_evm/up.sql b/hasura/migrations/default/1689614416757_create_schema_evm/up.sql new file mode 100644 index 00000000..212bc0a8 --- /dev/null +++ b/hasura/migrations/default/1689614416757_create_schema_evm/up.sql @@ -0,0 +1 @@ +create schema "evm"; diff --git a/hasura/migrations/default/1689614424151_create_table_evm_block/down.sql b/hasura/migrations/default/1689614424151_create_table_evm_block/down.sql new file mode 100644 index 00000000..dcdc9c9d --- /dev/null +++ b/hasura/migrations/default/1689614424151_create_table_evm_block/down.sql @@ -0,0 +1 @@ +DROP TABLE "evm"."block"; diff --git a/hasura/migrations/default/1689614424151_create_table_evm_block/up.sql b/hasura/migrations/default/1689614424151_create_table_evm_block/up.sql new file mode 100644 index 00000000..68c24cf9 --- /dev/null +++ b/hasura/migrations/default/1689614424151_create_table_evm_block/up.sql @@ -0,0 +1 @@ +CREATE TABLE "evm"."block" ("hash" varchar NOT NULL, "gasUsed" numeric NOT NULL, "transactions" jsonb NOT NULL, "number" numeric NOT NULL, "timestamp" timestamptz NOT NULL, PRIMARY KEY ("hash") ); diff --git a/hasura/migrations/default/1689614988390_alter_table_evm_block_alter_column_gasUsed/down.sql b/hasura/migrations/default/1689614988390_alter_table_evm_block_alter_column_gasUsed/down.sql new file mode 100644 index 00000000..f8f6ceeb --- /dev/null +++ b/hasura/migrations/default/1689614988390_alter_table_evm_block_alter_column_gasUsed/down.sql @@ -0,0 +1 @@ +alter table "evm"."block" rename column "gas_used" to "gasUsed"; diff --git a/hasura/migrations/default/1689614988390_alter_table_evm_block_alter_column_gasUsed/up.sql b/hasura/migrations/default/1689614988390_alter_table_evm_block_alter_column_gasUsed/up.sql new file mode 100644 index 00000000..927317d1 --- /dev/null +++ b/hasura/migrations/default/1689614988390_alter_table_evm_block_alter_column_gasUsed/up.sql @@ -0,0 +1 @@ +alter table "evm"."block" rename column "gasUsed" to "gas_used"; diff --git a/hasura/migrations/default/1689615011869_alter_table_evm_block_add_unique_number/down.sql b/hasura/migrations/default/1689615011869_alter_table_evm_block_add_unique_number/down.sql new file mode 100644 index 00000000..bda7f6e8 --- /dev/null +++ b/hasura/migrations/default/1689615011869_alter_table_evm_block_add_unique_number/down.sql @@ -0,0 +1 @@ +alter table "evm"."block" drop constraint "block_number_key"; diff --git a/hasura/migrations/default/1689615011869_alter_table_evm_block_add_unique_number/up.sql b/hasura/migrations/default/1689615011869_alter_table_evm_block_add_unique_number/up.sql new file mode 100644 index 00000000..f9f18195 --- /dev/null +++ b/hasura/migrations/default/1689615011869_alter_table_evm_block_add_unique_number/up.sql @@ -0,0 +1 @@ +alter table "evm"."block" add constraint "block_number_key" unique ("number"); diff --git a/hasura/migrations/default/1689615116520_create_table_evm_transaction/down.sql b/hasura/migrations/default/1689615116520_create_table_evm_transaction/down.sql new file mode 100644 index 00000000..e7458dbe --- /dev/null +++ b/hasura/migrations/default/1689615116520_create_table_evm_transaction/down.sql @@ -0,0 +1 @@ +DROP TABLE "evm"."transaction"; diff --git a/hasura/migrations/default/1689615116520_create_table_evm_transaction/up.sql b/hasura/migrations/default/1689615116520_create_table_evm_transaction/up.sql new file mode 100644 index 00000000..55d9bbf9 --- /dev/null +++ b/hasura/migrations/default/1689615116520_create_table_evm_transaction/up.sql @@ -0,0 +1 @@ +CREATE TABLE "evm"."transaction" ("block_hash" varchar NOT NULL, "block_number" numeric NOT NULL, "gas" numeric NOT NULL, "gas_price" numeric NOT NULL, "hash" varchar NOT NULL, PRIMARY KEY ("hash") ); diff --git a/hasura/migrations/default/1689615410384_alter_table_evm_block_add_unique_number_hash/down.sql b/hasura/migrations/default/1689615410384_alter_table_evm_block_add_unique_number_hash/down.sql new file mode 100644 index 00000000..2fb4743d --- /dev/null +++ b/hasura/migrations/default/1689615410384_alter_table_evm_block_add_unique_number_hash/down.sql @@ -0,0 +1,2 @@ +alter table "evm"."block" drop constraint "block_number_hash_key"; +alter table "evm"."block" add constraint "block_number_key" unique ("number"); diff --git a/hasura/migrations/default/1689615410384_alter_table_evm_block_add_unique_number_hash/up.sql b/hasura/migrations/default/1689615410384_alter_table_evm_block_add_unique_number_hash/up.sql new file mode 100644 index 00000000..4e0f0f1c --- /dev/null +++ b/hasura/migrations/default/1689615410384_alter_table_evm_block_add_unique_number_hash/up.sql @@ -0,0 +1,2 @@ +alter table "evm"."block" drop constraint "block_number_key"; +alter table "evm"."block" add constraint "block_number_hash_key" unique ("number", "hash"); diff --git a/hasura/migrations/default/1689615432215_set_fk_evm_transaction_block_number_block_hash/down.sql b/hasura/migrations/default/1689615432215_set_fk_evm_transaction_block_number_block_hash/down.sql new file mode 100644 index 00000000..9298915c --- /dev/null +++ b/hasura/migrations/default/1689615432215_set_fk_evm_transaction_block_number_block_hash/down.sql @@ -0,0 +1 @@ +alter table "evm"."transaction" drop constraint "transaction_block_number_block_hash_fkey"; diff --git a/hasura/migrations/default/1689615432215_set_fk_evm_transaction_block_number_block_hash/up.sql b/hasura/migrations/default/1689615432215_set_fk_evm_transaction_block_number_block_hash/up.sql new file mode 100644 index 00000000..f2cee2b1 --- /dev/null +++ b/hasura/migrations/default/1689615432215_set_fk_evm_transaction_block_number_block_hash/up.sql @@ -0,0 +1,5 @@ +alter table "evm"."transaction" + add constraint "transaction_block_number_block_hash_fkey" + foreign key ("block_number", "block_hash") + references "evm"."block" + ("number", "hash") on update restrict on delete restrict; diff --git a/hasura/migrations/default/1689963835559_create_table_evm_params/down.sql b/hasura/migrations/default/1689963835559_create_table_evm_params/down.sql new file mode 100644 index 00000000..746c729e --- /dev/null +++ b/hasura/migrations/default/1689963835559_create_table_evm_params/down.sql @@ -0,0 +1 @@ +DROP TABLE "evm"."params"; diff --git a/hasura/migrations/default/1689963835559_create_table_evm_params/up.sql b/hasura/migrations/default/1689963835559_create_table_evm_params/up.sql new file mode 100644 index 00000000..aaba3008 --- /dev/null +++ b/hasura/migrations/default/1689963835559_create_table_evm_params/up.sql @@ -0,0 +1,2 @@ +CREATE TABLE "evm"."params" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "last_block_synced" numeric NOT NULL, PRIMARY KEY ("id") ); +CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/hasura/migrations/default/1689963954957_rename_table_evm_params/down.sql b/hasura/migrations/default/1689963954957_rename_table_evm_params/down.sql new file mode 100644 index 00000000..bfaa32fb --- /dev/null +++ b/hasura/migrations/default/1689963954957_rename_table_evm_params/down.sql @@ -0,0 +1 @@ +alter table "evm"."param" rename to "params"; diff --git a/hasura/migrations/default/1689963954957_rename_table_evm_params/up.sql b/hasura/migrations/default/1689963954957_rename_table_evm_params/up.sql new file mode 100644 index 00000000..6ff3d5cd --- /dev/null +++ b/hasura/migrations/default/1689963954957_rename_table_evm_params/up.sql @@ -0,0 +1 @@ +alter table "evm"."params" rename to "param"; diff --git a/hasura/migrations/default/1689964045956_create_table_evm_hyperion_state/down.sql b/hasura/migrations/default/1689964045956_create_table_evm_hyperion_state/down.sql new file mode 100644 index 00000000..7e7c39fb --- /dev/null +++ b/hasura/migrations/default/1689964045956_create_table_evm_hyperion_state/down.sql @@ -0,0 +1 @@ +DROP TABLE "evm"."hyperion_state"; diff --git a/hasura/migrations/default/1689964045956_create_table_evm_hyperion_state/up.sql b/hasura/migrations/default/1689964045956_create_table_evm_hyperion_state/up.sql new file mode 100644 index 00000000..4f40f17e --- /dev/null +++ b/hasura/migrations/default/1689964045956_create_table_evm_hyperion_state/up.sql @@ -0,0 +1,18 @@ +CREATE TABLE "evm"."hyperion_state" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "last_synced_at" timestamptz NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") ); +CREATE OR REPLACE FUNCTION "evm"."set_current_timestamp_updated_at"() +RETURNS TRIGGER AS $$ +DECLARE + _new record; +BEGIN + _new := NEW; + _new."updated_at" = NOW(); + RETURN _new; +END; +$$ LANGUAGE plpgsql; +CREATE TRIGGER "set_evm_hyperion_state_updated_at" +BEFORE UPDATE ON "evm"."hyperion_state" +FOR EACH ROW +EXECUTE PROCEDURE "evm"."set_current_timestamp_updated_at"(); +COMMENT ON TRIGGER "set_evm_hyperion_state_updated_at" ON "evm"."hyperion_state" +IS 'trigger to set value of column "updated_at" to current timestamp on row update'; +CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/hasura/migrations/default/1689983709652_create_table_evm_incoming_transfer/down.sql b/hasura/migrations/default/1689983709652_create_table_evm_incoming_transfer/down.sql new file mode 100644 index 00000000..5b3a9650 --- /dev/null +++ b/hasura/migrations/default/1689983709652_create_table_evm_incoming_transfer/down.sql @@ -0,0 +1 @@ +DROP TABLE "evm"."incoming_transfer"; diff --git a/hasura/migrations/default/1689983709652_create_table_evm_incoming_transfer/up.sql b/hasura/migrations/default/1689983709652_create_table_evm_incoming_transfer/up.sql new file mode 100644 index 00000000..012716d0 --- /dev/null +++ b/hasura/migrations/default/1689983709652_create_table_evm_incoming_transfer/up.sql @@ -0,0 +1,2 @@ +CREATE TABLE "evm"."incoming_transfer" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "block" numeric NOT NULL, "transaction_id" varchar NOT NULL, "from" varchar NOT NULL, "to" varchar NOT NULL, "amount" numeric NOT NULL, "symbol" varchar NOT NULL, "memo" varchar NOT NULL, "quantity" varchar NOT NULL, PRIMARY KEY ("id") );COMMENT ON TABLE "evm"."incoming_transfer" IS E'Incoming TLOS token transfer. (EOS account -> tEVM address)'; +CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/hasura/migrations/default/1689984918750_alter_table_evm_incoming_transfer_add_column_timestamp/down.sql b/hasura/migrations/default/1689984918750_alter_table_evm_incoming_transfer_add_column_timestamp/down.sql new file mode 100644 index 00000000..df06c440 --- /dev/null +++ b/hasura/migrations/default/1689984918750_alter_table_evm_incoming_transfer_add_column_timestamp/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "evm"."incoming_transfer" add column "timestamp" timestamptz +-- not null; diff --git a/hasura/migrations/default/1689984918750_alter_table_evm_incoming_transfer_add_column_timestamp/up.sql b/hasura/migrations/default/1689984918750_alter_table_evm_incoming_transfer_add_column_timestamp/up.sql new file mode 100644 index 00000000..9fbbb6b1 --- /dev/null +++ b/hasura/migrations/default/1689984918750_alter_table_evm_incoming_transfer_add_column_timestamp/up.sql @@ -0,0 +1,2 @@ +alter table "evm"."incoming_transfer" add column "timestamp" timestamptz + not null; diff --git a/hasura/migrations/default/1690322260794_create_evm_stats_view/down.sql b/hasura/migrations/default/1690322260794_create_evm_stats_view/down.sql new file mode 100644 index 00000000..d344e151 --- /dev/null +++ b/hasura/migrations/default/1690322260794_create_evm_stats_view/down.sql @@ -0,0 +1,67 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- CREATE OR REPLACE VIEW "evm"."stats" AS +-- SELECT +-- evm_block.avg_gas_used AS block_gas_avg, +-- daily_transactions.total_transaction_count AS daily_transaction_count, +-- ath.max_transaction_sum AS ath_transaction_sum, +-- incoming_tlos.transfer_count AS incoming_tlos_count +-- FROM +-- ( +-- ( +-- ( +-- ( +-- SELECT AVG(subquery_alias.gas_used) AS avg_gas_used +-- FROM ( +-- SELECT gas_used, timestamp +-- FROM evm.block +-- ORDER BY timestamp DESC +-- LIMIT 100 +-- ) subquery_alias +-- ) evm_block +-- CROSS JOIN LATERAL ( +-- SELECT +-- sum(jsonb_array_length(block.transactions)) AS total_transaction_count +-- FROM +-- evm.block +-- WHERE +-- ( +-- block.timestamp >= (now() - '24:00:00' :: interval) +-- ) +-- ) daily_transactions +-- ) +-- CROSS JOIN LATERAL ( +-- SELECT +-- max(pairs_sum.total_transaction_count) AS max_transaction_sum +-- FROM +-- ( +-- SELECT +-- ( +-- (b1.number || ' and ' :: text) || (b1.number + (1) :: numeric) +-- ) AS block_pair, +-- sum( +-- ( +-- jsonb_array_length(b1.transactions) + jsonb_array_length(b2.transactions) +-- ) +-- ) AS total_transaction_count +-- FROM +-- ( +-- evm.block b1 +-- LEFT JOIN evm.block b2 ON ((b1.number = (b2.number - (1) :: numeric))) +-- ) +-- WHERE +-- ((b1.number % (2) :: numeric) = (0) :: numeric) +-- GROUP BY +-- ( +-- (b1.number || ' and ' :: text) || (b1.number + (1) :: numeric) +-- ) +-- ) pairs_sum +-- ) ath +-- ) +-- CROSS JOIN LATERAL ( +-- SELECT +-- count(incoming_transfer.id) AS transfer_count +-- FROM +-- evm.incoming_transfer +-- ) incoming_tlos +-- ); diff --git a/hasura/migrations/default/1690322260794_create_evm_stats_view/up.sql b/hasura/migrations/default/1690322260794_create_evm_stats_view/up.sql new file mode 100644 index 00000000..bbdcfd43 --- /dev/null +++ b/hasura/migrations/default/1690322260794_create_evm_stats_view/up.sql @@ -0,0 +1,65 @@ +CREATE OR REPLACE VIEW "evm"."stats" AS +SELECT + evm_block.avg_gas_used AS block_gas_avg, + daily_transactions.total_transaction_count AS daily_transaction_count, + ath.max_transaction_sum AS ath_transaction_sum, + incoming_tlos.transfer_count AS incoming_tlos_count +FROM + ( + ( + ( + ( + SELECT AVG(subquery_alias.gas_used) AS avg_gas_used + FROM ( + SELECT gas_used, timestamp + FROM evm.block + ORDER BY timestamp DESC + LIMIT 100 + ) subquery_alias + ) evm_block + CROSS JOIN LATERAL ( + SELECT + sum(jsonb_array_length(block.transactions)) AS total_transaction_count + FROM + evm.block + WHERE + ( + block.timestamp >= (now() - '24:00:00' :: interval) + ) + ) daily_transactions + ) + CROSS JOIN LATERAL ( + SELECT + max(pairs_sum.total_transaction_count) AS max_transaction_sum + FROM + ( + SELECT + ( + (b1.number || ' and ' :: text) || (b1.number + (1) :: numeric) + ) AS block_pair, + sum( + ( + jsonb_array_length(b1.transactions) + jsonb_array_length(b2.transactions) + ) + ) AS total_transaction_count + FROM + ( + evm.block b1 + LEFT JOIN evm.block b2 ON ((b1.number = (b2.number - (1) :: numeric))) + ) + WHERE + ((b1.number % (2) :: numeric) = (0) :: numeric) + GROUP BY + ( + (b1.number || ' and ' :: text) || (b1.number + (1) :: numeric) + ) + ) pairs_sum + ) ath + ) + CROSS JOIN LATERAL ( + SELECT + count(incoming_transfer.id) AS transfer_count + FROM + evm.incoming_transfer + ) incoming_tlos + ); diff --git a/hasura/migrations/default/1690322582361_create_evm_stats_view_v2/down.sql b/hasura/migrations/default/1690322582361_create_evm_stats_view_v2/down.sql new file mode 100644 index 00000000..97b59a23 --- /dev/null +++ b/hasura/migrations/default/1690322582361_create_evm_stats_view_v2/down.sql @@ -0,0 +1,67 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- CREATE OR REPLACE VIEW "evm"."stats" AS +-- SELECT +-- COALESCE(evm_block.avg_gas_used, 0) AS block_gas_avg, +-- COALESCE(daily_transactions.total_transaction_count, 0) AS daily_transaction_count, +-- COALESCE(ath.max_transaction_sum, 0) AS ath_transaction_sum, +-- COALESCE(incoming_tlos.transfer_count, 0) AS incoming_tlos_count +-- FROM +-- ( +-- ( +-- ( +-- ( +-- SELECT AVG(subquery_alias.gas_used) AS avg_gas_used +-- FROM ( +-- SELECT gas_used, timestamp +-- FROM evm.block +-- ORDER BY timestamp DESC +-- LIMIT 100 +-- ) subquery_alias +-- ) evm_block +-- CROSS JOIN LATERAL ( +-- SELECT +-- sum(jsonb_array_length(block.transactions)) AS total_transaction_count +-- FROM +-- evm.block +-- WHERE +-- ( +-- block.timestamp >= (now() - '24:00:00' :: interval) +-- ) +-- ) daily_transactions +-- ) +-- CROSS JOIN LATERAL ( +-- SELECT +-- max(pairs_sum.total_transaction_count) AS max_transaction_sum +-- FROM +-- ( +-- SELECT +-- ( +-- (b1.number || ' and ' :: text) || (b1.number + (1) :: numeric) +-- ) AS block_pair, +-- sum( +-- ( +-- jsonb_array_length(b1.transactions) + jsonb_array_length(b2.transactions) +-- ) +-- ) AS total_transaction_count +-- FROM +-- ( +-- evm.block b1 +-- LEFT JOIN evm.block b2 ON ((b1.number = (b2.number - (1) :: numeric))) +-- ) +-- WHERE +-- ((b1.number % (2) :: numeric) = (0) :: numeric) +-- GROUP BY +-- ( +-- (b1.number || ' and ' :: text) || (b1.number + (1) :: numeric) +-- ) +-- ) pairs_sum +-- ) ath +-- ) +-- CROSS JOIN LATERAL ( +-- SELECT +-- count(incoming_transfer.id) AS transfer_count +-- FROM +-- evm.incoming_transfer +-- ) incoming_tlos +-- ); diff --git a/hasura/migrations/default/1690322582361_create_evm_stats_view_v2/up.sql b/hasura/migrations/default/1690322582361_create_evm_stats_view_v2/up.sql new file mode 100644 index 00000000..763f92f5 --- /dev/null +++ b/hasura/migrations/default/1690322582361_create_evm_stats_view_v2/up.sql @@ -0,0 +1,65 @@ +CREATE OR REPLACE VIEW "evm"."stats" AS +SELECT + COALESCE(evm_block.avg_gas_used, 0) AS block_gas_avg, + COALESCE(daily_transactions.total_transaction_count, 0) AS daily_transaction_count, + COALESCE(ath.max_transaction_sum, 0) AS ath_transaction_sum, + COALESCE(incoming_tlos.transfer_count, 0) AS incoming_tlos_count +FROM + ( + ( + ( + ( + SELECT AVG(subquery_alias.gas_used) AS avg_gas_used + FROM ( + SELECT gas_used, timestamp + FROM evm.block + ORDER BY timestamp DESC + LIMIT 100 + ) subquery_alias + ) evm_block + CROSS JOIN LATERAL ( + SELECT + sum(jsonb_array_length(block.transactions)) AS total_transaction_count + FROM + evm.block + WHERE + ( + block.timestamp >= (now() - '24:00:00' :: interval) + ) + ) daily_transactions + ) + CROSS JOIN LATERAL ( + SELECT + max(pairs_sum.total_transaction_count) AS max_transaction_sum + FROM + ( + SELECT + ( + (b1.number || ' and ' :: text) || (b1.number + (1) :: numeric) + ) AS block_pair, + sum( + ( + jsonb_array_length(b1.transactions) + jsonb_array_length(b2.transactions) + ) + ) AS total_transaction_count + FROM + ( + evm.block b1 + LEFT JOIN evm.block b2 ON ((b1.number = (b2.number - (1) :: numeric))) + ) + WHERE + ((b1.number % (2) :: numeric) = (0) :: numeric) + GROUP BY + ( + (b1.number || ' and ' :: text) || (b1.number + (1) :: numeric) + ) + ) pairs_sum + ) ath + ) + CROSS JOIN LATERAL ( + SELECT + count(incoming_transfer.id) AS transfer_count + FROM + evm.incoming_transfer + ) incoming_tlos + ); diff --git a/hasura/migrations/default/1690396057707_alter_table_evm_incoming_transfer_add_column_type/down.sql b/hasura/migrations/default/1690396057707_alter_table_evm_incoming_transfer_add_column_type/down.sql new file mode 100644 index 00000000..418d6181 --- /dev/null +++ b/hasura/migrations/default/1690396057707_alter_table_evm_incoming_transfer_add_column_type/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "evm"."incoming_transfer" add column "type" varchar +-- not null default 'incoming'; diff --git a/hasura/migrations/default/1690396057707_alter_table_evm_incoming_transfer_add_column_type/up.sql b/hasura/migrations/default/1690396057707_alter_table_evm_incoming_transfer_add_column_type/up.sql new file mode 100644 index 00000000..856ef635 --- /dev/null +++ b/hasura/migrations/default/1690396057707_alter_table_evm_incoming_transfer_add_column_type/up.sql @@ -0,0 +1,2 @@ +alter table "evm"."incoming_transfer" add column "type" varchar + not null default 'incoming'; diff --git a/hasura/migrations/default/1690396062626_rename_table_evm_incoming_transfer/down.sql b/hasura/migrations/default/1690396062626_rename_table_evm_incoming_transfer/down.sql new file mode 100644 index 00000000..4da99809 --- /dev/null +++ b/hasura/migrations/default/1690396062626_rename_table_evm_incoming_transfer/down.sql @@ -0,0 +1 @@ +alter table "evm"."transfer" rename to "incoming_transfer"; diff --git a/hasura/migrations/default/1690396062626_rename_table_evm_incoming_transfer/up.sql b/hasura/migrations/default/1690396062626_rename_table_evm_incoming_transfer/up.sql new file mode 100644 index 00000000..1508c275 --- /dev/null +++ b/hasura/migrations/default/1690396062626_rename_table_evm_incoming_transfer/up.sql @@ -0,0 +1 @@ +alter table "evm"."incoming_transfer" rename to "transfer"; diff --git a/hasura/migrations/default/1690397773824_create_evm_stats_view_v3/down.sql b/hasura/migrations/default/1690397773824_create_evm_stats_view_v3/down.sql new file mode 100644 index 00000000..c5a71f2f --- /dev/null +++ b/hasura/migrations/default/1690397773824_create_evm_stats_view_v3/down.sql @@ -0,0 +1,29 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- CREATE OR REPLACE VIEW "evm"."stats" AS +-- SELECT COALESCE(evm_block.avg_gas_used, (0)::numeric) AS block_gas_avg, +-- COALESCE(daily_transactions.total_transaction_count, (0)::bigint) AS daily_transaction_count, +-- COALESCE(ath.max_transaction_sum, (0)::bigint) AS ath_transaction_sum, +-- COALESCE(incoming_tlos.incoming_transfer_count, (0)::bigint) AS incoming_tlos_count, +-- COALESCE(incoming_tlos.outgoing_transfer_count, (0)::bigint) AS outgoing_tlos_count +-- FROM (((( SELECT avg(subquery_alias.gas_used) AS avg_gas_used +-- FROM ( SELECT block.gas_used, +-- block."timestamp" +-- FROM evm.block +-- ORDER BY block."timestamp" DESC +-- LIMIT 100) subquery_alias) evm_block +-- CROSS JOIN LATERAL ( SELECT sum(jsonb_array_length(block.transactions)) AS total_transaction_count +-- FROM evm.block +-- WHERE (block."timestamp" >= (now() - '24:00:00'::interval))) daily_transactions) +-- CROSS JOIN LATERAL ( SELECT max(pairs_sum.total_transaction_count) AS max_transaction_sum +-- FROM ( SELECT ((b1.number || ' and '::text) || (b1.number + (1)::numeric)) AS block_pair, +-- sum((jsonb_array_length(b1.transactions) + jsonb_array_length(b2.transactions))) AS total_transaction_count +-- FROM (evm.block b1 +-- LEFT JOIN evm.block b2 ON ((b1.number = (b2.number - (1)::numeric)))) +-- WHERE ((b1.number % (2)::numeric) = (0)::numeric) +-- GROUP BY ((b1.number || ' and '::text) || (b1.number + (1)::numeric))) pairs_sum) ath) +-- CROSS JOIN LATERAL ( SELECT +-- COUNT(CASE WHEN transfer.type = 'incoming' THEN 1 END) AS incoming_transfer_count, +-- COUNT(CASE WHEN transfer.type = 'outgoing' THEN 1 END) AS outgoing_transfer_count +-- FROM +-- evm.transfer) incoming_tlos); diff --git a/hasura/migrations/default/1690397773824_create_evm_stats_view_v3/up.sql b/hasura/migrations/default/1690397773824_create_evm_stats_view_v3/up.sql new file mode 100644 index 00000000..9534b55f --- /dev/null +++ b/hasura/migrations/default/1690397773824_create_evm_stats_view_v3/up.sql @@ -0,0 +1,27 @@ +CREATE OR REPLACE VIEW "evm"."stats" AS + SELECT COALESCE(evm_block.avg_gas_used, (0)::numeric) AS block_gas_avg, + COALESCE(daily_transactions.total_transaction_count, (0)::bigint) AS daily_transaction_count, + COALESCE(ath.max_transaction_sum, (0)::bigint) AS ath_transaction_sum, + COALESCE(incoming_tlos.incoming_transfer_count, (0)::bigint) AS incoming_tlos_count, + COALESCE(incoming_tlos.outgoing_transfer_count, (0)::bigint) AS outgoing_tlos_count + FROM (((( SELECT avg(subquery_alias.gas_used) AS avg_gas_used + FROM ( SELECT block.gas_used, + block."timestamp" + FROM evm.block + ORDER BY block."timestamp" DESC + LIMIT 100) subquery_alias) evm_block + CROSS JOIN LATERAL ( SELECT sum(jsonb_array_length(block.transactions)) AS total_transaction_count + FROM evm.block + WHERE (block."timestamp" >= (now() - '24:00:00'::interval))) daily_transactions) + CROSS JOIN LATERAL ( SELECT max(pairs_sum.total_transaction_count) AS max_transaction_sum + FROM ( SELECT ((b1.number || ' and '::text) || (b1.number + (1)::numeric)) AS block_pair, + sum((jsonb_array_length(b1.transactions) + jsonb_array_length(b2.transactions))) AS total_transaction_count + FROM (evm.block b1 + LEFT JOIN evm.block b2 ON ((b1.number = (b2.number - (1)::numeric)))) + WHERE ((b1.number % (2)::numeric) = (0)::numeric) + GROUP BY ((b1.number || ' and '::text) || (b1.number + (1)::numeric))) pairs_sum) ath) + CROSS JOIN LATERAL ( SELECT + COUNT(CASE WHEN transfer.type = 'incoming' THEN 1 END) AS incoming_transfer_count, + COUNT(CASE WHEN transfer.type = 'outgoing' THEN 1 END) AS outgoing_transfer_count +FROM + evm.transfer) incoming_tlos); diff --git a/hasura/migrations/default/1690561974241_alter_table_evm_param_alter_column_last_block_synced/down.sql b/hasura/migrations/default/1690561974241_alter_table_evm_param_alter_column_last_block_synced/down.sql new file mode 100644 index 00000000..a06e7ffb --- /dev/null +++ b/hasura/migrations/default/1690561974241_alter_table_evm_param_alter_column_last_block_synced/down.sql @@ -0,0 +1 @@ +alter table "evm"."param" rename column "next_block" to "last_block_synced"; diff --git a/hasura/migrations/default/1690561974241_alter_table_evm_param_alter_column_last_block_synced/up.sql b/hasura/migrations/default/1690561974241_alter_table_evm_param_alter_column_last_block_synced/up.sql new file mode 100644 index 00000000..c3d5a473 --- /dev/null +++ b/hasura/migrations/default/1690561974241_alter_table_evm_param_alter_column_last_block_synced/up.sql @@ -0,0 +1 @@ +alter table "evm"."param" rename column "last_block_synced" to "next_block"; diff --git a/hasura/migrations/default/1690573147430_alter_table_evm_param_add_column_is_synced/down.sql b/hasura/migrations/default/1690573147430_alter_table_evm_param_add_column_is_synced/down.sql new file mode 100644 index 00000000..0ec37ced --- /dev/null +++ b/hasura/migrations/default/1690573147430_alter_table_evm_param_add_column_is_synced/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "evm"."param" add column "is_synced" boolean +-- not null default 'false'; diff --git a/hasura/migrations/default/1690573147430_alter_table_evm_param_add_column_is_synced/up.sql b/hasura/migrations/default/1690573147430_alter_table_evm_param_add_column_is_synced/up.sql new file mode 100644 index 00000000..8718c408 --- /dev/null +++ b/hasura/migrations/default/1690573147430_alter_table_evm_param_add_column_is_synced/up.sql @@ -0,0 +1,2 @@ +alter table "evm"."param" add column "is_synced" boolean + not null default 'false'; diff --git a/hasura/migrations/default/1692117604338_set_fk_evm_transaction_block_hash_block_number/down.sql b/hasura/migrations/default/1692117604338_set_fk_evm_transaction_block_hash_block_number/down.sql new file mode 100644 index 00000000..922df2f9 --- /dev/null +++ b/hasura/migrations/default/1692117604338_set_fk_evm_transaction_block_hash_block_number/down.sql @@ -0,0 +1,5 @@ +alter table "evm"."transaction" drop constraint "transaction_block_hash_block_number_fkey", + add constraint "transaction_block_number_block_hash_fkey" + foreign key ("block_number", "block_hash") + references "evm"."block" + ("number", "hash") on update restrict on delete restrict; diff --git a/hasura/migrations/default/1692117604338_set_fk_evm_transaction_block_hash_block_number/up.sql b/hasura/migrations/default/1692117604338_set_fk_evm_transaction_block_hash_block_number/up.sql new file mode 100644 index 00000000..0266f6a7 --- /dev/null +++ b/hasura/migrations/default/1692117604338_set_fk_evm_transaction_block_hash_block_number/up.sql @@ -0,0 +1,5 @@ +alter table "evm"."transaction" drop constraint "transaction_block_number_block_hash_fkey", + add constraint "transaction_block_hash_block_number_fkey" + foreign key ("block_hash", "block_number") + references "evm"."block" + ("hash", "number") on update restrict on delete cascade; diff --git a/hasura/migrations/default/1692132948056_create_table_evm_historical_stats/down.sql b/hasura/migrations/default/1692132948056_create_table_evm_historical_stats/down.sql new file mode 100644 index 00000000..8ab1f4c2 --- /dev/null +++ b/hasura/migrations/default/1692132948056_create_table_evm_historical_stats/down.sql @@ -0,0 +1 @@ +DROP TABLE "evm"."historical_stats"; diff --git a/hasura/migrations/default/1692132948056_create_table_evm_historical_stats/up.sql b/hasura/migrations/default/1692132948056_create_table_evm_historical_stats/up.sql new file mode 100644 index 00000000..49bc7329 --- /dev/null +++ b/hasura/migrations/default/1692132948056_create_table_evm_historical_stats/up.sql @@ -0,0 +1,2 @@ +CREATE TABLE "evm"."historical_stats" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "total_transactions" integer NOT NULL DEFAULT 0, "tps_all_time_high" jsonb NOT NULL DEFAULT jsonb_build_object(), "total_incoming_token" numeric NOT NULL DEFAULT 0, "total_outgoing_token" numeric NOT NULL DEFAULT 0, PRIMARY KEY ("id") , UNIQUE ("id")); +CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/hasura/migrations/default/1692286077976_create_evm_stats_view_v4/down.sql b/hasura/migrations/default/1692286077976_create_evm_stats_view_v4/down.sql new file mode 100644 index 00000000..839dc42d --- /dev/null +++ b/hasura/migrations/default/1692286077976_create_evm_stats_view_v4/down.sql @@ -0,0 +1,30 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- DROP VIEW IF EXISTS "evm"."stats"; +-- CREATE OR REPLACE VIEW "evm"."stats" AS +-- SELECT COALESCE(evm_block.avg_gas_used, (0)::numeric) AS block_gas_avg, +-- COALESCE(daily_transactions.total_transaction_count, (0)::bigint) AS daily_transaction_count, +-- COALESCE(max_transaction_sum, (0)::numeric) AS ath_transactions_count, +-- COALESCE(gas_used_sum, (0)::numeric) AS ath_gas_used, +-- blocks AS ath_blocks +-- FROM (((( SELECT avg(subquery_alias.gas_used) AS avg_gas_used +-- FROM ( SELECT block.gas_used, block."timestamp" +-- FROM evm.block +-- ORDER BY block."timestamp" DESC +-- LIMIT 100) subquery_alias) evm_block +-- CROSS JOIN LATERAL ( +-- SELECT sum(jsonb_array_length(block.transactions)) AS total_transaction_count +-- FROM evm.block +-- WHERE (block."timestamp" >= (now() - '24:00:00'::interval))) daily_transactions) +-- CROSS JOIN LATERAL ( +-- WITH subquery AS( +-- SELECT array_to_string(array_agg(evm.block.number), ',') AS blocks , +-- sum(jsonb_array_length(evm.block.transactions)) AS total_transaction_count, +-- sum(evm.block.gas_used) AS gas_used_sum +-- FROM evm.block +-- GROUP BY timestamp) +-- SELECT blocks, max_transaction_sum, gas_used_sum +-- FROM ( SELECT max(subquery.total_transaction_count) AS max_transaction_sum +-- FROM subquery) q1 +-- INNER JOIN subquery q2 ON q1.max_transaction_sum = q2.total_transaction_count +-- LIMIT 1) ath_last_year)); diff --git a/hasura/migrations/default/1692286077976_create_evm_stats_view_v4/up.sql b/hasura/migrations/default/1692286077976_create_evm_stats_view_v4/up.sql new file mode 100644 index 00000000..91993b63 --- /dev/null +++ b/hasura/migrations/default/1692286077976_create_evm_stats_view_v4/up.sql @@ -0,0 +1,28 @@ +DROP VIEW IF EXISTS "evm"."stats"; +CREATE OR REPLACE VIEW "evm"."stats" AS + SELECT COALESCE(evm_block.avg_gas_used, (0)::numeric) AS block_gas_avg, + COALESCE(daily_transactions.total_transaction_count, (0)::bigint) AS daily_transaction_count, + COALESCE(max_transaction_sum, (0)::numeric) AS ath_transactions_count, + COALESCE(gas_used_sum, (0)::numeric) AS ath_gas_used, + blocks AS ath_blocks + FROM (((( SELECT avg(subquery_alias.gas_used) AS avg_gas_used + FROM ( SELECT block.gas_used, block."timestamp" + FROM evm.block + ORDER BY block."timestamp" DESC + LIMIT 100) subquery_alias) evm_block + CROSS JOIN LATERAL ( + SELECT sum(jsonb_array_length(block.transactions)) AS total_transaction_count + FROM evm.block + WHERE (block."timestamp" >= (now() - '24:00:00'::interval))) daily_transactions) + CROSS JOIN LATERAL ( + WITH subquery AS( + SELECT array_to_string(array_agg(evm.block.number), ',') AS blocks , + sum(jsonb_array_length(evm.block.transactions)) AS total_transaction_count, + sum(evm.block.gas_used) AS gas_used_sum + FROM evm.block + GROUP BY timestamp) + SELECT blocks, max_transaction_sum, gas_used_sum + FROM ( SELECT max(subquery.total_transaction_count) AS max_transaction_sum + FROM subquery) q1 + INNER JOIN subquery q2 ON q1.max_transaction_sum = q2.total_transaction_count + LIMIT 1) ath_last_year)); diff --git a/kubernetes-evm/hapi-evm-deployment.yaml b/kubernetes-evm/hapi-evm-deployment.yaml new file mode 100644 index 00000000..d5af5007 --- /dev/null +++ b/kubernetes-evm/hapi-evm-deployment.yaml @@ -0,0 +1,29 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: dashboard-hapi-evm + name: dashboard-hapi-evm +spec: + replicas: 1 + selector: + matchLabels: + app: dashboard-hapi-evm + strategy: + type: Recreate + template: + metadata: + labels: + app: dashboard-hapi-evm + spec: + imagePullSecrets: + - name: regcred + containers: + - image: ${DOCKER_REGISTRY}/${IMAGE_NAME_HAPI_EVM}:${VERSION} + imagePullPolicy: "Always" + name: "dashboard-hapi-evm" + envFrom: + - configMapRef: + name: dashboard-hapi-evm-config + ports: + - containerPort: 9090 diff --git a/kubernetes-evm/hapi-evm-service.yaml b/kubernetes-evm/hapi-evm-service.yaml new file mode 100644 index 00000000..88c28f79 --- /dev/null +++ b/kubernetes-evm/hapi-evm-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: dashboard-hapi-evm + name: dashboard-hapi-evm +spec: + ports: + - name: hapi + port: 9091 + targetPort: 9090 + selector: + app: dashboard-hapi-evm diff --git a/kubernetes/configmap-dashboard.yaml b/kubernetes/configmap-dashboard.yaml index e6149c69..639c4e07 100644 --- a/kubernetes/configmap-dashboard.yaml +++ b/kubernetes/configmap-dashboard.yaml @@ -33,6 +33,9 @@ data: REACT_APP_STATE_HISTORY_ENABLED: '${REACT_APP_STATE_HISTORY_ENABLED}' REACT_APP_GOOGLE_ANALITIC_PAGE_ID: '${REACT_APP_GOOGLE_ANALITIC_PAGE_ID}' REACT_APP_PUBLIC_RE_CAPTCHA_KEY: '${REACT_APP_PUBLIC_RE_CAPTCHA_KEY}' + REACT_APP_EVM_ENDPOINT: '${REACT_APP_EVM_ENDPOINT}' + REACT_APP_EVM_BLOCK_EXPLORER_URL: '${REACT_APP_EVM_BLOCK_EXPLORER_URL}' + REACT_APP_EVM_ENDPOINTS: '${REACT_APP_EVM_ENDPOINTS}' --- apiVersion: v1 kind: ConfigMap @@ -103,6 +106,30 @@ data: --- apiVersion: v1 kind: ConfigMap +metadata: + name: dashboard-hapi-evm-config +data: + # hapi-evm + HAPI_EVM_SERVER_PORT: '${HAPI_EVM_SERVER_PORT}' + HAPI_EVM_SERVER_ADDRESS: '${HAPI_EVM_SERVER_ADDRESS}' + HAPI_EVM_HASURA_URL: '${HAPI_EVM_HASURA_URL}' + HAPI_EVM_HASURA_ADMIN_SECRET: '${HAPI_EVM_HASURA_ADMIN_SECRET}' + HAPI_EVM_DATABASE_URL: '${HAPI_EVM_DATABASE_URL}' + HAPI_EVM_ENDPOINT: '${HAPI_EVM_ENDPOINT}' + HAPI_EVM_API_ENDPOINTS: '${HAPI_EVM_API_ENDPOINTS}' + HAPI_EVM_NETWORK_CHAIN_ID: '${HAPI_EVM_NETWORK_CHAIN_ID}' + HAPI_EVM_EOS_EVM_ACCOUNT: '${HAPI_EVM_EOS_EVM_ACCOUNT}' + HAPI_EVM_BLOCK_INTERVAL_SEC: '${HAPI_EVM_BLOCK_INTERVAL_SEC}' + HAPI_EVM_OLD_BLOCK_INTERVAL_SEC: '${HAPI_EVM_OLD_BLOCK_INTERVAL_SEC}' + HAPI_EVM_ATH_INTERVAL_SEC: '${HAPI_EVM_ATH_INTERVAL_SEC}' + HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC: '${HAPI_EVM_CLEAN_OLD_BLOCK_INTERVAL_SEC}' + HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC: '${HAPI_EVM_CLEAN_OLD_TRANSFER_INTERVAL_SEC}' + HAPI_EVM_KEEP_HISTORY_FOR_YEARS: '${HAPI_EVM_KEEP_HISTORY_FOR_YEARS}' + HAPI_EVM_HYPERION_API: '${HAPI_EVM_HYPERION_API}' + HAPI_EVM_HYPERION_START_AT: '${HAPI_EVM_HYPERION_START_AT}' +--- +apiVersion: v1 +kind: ConfigMap metadata: name: dashboard-hasura-config data: @@ -112,3 +139,4 @@ data: HASURA_GRAPHQL_ADMIN_SECRET: '${HASURA_GRAPHQL_ADMIN_SECRET}' HASURA_GRAPHQL_UNAUTHORIZED_ROLE: '${HASURA_GRAPHQL_UNAUTHORIZED_ROLE}' HASURA_GRAPHQL_ACTION_BASE_URL: '${HASURA_GRAPHQL_ACTION_BASE_URL}' + HASURA_GRAPHQL_ACTION_EVM_URL: '${HASURA_GRAPHQL_ACTION_EVM_URL}' diff --git a/makefile b/makefile index 17d391f3..eea8370d 100644 --- a/makefile +++ b/makefile @@ -10,6 +10,7 @@ RESET := $(shell tput -Txterm sgr0) K8S_BUILD_DIR ?= ./build_k8s K8S_FILES := $(shell find ./kubernetes -name '*.yaml' | sed 's:./kubernetes/::g') +K8S_FILES_EVM := $(shell find ./kubernetes-evm -name '*.yaml' | sed 's:./kubernetes-evm/::g') run: @echo "$(BLUE)running action $(filter-out $@,$(MAKECMDGOALS))$(RESET)" @@ -20,6 +21,7 @@ clean: @docker-compose stop @rm -rf tmp/postgres @rm -rf tmp/hapi + @rm -rf tmp/hapi-evm @rm -rf tmp/webapp @docker system prune @@ -100,6 +102,7 @@ start: make start-postgres make start-wallet make start-hapi + # make start-hapi-evm make start-hasura make -j 3 start-hasura-cli start-logs start-webapp @@ -112,6 +115,9 @@ start-wallet: start-hapi: @docker-compose up -d --build hapi +start-hapi-evm: + @docker-compose up -d --build hapi-evm + start-hasura: $(eval -include .env) @until \ @@ -122,6 +128,10 @@ start-hasura: curl http://localhost:9090/healthz; \ do echo "$(BLUE)$(STAGE)-$(APP_NAME)-hasura |$(RESET) waiting for hapi service"; \ sleep 5; done; + @until \ + curl http://localhost:9091/healthz; \ + do echo "$(BLUE)$(STAGE)-$(APP_NAME)-hasura |$(RESET) waiting for hapi-evm service"; \ + sleep 5; done; @echo "..." @docker-compose stop hasura @docker-compose up -d --build hasura @@ -145,7 +155,7 @@ start-webapp: @echo "done webapp" start-logs: - @docker-compose logs -f hapi webapp + @docker-compose logs -f hapi hapi-evm webapp build-kubernetes: ##@devops Generate proper k8s files based on the templates build-kubernetes: ./kubernetes @@ -156,6 +166,15 @@ build-kubernetes: ./kubernetes $(SHELL_EXPORT) envsubst <./kubernetes/$$file >$(K8S_BUILD_DIR)/$$file; \ done +build-kubernetes-evm: ##@devops Generate proper k8s files based on the templates for evm +build-kubernetes-evm: ./kubernetes-evm + @echo "Build kubernetes files for evm..." + @mkdir -p $(K8S_BUILD_DIR) + @for file in $(K8S_FILES_EVM); do \ + mkdir -p `dirname "$(K8S_BUILD_DIR)/$$file"`; \ + $(SHELL_EXPORT) envsubst <./kubernetes-evm/$$file >$(K8S_BUILD_DIR)/$$file; \ + done + deploy-kubernetes: ##@devops Publish the build k8s files deploy-kubernetes: $(K8S_BUILD_DIR) @kubectl create ns $(NAMESPACE) || echo "Namespace '$(NAMESPACE)' already exists."; diff --git a/utils/meta.mk b/utils/meta.mk index 9f9f4e92..ca022414 100644 --- a/utils/meta.mk +++ b/utils/meta.mk @@ -4,13 +4,14 @@ VERSION ?= $(shell git rev-parse --short HEAD) IMAGE_NAME_WEBAPP=dashboard-webapp IMAGE_NAME_HAPI=dashboard-hapi +IMAGE_NAME_HAPI_EVM=dashboard-hapi-evm IMAGE_NAME_HASURA=dashboard-hasura IMAGE_NAME_WALLET=dashboard-wallet DOCKER_REGISTRY=ghcr.io/edenia -SUBDIRS = webapp hapi hasura wallet +SUBDIRS = webapp hapi hasura wallet hapi-evm -MAKE_ENV += DOCKER_REGISTRY VERSION IMAGE_NAME_WEBAPP IMAGE_NAME_HAPI IMAGE_NAME_WALLET IMAGE_NAME_HASURA +MAKE_ENV += DOCKER_REGISTRY VERSION IMAGE_NAME_WEBAPP IMAGE_NAME_HAPI IMAGE_NAME_HAPI_EVM IMAGE_NAME_WALLET IMAGE_NAME_HASURA SHELL_EXPORT := $(foreach v,$(MAKE_ENV),$(v)='$($(v))') diff --git a/webapp/Dockerfile b/webapp/Dockerfile index d9f910d9..2cd29ede 100644 --- a/webapp/Dockerfile +++ b/webapp/Dockerfile @@ -29,6 +29,9 @@ ARG react_app_state_history_enabled ARG react_app_google_analitic_page_id ARG react_app_public_re_captcha_key ARG react_app_sync_tolerance_interval +ARG react_app_evm_endpoint +ARG react_app_evm_block_explorer_url +ARG react_app_evm_endpoints ENV WORK_DIR /usr/src/app ENV PATH $WORK_DIR/node_modules/.bin:$PATH @@ -62,6 +65,9 @@ ENV REACT_APP_STATE_HISTORY_ENABLED $react_app_state_history_enabled ENV REACT_APP_GOOGLE_ANALITIC_PAGE_ID $react_app_google_analitic_page_id ENV REACT_APP_PUBLIC_RE_CAPTCHA_KEY $react_app_public_re_captcha_key ENV REACT_APP_SYNC_TOLERANCE_INTERVAL $react_app_sync_tolerance_interval +ENV REACT_APP_EVM_ENDPOINT $react_app_evm_endpoint +ENV REACT_APP_EVM_BLOCK_EXPLORER_URL $react_app_evm_block_explorer_url +ENV REACT_APP_EVM_ENDPOINTS $react_app_evm_endpoints RUN mkdir -p $WORK_DIR WORKDIR $WORK_DIR diff --git a/webapp/makefile b/webapp/makefile index 64d0aded..57fa6142 100644 --- a/webapp/makefile +++ b/webapp/makefile @@ -51,6 +51,9 @@ build-docker: ./Dockerfile --build-arg react_app_google_analitic_page_id='$(REACT_APP_GOOGLE_ANALITIC_PAGE_ID)' \ --build-arg react_app_public_re_captcha_key='$(REACT_APP_PUBLIC_RE_CAPTCHA_KEY)' \ --build-arg react_app_sync_tolerance_interval='$(REACT_APP_SYNC_TOLERANCE_INTERVAL)' \ + --build-arg react_app_evm_endpoint='$(REACT_APP_EVM_ENDPOINT)' \ + --build-arg react_app_evm_block_explorer_url='$(REACT_APP_EVM_BLOCK_EXPLORER_URL)' \ + --build-arg react_app_evm_endpoints='$(REACT_APP_EVM_ENDPOINTS)' \ . pull-image: ##@devops Pull the latest image from registry for caching diff --git a/webapp/src/components/EndpointsTable/index.js b/webapp/src/components/EndpointsTable/index.js index 073db483..1fa71123 100644 --- a/webapp/src/components/EndpointsTable/index.js +++ b/webapp/src/components/EndpointsTable/index.js @@ -18,7 +18,7 @@ import QueryStatsIcon from '@mui/icons-material/QueryStats' import HealthCheck from '../HealthCheck' import HealthCheckInfo from 'components/HealthCheck/HealthCheckInfo' -import { eosConfig } from '../../config' +import { getStatus } from 'utils' import styles from './styles' import Tooltip from '../Tooltip' @@ -41,33 +41,6 @@ const EndpointsTable = ({ producers }) => { setAnchorEl(null) } - const syncToleranceInterval = eosConfig.syncToleranceInterval - - const isSynchronized = endpoint => { - const diffBlockTimems = - new Date(endpoint.updated_at) - new Date(endpoint.head_block_time) - - return diffBlockTimems <= syncToleranceInterval - } - - const getStatus = endpoint => { - if (endpoint.response.status === undefined) return - - if (endpoint.response?.isWorking) { - return !endpoint.head_block_time || isSynchronized(endpoint) - ? 'greenLight' - : 'timerOff' - } - - switch (Math.floor(endpoint.response?.status / 100)) { - case 4: - case 5: - return 'yellowLight' - default: - return 'redLight' - } - } - const CellList = ({ producer, endpointType }) => { return ( diff --git a/webapp/src/components/GeoMap/MainMap.js b/webapp/src/components/GeoMap/MainMap.js index ed6c56a8..45508c1a 100644 --- a/webapp/src/components/GeoMap/MainMap.js +++ b/webapp/src/components/GeoMap/MainMap.js @@ -2,6 +2,7 @@ import React, { useEffect, useRef, useCallback } from 'react' import { makeStyles } from '@mui/styles' import { useTranslation } from 'react-i18next' import PropTypes from 'prop-types' +import { useTheme } from '@mui/material/styles' import { countries } from '../../utils/countries' @@ -14,6 +15,7 @@ const MainMap = ({ data, map, setMap }) => { const classes = useStyles() const { t } = useTranslation('mainMapComponent') const myRef = useRef() + const theme = useTheme() const setupMapData = useCallback( (data = [], map) => { @@ -61,7 +63,7 @@ const MainMap = ({ data, map, setMap }) => { }, states: { hover: { - color: '#1565C0', + color: theme.palette.primary.main, }, }, dataLabels: { @@ -84,7 +86,7 @@ const MainMap = ({ data, map, setMap }) => { new HighMapsWrapper['Map'](myRef.current, options) }, - [setMap, t], + [setMap, t, theme.palette], ) useEffect(() => { diff --git a/webapp/src/components/HealthCheck/InfoModal.js b/webapp/src/components/HealthCheck/InfoModal.js index a5edd184..d9aecc88 100644 --- a/webapp/src/components/HealthCheck/InfoModal.js +++ b/webapp/src/components/HealthCheck/InfoModal.js @@ -34,6 +34,7 @@ const InfoModal = ({ lights = defaultLights }) => { return (

{t('help')}

+ {t('helpText')} {lights && Object.keys(lights).map((light, index) => (
diff --git a/webapp/src/components/HealthCheck/LightIcon.js b/webapp/src/components/HealthCheck/LightIcon.js index b3c6f014..ea7996d7 100644 --- a/webapp/src/components/HealthCheck/LightIcon.js +++ b/webapp/src/components/HealthCheck/LightIcon.js @@ -5,19 +5,22 @@ import DoneOutlinedIcon from '@mui/icons-material/DoneOutlined' import TimerOffOutlinedIcon from '@mui/icons-material/TimerOffOutlined' import ReportProblemOutlinedIcon from '@mui/icons-material/ReportProblemOutlined' +import { generalConfig } from '../../config' + import styles from './styles' const useStyles = makeStyles(styles) const LightIcon = ({ status }) => { const classes = useStyles() + const { healthLights } = generalConfig switch (status) { - case 'greenLight': + case healthLights.greenLight: return - case 'timerOff': + case healthLights.timerOff: return - case 'yellowLight': + case healthLights.yellowLight: return default: return diff --git a/webapp/src/components/HealthCheck/styles.js b/webapp/src/components/HealthCheck/styles.js index 1b0b2af9..d4ca30e8 100644 --- a/webapp/src/components/HealthCheck/styles.js +++ b/webapp/src/components/HealthCheck/styles.js @@ -24,8 +24,8 @@ export default (theme) => ({ marginBlock: '2px', }, helpIcon: { - width: '15px !important', - height: '15px !important', + width: '18px !important', + height: '18px !important', cursor: 'pointer', }, greenLight: { diff --git a/webapp/src/components/NodeCard/EndpointsChips.js b/webapp/src/components/NodeCard/EndpointsChips.js index 0cf7ff39..8c8e1cfd 100644 --- a/webapp/src/components/NodeCard/EndpointsChips.js +++ b/webapp/src/components/NodeCard/EndpointsChips.js @@ -6,6 +6,7 @@ import moment from 'moment' import ChipList from '../ChipList' import HealthCheck from '../HealthCheck' +import { generalConfig } from '../../config' import styles from './styles' @@ -14,25 +15,26 @@ const useStyles = makeStyles(styles) const EndpointsChips = ({ node }) => { const classes = useStyles() const { t } = useTranslation('nodeCardComponent') + const { healthLights } = generalConfig if (!node?.endpoints?.length) return <> const getHealthStatus = (totalEndpoints, workingEndpoints) => { switch (workingEndpoints) { case totalEndpoints: - return 'greenLight' + return healthLights.greenLight case 0: - return 'redLight' + return healthLights.redLight default: - return 'yellowLight' + return healthLights.yellowLight } } const getStatusMessage = (healthStatus, failingEndpoints) => { switch (healthStatus) { - case 'greenLight': + case healthLights.greenLight: return t('allWorking') - case 'redLight': + case healthLights.redLight: return t('noneWorking') default: const beginning = diff --git a/webapp/src/components/NodesSummary/index.js b/webapp/src/components/NodesSummary/index.js index 497ad28a..641d14fc 100644 --- a/webapp/src/components/NodesSummary/index.js +++ b/webapp/src/components/NodesSummary/index.js @@ -1,8 +1,6 @@ /* eslint camelcase: 0 */ import React, { memo, useEffect, useState } from 'react' import PropTypes from 'prop-types' -import Typography from '@mui/material/Typography' -import LinearProgress from '@mui/material/LinearProgress' import { useQuery } from '@apollo/client' import { useTranslation } from 'react-i18next' @@ -27,26 +25,6 @@ const NODES_ORDER = [ }, ] -const BodyGraphValue = ({ loading, value }) => { - if (loading) return - - return ( - - {value} - - ) -} - -BodyGraphValue.propTypes = { - loading: PropTypes.bool, - value: PropTypes.number, -} - -BodyGraphValue.defaultProps = { - value: 0, - loading: false, -} - const NodesSummary = ({ t }) => { const { data, loading } = useQuery(NODES_SUMMARY_QUERY) const { i18n } = useTranslation('translations') @@ -93,20 +71,23 @@ const NodesSummary = ({ t }) => { return ( <> - - {`${t('total')} ${t('nodes')}`} - - - + {nodes && nodes.map((node) => ( - - - {currentLanguaje === 'es' ? t('nodes') : ''} {t(node.type)}{' '} - {currentLanguaje !== 'es' ? t('nodes') : ''} - - - + ))} ) diff --git a/webapp/src/components/NonCompliantCard/index.js b/webapp/src/components/NonCompliantCard/index.js index 87b99665..5eabd27e 100644 --- a/webapp/src/components/NonCompliantCard/index.js +++ b/webapp/src/components/NonCompliantCard/index.js @@ -7,7 +7,7 @@ import Link from '@mui/material/Link' import Typography from '@mui/material/Typography' import moment from 'moment' -import { eosConfig } from '../../config' +import { eosConfig, generalConfig } from '../../config' import { formatWithThousandSeparator } from '../../utils' import HealthCheck from '../HealthCheck' import HealthCheckInfo from 'components/HealthCheck/HealthCheckInfo' @@ -21,9 +21,10 @@ const useStyles = makeStyles(styles) const NonCompliantCard = ({ producer, stats }) => { const classes = useStyles() const { t } = useTranslation('producerCardComponent') + const { healthLights } = generalConfig - const getHealthStatus = (healthCheck) => { - return healthCheck.valid ? 'greenLight' : 'redLight' + const getHealthStatus = healthCheck => { + return healthCheck.valid ? healthLights.greenLight : healthLights.redLight } const RowInfo = ({ title, value }) => { diff --git a/webapp/src/routes/Home/EqualIcon.js b/webapp/src/components/PauseButton/EqualIcon.js similarity index 100% rename from webapp/src/routes/Home/EqualIcon.js rename to webapp/src/components/PauseButton/EqualIcon.js diff --git a/webapp/src/components/PauseButton/index.js b/webapp/src/components/PauseButton/index.js new file mode 100644 index 00000000..c379b511 --- /dev/null +++ b/webapp/src/components/PauseButton/index.js @@ -0,0 +1,54 @@ +/* eslint camelcase: 0 */ +import React from 'react' +import { makeStyles } from '@mui/styles' +import { useTheme } from '@mui/material/styles' +import { useTranslation } from 'react-i18next' +import clsx from 'clsx' +import PropTypes from 'prop-types' +import Typography from '@mui/material/Typography' +import PlayArrowIcon from '@mui/icons-material/PlayArrow' + +import styles from './styles' +import EqualIcon from './EqualIcon' + +const useStyles = makeStyles(styles) + +const PauseButton = ({ isPaused, handlePause, isEnabled }) => { + const { t } = useTranslation('homeRoute') + const classes = useStyles() + const theme = useTheme() + + return ( + <> +
+ {isPaused ? ( + + ) : ( + + )} + {isPaused ? t('play') : t('pause')} +
+ + ) +} + +PauseButton.propTypes = { + isPaused: PropTypes.bool, + isEnabled: PropTypes.bool, + handlePause: PropTypes.func, +} + +export default PauseButton diff --git a/webapp/src/components/PauseButton/styles.js b/webapp/src/components/PauseButton/styles.js new file mode 100644 index 00000000..5738cf6d --- /dev/null +++ b/webapp/src/components/PauseButton/styles.js @@ -0,0 +1,13 @@ +export default (theme) => ({ + pauseButton: { + display: 'flex', + width: 75, + height: 24, + '&:hover': { + cursor: 'pointer', + }, + }, + disableButton: { + color: theme.palette.action.disabled, + }, +}) diff --git a/webapp/src/components/ProducersSummary/index.js b/webapp/src/components/ProducersSummary/index.js index c2976e17..eef1d4d1 100644 --- a/webapp/src/components/ProducersSummary/index.js +++ b/webapp/src/components/ProducersSummary/index.js @@ -1,33 +1,11 @@ /* eslint camelcase: 0 */ import React, { memo, useEffect, useState } from 'react' import PropTypes from 'prop-types' -import Typography from '@mui/material/Typography' -import LinearProgress from '@mui/material/LinearProgress' import { ENTITY_TYPE } from '../../utils/lacchain' import { eosConfig } from '../../config' import SimpleDataCard from '../SimpleDataCard' -const BodyGraphValue = ({ loading, value }) => { - if (loading) return - - return ( - - {value} - - ) -} - -BodyGraphValue.propTypes = { - loading: PropTypes.bool, - value: PropTypes.number, -} - -BodyGraphValue.defaultProps = { - value: 0, - loading: false, -} - const ProducersSummary = ({ t, data, loading, total }) => { const [nodes, setNodes] = useState([]) @@ -54,16 +32,18 @@ const ProducersSummary = ({ t, data, loading, total }) => { return ( <> - - {`${t('total')} ${t('producers')}`} - - - + {nodes.map((node, index) => ( - - {`${t(node.type)} ${t('producers')}`} - - + ))} ) diff --git a/webapp/src/components/Sidebar/SidebarCategory.js b/webapp/src/components/Sidebar/SidebarCategory.js index a14a3607..923c72b3 100644 --- a/webapp/src/components/Sidebar/SidebarCategory.js +++ b/webapp/src/components/Sidebar/SidebarCategory.js @@ -39,7 +39,7 @@ const SidebarCategory = ({ showOnlyIcons, ...rest }) => { - if (showOnlyIcons) return {icon} + if (showOnlyIcons) return {icon} return ( diff --git a/webapp/src/components/SimpleDataCard/BodyGraphValue.js b/webapp/src/components/SimpleDataCard/BodyGraphValue.js new file mode 100644 index 00000000..be9ac9b2 --- /dev/null +++ b/webapp/src/components/SimpleDataCard/BodyGraphValue.js @@ -0,0 +1,43 @@ +import React from 'react' +import { makeStyles } from '@mui/styles' +import PropTypes from 'prop-types' +import LinearProgress from '@mui/material/LinearProgress' +import LaunchIcon from '@mui/icons-material/Launch' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const BodyGraphValue = ({ loading, links }) => { + const classes = useStyles() + + if (loading) return + + return ( + <> + {links && + links.map((href, index) => ( + + + + ))} + + ) +} + +BodyGraphValue.propTypes = { + loading: PropTypes.bool, + href: PropTypes.string, +} + +BodyGraphValue.defaultProps = { + loading: false, +} + +export default BodyGraphValue diff --git a/webapp/src/components/SimpleDataCard/index.js b/webapp/src/components/SimpleDataCard/index.js index f7b92566..1207b73a 100644 --- a/webapp/src/components/SimpleDataCard/index.js +++ b/webapp/src/components/SimpleDataCard/index.js @@ -1,20 +1,44 @@ -import React from 'react' +import React, { memo } from 'react' import { makeStyles } from '@mui/styles' import PropTypes from 'prop-types' import Card from '@mui/material/Card' import CardContent from '@mui/material/CardContent' +import Typography from '@mui/material/Typography' +import LinearProgress from '@mui/material/LinearProgress' import styles from './styles' const useStyles = makeStyles(styles) -const SimpleDataCard = ({ header, children }) => { +const SimpleDataCard = ({ + header, + lowercase, + title, + value, + loading, + children, +}) => { const classes = useStyles() + const isNotLoading = !loading || !!value?.toString() return ( -
+
- {children} + + {title && {title}} + {isNotLoading ? ( + + {value} + {children} + + ) : ( + + )} +
) @@ -22,11 +46,19 @@ const SimpleDataCard = ({ header, children }) => { SimpleDataCard.propTypes = { header: PropTypes.bool, + lowercase: PropTypes.bool, + loading: PropTypes.bool, + title: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), children: PropTypes.node, } SimpleDataCard.defaultProps = { header: false, + loading: false, + lowercase: false, + title: '', + value: '', } -export default SimpleDataCard +export default memo(SimpleDataCard) diff --git a/webapp/src/components/SimpleDataCard/styles.js b/webapp/src/components/SimpleDataCard/styles.js index f3211a2f..bbef27af 100644 --- a/webapp/src/components/SimpleDataCard/styles.js +++ b/webapp/src/components/SimpleDataCard/styles.js @@ -33,4 +33,11 @@ export default (theme) => ({ height: '100%', }, }, + lowercase: { + textTransform: 'lowercase !important', + }, + svgLink: { + fontSize: 18, + marginLeft: theme.spacing(2), + }, }) diff --git a/webapp/src/components/TransactionsChartContainer/index.js b/webapp/src/components/TransactionsChartContainer/index.js new file mode 100644 index 00000000..d17d8362 --- /dev/null +++ b/webapp/src/components/TransactionsChartContainer/index.js @@ -0,0 +1,143 @@ +import React from 'react' +import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import Card from '@mui/material/Card' +import CardContent from '@mui/material/CardContent' +import PropTypes from 'prop-types' +import Select from '@mui/material/Select' +import MenuItem from '@mui/material/MenuItem' +import FormControl from '@mui/material/FormControl' +import InputLabel from '@mui/material/InputLabel' +import Typography from '@mui/material/Typography' +import LinearProgress from '@mui/material/LinearProgress' + +import PauseButton from '../../components/PauseButton' +import TransactionsLineChart from '../../components/TransactionsLineChart' + +import styles from './styles' + +const useStyles = makeStyles(styles) + +const TransactionsChartContainer = ({ + title, + ariaLabel, + loading, + data, + isPaused, + handlePause, + chartLabelFormat, + historyState +}) => { + const classes = useStyles() + const { t } = useTranslation() + + return ( + + +
+ + {title} + +
+ + {historyState?.isHistoryEnabled && ( + <> + {t('timeFrame')} + + + )} + + {handlePause && ( + + )} +
+
+ {loading && } + +
+
+ ) +} + +TransactionsChartContainer.propTypes = { + ariaLabel: PropTypes.string, + title: PropTypes.string, + loading: PropTypes.bool, + isPaused: PropTypes.bool, + data: PropTypes.array, + handlePause: PropTypes.func, + chartLabelFormat: PropTypes.shape({ + yAxisText: PropTypes.string, + shared: PropTypes.bool, + blockTime: PropTypes.number, + customFormatter: PropTypes.func, + }), + historyState: PropTypes.shape({ + value: PropTypes.string, + options: PropTypes.array, + isLive: PropTypes.bool, + isHistoryEnabled: PropTypes.bool, + onSelect: PropTypes.func, + }) +} + +TransactionsChartContainer.defaultProps = { + title: '', + ariaLabel: '', + loading: false, + isPaused: false, + handlePause: undefined, +} + +export default TransactionsChartContainer diff --git a/webapp/src/components/TransactionsChartContainer/styles.js b/webapp/src/components/TransactionsChartContainer/styles.js new file mode 100644 index 00000000..88c3f6a2 --- /dev/null +++ b/webapp/src/components/TransactionsChartContainer/styles.js @@ -0,0 +1,33 @@ +export default (theme) => ({ + headerTransactionLine: { + display: 'flex', + justifyContent: 'space-between', + flexDirection: 'column', + alignItems: 'baseline', + padding: theme.spacing(1), + [theme.breakpoints.up('lg')]: { + justifyContent: 'space-between', + alignItems: 'center', + flexDirection: 'row', + }, + }, + formControl: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + width: '100%', + '& .MuiFormControl-root': { + width: 200, + }, + '& .MuiInputLabel-formControl': { + position: 'relative', + marginBottom: `-${theme.spacing(2)}`, + }, + [theme.breakpoints.up('lg')]: { + width: 300, + }, + }, + cardShadow: { + boxShadow: '0px 1px 3px 1px rgba(0, 0, 0, 0.15) !important', + }, +}) diff --git a/webapp/src/components/TransactionsHistory/index.js b/webapp/src/components/TransactionsHistory/index.js index fba5e5e4..26a18976 100644 --- a/webapp/src/components/TransactionsHistory/index.js +++ b/webapp/src/components/TransactionsHistory/index.js @@ -2,9 +2,6 @@ import React, { memo } from 'react' import { makeStyles } from '@mui/styles' import PropTypes from 'prop-types' -import Typography from '@mui/material/Typography' -import LinearProgress from '@mui/material/LinearProgress' -import LaunchIcon from '@mui/icons-material/Launch' import { useSubscription } from '@apollo/client' import { BLOCK_TRANSACTIONS_HISTORY } from '../../gql' @@ -12,39 +9,12 @@ import { useSharedState } from '../../context/state.context' import { formatWithThousandSeparator, getBlockNumUrl } from '../../utils' import { generalConfig } from '../../config' import SimpleDataCard from '../SimpleDataCard' +import BodyGraphValue from '../SimpleDataCard/BodyGraphValue' import styles from './styles' const useStyles = makeStyles(styles) -const BodyGraphValue = ({ loading, value, classes, links }) => { - if (loading) return - - return ( - - {value} - {links && links.map((href, index) => ( - - - - ))} - - ) -} - -BodyGraphValue.propTypes = { - loading: PropTypes.bool, - value: PropTypes.any, - classes: PropTypes.object, - href: PropTypes.string, -} - -BodyGraphValue.defaultProps = { - value: 0, - loading: false, - classes: {}, -} - const TransactionsHistory = ({ t, nodesChildren }) => { const classes = useStyles() const [{ info, tps }] = useSharedState() @@ -54,169 +24,144 @@ const TransactionsHistory = ({ t, nodesChildren }) => {
{generalConfig.historyEnabled && ( <> - - {t('tpsAllTimeHigh')} - getBlockNumUrl(block))} - /> - - - {t('cpuUtilizationAllTimeHigh')} + getBlockNumUrl(block))} - loading={loading} - /> - - - {t('networkUtilizationAllTimeHigh')} - getBlockNumUrl(block))} - loading={loading} - /> - - - {`${t('transactions')} ${t('lastHour')}`} - + getBlockNumUrl(block), )} - loading={loading} /> - - {`${t('transactions')} ${t('lastDay')}`} + + getBlockNumUrl(block), )} - loading={loading} /> - - {`${t('transactions')} ${t( - 'dailyAverage', - )}`} + + getBlockNumUrl(block), )} - loading={loading} - /> - - - {`${t('transactions')} ${t('lastWeek')}`} - - - - {`${t('cpuUtilization')} ${t('lastHour')}`} - - - - {`${t('cpuUtilization')} ${t('lastDay')}`} - - - - {`${t('cpuUtilization')} ${t('lastWeek')}`} - - - - {`${t('netUtilization')} ${t('lastHour')}`} - - - - {`${t('netUtilization')} ${t('lastDay')}`} - - - - {`${t('netUtilization')} ${t('lastWeek')}`} - + + + + + + + + + + )} {nodesChildren && ( <> {nodesChildren} - - {`${t('uniqueLocations')}`} - - + )} - - {t('cpuUsage')} - - {`${formatWithThousandSeparator(tps[0]?.cpu, 2)} %`} - - - - - {t('netUsage')} - - {`${formatWithThousandSeparator(tps[0]?.net, 3)} %`} - - - - - {t('cpuLimitPerBlock')} - - {`${(info.block_cpu_limit * 0.001).toFixed(0)} ms`} - - - - {t('netLimitPerBlock')} - - {`${formatWithThousandSeparator(info.block_net_limit / 1024, 0)} KB`} - - - - {t('chainCpuLimit')} - - {`${(info.virtual_block_cpu_limit * 0.001).toFixed(0)} ms`} - - - - {t('chainNetLimit')} - - {`${formatWithThousandSeparator( - info.virtual_block_net_limit / 1024, - 0, - )} KB`} - - + + + + + +
) } diff --git a/webapp/src/components/TransactionsHistory/styles.js b/webapp/src/components/TransactionsHistory/styles.js index 67153c56..67db383b 100644 --- a/webapp/src/components/TransactionsHistory/styles.js +++ b/webapp/src/components/TransactionsHistory/styles.js @@ -1,11 +1,4 @@ export default (theme) => ({ - svgLink: { - fontSize: 18, - marginLeft: theme.spacing(2), - }, - lowercase: { - textTransform: 'lowercase !important', - }, wrapper: { display: 'flex', gap: '10px', diff --git a/webapp/src/components/TransactionsLineChart/index.js b/webapp/src/components/TransactionsLineChart/index.js index 59190e44..26794701 100644 --- a/webapp/src/components/TransactionsLineChart/index.js +++ b/webapp/src/components/TransactionsLineChart/index.js @@ -3,7 +3,15 @@ import HighchartsReact from 'highcharts-react-official' import PropTypes from 'prop-types' import Highcharts from 'highcharts' -const TransactionsLineChart = ({ data, xAxisProps, title, yAxisProps, zoomEnabled }) => { +const TransactionsLineChart = ({ + data, + xAxisProps, + title, + yAxisProps, + zoomEnabled, + shared, + customFormatter +}) => { const options = { time: { timezoneOffset: new Date().getTimezoneOffset(), @@ -14,7 +22,7 @@ const TransactionsLineChart = ({ data, xAxisProps, title, yAxisProps, zoomEnable chart: { animation: false, type: 'spline', - zoomType: zoomEnabled ? 'x' : '' + zoomType: zoomEnabled ? 'x' : '', }, credits: { enabled: false, @@ -22,7 +30,8 @@ const TransactionsLineChart = ({ data, xAxisProps, title, yAxisProps, zoomEnable xAxis: xAxisProps, yAxis: yAxisProps, tooltip: { - pointFormat: '{series.name}: {point.y}
Net usage:{point.net} %
CPU usage:{point.cpu} %', + shared, + ...(customFormatter && { formatter() { return customFormatter(this) } }) }, } @@ -45,6 +54,8 @@ TransactionsLineChart.propTypes = { yAxisProps: PropTypes.object, title: PropTypes.string, zoomEnabled: PropTypes.bool, + shared: PropTypes.bool, + customFormatter: PropTypes.func } TransactionsLineChart.defaultProps = { @@ -53,6 +64,8 @@ TransactionsLineChart.defaultProps = { yAxisProps: {}, title: '', zoomEnabled: false, + shared: false, + customFormatter: undefined } export default TransactionsLineChart diff --git a/webapp/src/config/evm.config.js b/webapp/src/config/evm.config.js new file mode 100644 index 00000000..972b2fde --- /dev/null +++ b/webapp/src/config/evm.config.js @@ -0,0 +1,23 @@ +import { eosConfig } from 'config' + +let _avgBlockTime = 'N/A' + +switch (eosConfig.networkName) { + case 'telos-testnet': + case 'telos': + _avgBlockTime = 0.5 + break + case 'jungle': + case 'mainnet': + _avgBlockTime = 1 + break + default: + break +} + +export const avgBlockTime = _avgBlockTime +export const maxTPSDataSize = 30 / _avgBlockTime || 0 +export const account = 'eosio.evm' +export const endpoint = process.env.REACT_APP_EVM_ENDPOINT +export const blockExplorerUrl = process.env.REACT_APP_EVM_BLOCK_EXPLORER_URL +export const endpoints = JSON.parse(process.env.REACT_APP_EVM_ENDPOINTS || '[]') || [] diff --git a/webapp/src/config/general.js b/webapp/src/config/general.js index fbaba1e2..294cfe5b 100644 --- a/webapp/src/config/general.js +++ b/webapp/src/config/general.js @@ -22,3 +22,9 @@ export const historyEnabled = export const googleAnaliticPageId = process.env.REACT_APP_GOOGLE_ANALITIC_PAGE_ID export const highchartsMapURL = 'https://code.highcharts.com/mapdata/countries/' +export const healthLights = Object.freeze({ + greenLight: 'greenLight', + timerOff: 'timerOff', + yellowLight: 'yellowLight', + redLight: 'redLight', +}) diff --git a/webapp/src/config/index.js b/webapp/src/config/index.js index bc65a418..826f9b68 100644 --- a/webapp/src/config/index.js +++ b/webapp/src/config/index.js @@ -1,7 +1,8 @@ import * as eosConfig from './eos.config' +import * as evmConfig from './evm.config' import * as generalConfig from './general' import { ualConfig } from './ual.config' import * as recaptchaConfig from './recaptcha.config' -export { eosConfig, generalConfig, ualConfig, recaptchaConfig } +export { eosConfig, evmConfig, generalConfig, ualConfig, recaptchaConfig } export * from './graphql.config' diff --git a/webapp/src/context/state.context.js b/webapp/src/context/state.context.js index 256aac63..226e4268 100644 --- a/webapp/src/context/state.context.js +++ b/webapp/src/context/state.context.js @@ -1,4 +1,4 @@ -import React, { useEffect, useCallback } from 'react' +import React, { useEffect, useCallback, useRef } from 'react' import useLightUAL from '../hooks/useUAL' import { ualConfig } from '../config' @@ -155,9 +155,11 @@ export const useSharedState = () => { throw new Error(`useSharedState must be used within a SharedStateContext`) } + const lastBlock = useRef() + const infoInterval = useRef(null) + const [state, dispatch] = context const waitTrackingInterval = 30000 - let infoInterval let scheduleInterval let global @@ -268,7 +270,7 @@ export const useSharedState = () => { } const startTrackingInfo = async ({ interval = 1 } = {}) => { - if (infoInterval) return + if (infoInterval.current) return const handle = async () => { try { @@ -279,24 +281,31 @@ export const useSharedState = () => { payload: { ...info }, }) - await getBlock(info.head_block_num) + if (!lastBlock.current) { + lastBlock.current = info.head_block_num + } else { + lastBlock.current += 1 + } + + await getBlock(lastBlock.current) } catch (error) { console.error(error?.message || error) if (error?.message === ENDPOINTS_ERROR) { - clearInterval(infoInterval) + clearInterval(infoInterval.current) } } } - infoInterval = setInterval(handle, interval * 1000) + infoInterval.current = setInterval(handle, interval * 1000) } const stopTrackingInfo = () => { - if (!infoInterval) return + if (!infoInterval.current) return - clearInterval(infoInterval) - infoInterval = null + clearInterval(infoInterval.current) + infoInterval.current = null + lastBlock.current = null } const stopTrackingProducerSchedule = () => { diff --git a/webapp/src/gql/evm.gql.js b/webapp/src/gql/evm.gql.js new file mode 100644 index 00000000..f2372c8b --- /dev/null +++ b/webapp/src/gql/evm.gql.js @@ -0,0 +1,41 @@ +import gql from 'graphql-tag' + +export const EVM_STATS_SUBSCRIPTION = gql` + subscription { + evm_stats(limit: 1) { + avg_gas_used: block_gas_avg + daily_transaction_count + } + } +` + +export const EVM_HISTORICAL_STATS_SUBSCRIPTION = gql` + subscription { + evm_historical_stats{ + total_incoming_token + total_outgoing_token + total_transactions + tps_all_time_high + } + } +` + +export const EVM_TRANSACTION_QUERY = gql` + query ($range: String!) { + transactions: evm_transactions_history(range: $range) { + datetime + transactions_count + avg_gas_used + } + } +` + +export const EVM_TOKEN_QUERY = gql` + query ($range: String!) { + evm_token_history(range: $range) { + datetime + incoming + outgoing + } + } +` diff --git a/webapp/src/gql/index.js b/webapp/src/gql/index.js index 5cc41bf2..5a4709c8 100644 --- a/webapp/src/gql/index.js +++ b/webapp/src/gql/index.js @@ -2,3 +2,4 @@ export * from './producer.gql' export * from './setting.gql' export * from './transaction.gql' export * from './faucet.gql' +export * from './evm.gql' diff --git a/webapp/src/language/en.json b/webapp/src/language/en.json index 3de15202..1ae0c286 100644 --- a/webapp/src/language/en.json +++ b/webapp/src/language/en.json @@ -47,7 +47,8 @@ "options": "Options", "noOptions": "No matches", "updatedAt": "Updated at", - "nextUpdateAt": "Next updated at" + "nextUpdateAt": "Next update at", + "secondsAgo": "Seconds Ago" }, "routes": { "/>sidebar": "Dashboard", @@ -89,9 +90,15 @@ "/missed-blocks>sidebar": "Missed Blocks", "/missed-blocks>title": "Missed Blocks - EOSIO + Antelope Network Dashboard", "/missed-blocks>heading": "Missed Blocks", - "/stress-test>title": "Stress Test Dashboard", + "/stress-test>title": "Stress Test Dashboard - EOSIO + Antelope Network Dashboard", "/stress-test>sidebar": "Stress Test", "/stress-test>heading": "Stress Test", + "/evm>title": "EVM Dashboard - EOSIO + Antelope Network Dashboard", + "/evm>sidebar": "EVM Dashboard", + "/evm>heading": "EVM Dashboard", + "/evm-rpc-endpoints>title": "EVM RPC Endpoints - EOSIO + Antelope Network Dashboard", + "/evm-rpc-endpoints>sidebar": "EVM RPC Endpoints", + "/evm-rpc-endpoints>heading": "EVM RPC Endpoints", "/endpoints>sidebar": "API Endpoints", "/endpoints>title": "API Endpoints - EOSIO + Antelope Network Dashboard", "/endpoints>heading": "API Endpoints", @@ -135,7 +142,6 @@ "Last Week": "Last Week", "Last Year": "Last Year", "scheduleVersion": "Schedule Version", - "secondsAgo": "Seconds Ago", "tpsAllTimeHigh": "TPS All Time High", "cpuUtilization": "CPU Usage", "netUtilization": "NET Usage", @@ -158,7 +164,8 @@ "chainNetLimit": "Chain Net Limit", "timeToFinality": "Time to Finality", "cpuUsage": "CPU Usage", - "netUsage": "NET Usage" + "netUsage": "NET Usage", + "average": "Average" }, "blockProducersRoute": {}, "rewardsDistributionRoute": { @@ -194,14 +201,18 @@ "bpjsonInconsistency": "The bp.json on chain and of chain does not match, review it and make the necessary changes" }, "faucetRoute": { - "createAccount": "Create Faucet Account", - "newCreatedAccount": "Your new account is", - "transferTokensTransaction": "Tokens transferred correctly. Check it on explorer here", - "createButton": "Create", - "issueTokens": "Issue Tokens", - "getTokens": "Get Tokens", - "publicKey": "Public Key (Active/Owner)", - "accountName": "Account Name" + "createAccount": "Create Your Account", + "newCreatedAccount": "Congratulations! Your new account has been created:", + "transferTokensTransaction": "Tokens have been successfully transferred. View the transaction on the explorer:", + "createButton": "Create Your Account", + "issueTokens": "Distribute Tokens", + "getTokens": "Receive Tokens", + "publicKey": "Enter Public Key (Active/Owner)", + "accountName": "Choose an Account Name", + "invalidAccount": "Enter a valid account name, please.", + "emptyFields": "Complete all fields to proceed with account creation.", + "accountFormat": "Account name should be 12 characters or fewer. Use lowercase letters (a-z) and numbers (1-5) only.", + "keyFormat": "Enter a valid ECC key. You can generate one using cleos or any compatible wallet." }, "ricardianContractRoute": { "title": "Block Producer Agreement" @@ -401,7 +412,8 @@ "updated": "The endpoint is working", "outdated": "The endpoint works but is outdated with the last block", "error": "Error in the endpoint request", - "not working": "The endpoint is not responding" + "not working": "The endpoint is not responding", + "helpText": "Hover or click the icons to display the endpoint health status data" }, "copyToClipboardComponent": { "copy": "Click to copy", @@ -424,5 +436,27 @@ "charTitle": "Average Response Time from Costa Rica", "list": "List of endpoints", "timeInSecs": "Time in seconds" + }, + "evmDashboardRoute": { + "totalWallets": "Total wallets created", + "avgBlockTime": "Average block time", + "gasPrice": "Gas price", + "avgGasUsage": "Average gas usage", + "totalIncoming": "Total (TOKEN) incoming", + "totalOutgoing": "Total (TOKEN) outgoing", + "incoming": "Incoming", + "outgoing": "Outgoing", + "ATH": "TPS All Time High", + "lastBlock": "Last block", + "totalTxs": "Total EVM transactions", + "transactions": "EVM transactions", + "gasUsed": "Gas Used" + }, + "evmEndpointsRoute": { + "title": "EVM RPC endpoints list", + "rpcEndpoint": "RPC Endpoint", + "latency": "Latency", + "lastBlock": "Last block", + "rerun": "Re-run health checks" } } diff --git a/webapp/src/language/en.jungle.json b/webapp/src/language/en.jungle.json index e420fcc0..19755905 100644 --- a/webapp/src/language/en.jungle.json +++ b/webapp/src/language/en.jungle.json @@ -30,6 +30,7 @@ "/nodes-distribution>moreDescription": "A visualization of the geographic distribution of the nodes in this network.", "/accounts>moreDescription": "This tool helps find information about accounts and interact with contracts on the network. Enter an account name and obtain account information, smart contract actions, and table data.", "/block-distribution>moreDescription": "A visualization of the distribution of blocks produced by the nodes in the network.", - "/missed-blocks>moreDescription": "A list of scheduled, produced, and missed blocks by each account in the network." + "/missed-blocks>moreDescription": "A list of scheduled, produced, and missed blocks by each account in the network.", + "/evm>moreDescription": "Monitor EVM statistics, such as transaction amount history, gas price and total wallets created." } } diff --git a/webapp/src/language/en.mainnet.json b/webapp/src/language/en.mainnet.json index 38a32fb2..e978b1b8 100644 --- a/webapp/src/language/en.mainnet.json +++ b/webapp/src/language/en.mainnet.json @@ -29,6 +29,7 @@ "/nodes-distribution>moreDescription": "A visualization of the geographic distribution of the nodes in this network.", "/accounts>moreDescription": "This tool helps find information about accounts and interact with contracts on the network. Enter an account name and obtain account information, smart contract actions, and table data.", "/block-distribution>moreDescription": "A visualization of the distribution of blocks produced by the nodes in the network.", - "/missed-blocks>moreDescription": "A list of scheduled, produced, and missed blocks by each account in the network." + "/missed-blocks>moreDescription": "A list of scheduled, produced, and missed blocks by each account in the network.", + "/evm>moreDescription": "Monitor EVM statistics, such as transaction amount history, gas price and total wallets created." } } diff --git a/webapp/src/language/en.telos-testnet.json b/webapp/src/language/en.telos-testnet.json index 6f75f9cd..1b6b15ba 100644 --- a/webapp/src/language/en.telos-testnet.json +++ b/webapp/src/language/en.telos-testnet.json @@ -30,6 +30,9 @@ "/nodes-distribution>moreDescription": "A visualization of the geographic distribution of the nodes in this network.", "/accounts>moreDescription": "This tool helps find information about accounts and interact with contracts on the network. Enter an account name and obtain account information, smart contract actions, and table data.", "/block-distribution>moreDescription": "A visualization of the distribution of blocks produced by the nodes in the network.", - "/missed-blocks>moreDescription": "A list of scheduled, produced, and missed blocks by each account in the network." + "/missed-blocks>moreDescription": "A list of scheduled, produced, and missed blocks by each account in the network.", + "/evm>heading": "Telos EVM Dashboard", + "/evm>moreDescription": "Monitor Telos EVM statistics, such as transaction amount history, gas price and total wallets created.", + "/evm-rpc-endpoints>moreDescription": "A list of Telos EVM endpoints, with their health status and latency in milliseconds." } } diff --git a/webapp/src/language/en.telos.json b/webapp/src/language/en.telos.json index 5af2c6e5..f4bddb41 100644 --- a/webapp/src/language/en.telos.json +++ b/webapp/src/language/en.telos.json @@ -30,6 +30,9 @@ "/nodes-distribution>moreDescription": "A visualization of the geographic distribution of the nodes in this network.", "/accounts>moreDescription": "This tool helps find information about accounts and interact with contracts on the network. Enter an account name and obtain account information, smart contract actions, and table data.", "/block-distribution>moreDescription": "A visualization of the distribution of blocks produced by the nodes in the network.", - "/missed-blocks>moreDescription": "A list of scheduled, produced, and missed blocks by each account in the network." + "/missed-blocks>moreDescription": "A list of scheduled, produced, and missed blocks by each account in the network.", + "/evm>heading": "Telos EVM Dashboard", + "/evm>moreDescription": "Monitor Telos EVM statistics, such as transaction amount history, gas price and total wallets created.", + "/evm-rpc-endpoints>moreDescription": "A list of Telos EVM endpoints, with their health status and latency in milliseconds." } } diff --git a/webapp/src/language/es.json b/webapp/src/language/es.json index 7e95062e..44e742f7 100644 --- a/webapp/src/language/es.json +++ b/webapp/src/language/es.json @@ -58,7 +58,8 @@ "options": "Opciones", "noOptions": "Sin coincidencias", "updatedAt": "脷ltima actualizaci贸n", - "nextUpdateAt": "Pr贸xima actualizaci贸n" + "nextUpdateAt": "Pr贸xima actualizaci贸n", + "secondsAgo": "Hace Segundos" }, "routes": { "/>sidebar": "Panel", @@ -140,7 +141,6 @@ "Last Week": "脷ltima Semana", "Last Year": "脷ltimo A帽o", "scheduleVersion": "Versi贸n de Programa", - "secondsAgo": "Hace Segundos", "cpuUtilization": "Uso de CPU", "netUtilization": "Uso de NET", "cpuUtilizationAllTimeHigh": "Uso de CPU en TPS m谩ximo hist贸rico", @@ -164,7 +164,8 @@ "chainNetLimit": "L铆mite de Net en cadena", "timeToFinality": "Tiempo para finalidad", "cpuUsage": "Uso del CPU", - "netUsage": "Uso de NET" + "netUsage": "Uso de NET", + "average": "Promedio" }, "blockProducersRoute": {}, "rewardsDistributionRoute": { @@ -200,14 +201,18 @@ "bpjsonInconsistency": "El bp.json on chain y en of chain no coincide revisalo y realiza los cambios necesarios" }, "faucetRoute": { - "createAccount": "Crear Cuenta Faucet", - "newCreatedAccount": "Su nueva cuenta es", - "transferTokensTransaction": "Tokens transferidos correctamente. Puede revisar la transacci贸n aqu铆", - "createButton": "Crear", - "issueTokens": "Emitir Tokens", - "getTokens": "Obtener Tokens", - "publicKey": "Llave p煤blica (Active/Owner)", - "accountName": "Nombre de la cuenta" + "createAccount": "Cree su Cuenta", + "newCreatedAccount": "隆Felicidades! Su nueva cuenta ha sido creada:", + "transferTokensTransaction": "Los tokens han sido transferidos exitosamente. Vea la transacci贸n en el explorador:", + "createButton": "Cree su Cuenta", + "issueTokens": "Distribuya Tokens", + "getTokens": "Reciba Tokens", + "publicKey": "Introduzca la Clave P煤blica (Activa/Propietario)", + "accountName": "Elija un Nombre de Cuenta", + "invalidAccount": "Por favor, introduzca un nombre de cuenta v谩lido.", + "emptyFields": "Complete todos los campos para continuar con la creaci贸n de la cuenta.", + "accountFormat": "El nombre de la cuenta debe tener 12 caracteres o menos. Utilice solo letras min煤sculas (a-z) y n煤meros (1-5).", + "keyFormat": "Introduzca una clave ECC v谩lida. Puede generar una usando cleos o cualquier billetera compatible." }, "ricardianContractRoute": { "title": "Acuerdo de Productor de Bloques" @@ -411,7 +416,8 @@ "Connection error": "Error de conexi贸n", "Connection established": "Conexi贸n establecida", "Success": "脡xitosa", - "Failed": "Fallida" + "Failed": "Fallida", + "Network Error": "Error de red" }, "nodeSearchComponent": { "title": "Buscar Nodo", @@ -425,7 +431,8 @@ "updated": "El punto final funciona", "outdated": "El punto final funciona, pero no est谩 actualizado con el 煤ltimo bloque", "error": "Error en la consulta del punto final", - "not working": "El punto final no responde" + "not working": "El punto final no responde", + "helpText": "Pase el cursor o haga clic en los iconos para ver el estado de salud de un endpoint" }, "copyToClipboardComponent": { "copy": "Copiar", @@ -448,5 +455,27 @@ "charTitle": "Tiempo de respuesta promedio desde Costa Rica", "list": "Lista de puntos finales", "timeInSecs": "Tiempo en segundos" + }, + "evmDashboardRoute": { + "totalWallets": "Total de wallets creadas", + "avgBlockTime": "Tiempo promedio de bloque", + "gasPrice": "Precio de gas", + "avgGasUsage": "Uso promedio de gas", + "totalIncoming": "Total (TOKEN) entrantes", + "totalOutgoing": "Total (TOKEN) salientes", + "incoming": "Entrantes", + "outgoing": "Salientes", + "ATH": "TPS M谩ximo hist贸rico", + "lastBlock": "脷ltimo bloque", + "totalTxs": "Total de transacciones EVM", + "transactions": "Transacciones EVM", + "gasUsed": "Gas Usado" + }, + "evmEndpointsRoute": { + "title": "Lista de puntos finales RPC de EVM", + "rpcEndpoint": "Punto final RPC", + "latency": "Latencia", + "lastBlock": "脷ltimo bloque", + "rerun": "Reejecutar las pruebas" } } diff --git a/webapp/src/language/es.jungle.json b/webapp/src/language/es.jungle.json index e9c1caeb..8d4ce17b 100644 --- a/webapp/src/language/es.jungle.json +++ b/webapp/src/language/es.jungle.json @@ -28,6 +28,7 @@ "/nodes-distribution>moreDescription": "Una visualizaci贸n de la distribuci贸n geogr谩fica de los nodos de esta red.", "/accounts>moreDescription": "Esta herramienta le ayuda a buscar informaci贸n sobre cuentas y contratos de la red. Escriba el nombre de un contrato o cuenta en el espacio provisto para comenzar a buscar. Obtendr谩 los datos de las acciones del contrato, tablas de contrato, alcance, l铆mites superior e inferior y l铆mites.", "/block-distribution>moreDescription": "Una visualizaci贸n de la distribuci贸n de bloques producida por los nodos de la red.", - "/missed-blocks>moreDescription": "Una lista de bloques programados, producidos y perdidos por cada cuenta en la red." + "/missed-blocks>moreDescription": "Una lista de bloques programados, producidos y perdidos por cada cuenta en la red.", + "/evm>moreDescription": "Supervise las estad铆sticas del EVM, como el hist贸rico de la cantidad de transacciones, el precio del gas y las wallets creadas totales." } } diff --git a/webapp/src/language/es.mainnet.json b/webapp/src/language/es.mainnet.json index 5f271322..e4e2f2c1 100644 --- a/webapp/src/language/es.mainnet.json +++ b/webapp/src/language/es.mainnet.json @@ -28,6 +28,7 @@ "/nodes-distribution>moreDescription": "Una visualizaci贸n de la distribuci贸n geogr谩fica de los nodos de esta red.", "/accounts>moreDescription": "Esta herramienta le ayuda a buscar informaci贸n sobre cuentas y contratos de la red. Escriba el nombre de un contrato o cuenta en el espacio provisto para comenzar a buscar. Obtendr谩 los datos de las acciones del contrato, tablas de contrato, alcance, l铆mites superior e inferior y l铆mites.", "/block-distribution>moreDescription": "Una visualizaci贸n de la distribuci贸n de bloques producida por los nodos de la red.", - "/missed-blocks>moreDescription": "Una lista de bloques programados, producidos y perdidos por cada cuenta en la red." + "/missed-blocks>moreDescription": "Una lista de bloques programados, producidos y perdidos por cada cuenta en la red.", + "/evm>moreDescription": "Supervise las estad铆sticas del EVM, como el hist贸rico de la cantidad de transacciones, el precio del gas y las wallets creadas totales." } } diff --git a/webapp/src/language/es.telos-testnet.json b/webapp/src/language/es.telos-testnet.json index a0a1a5a9..8e707870 100644 --- a/webapp/src/language/es.telos-testnet.json +++ b/webapp/src/language/es.telos-testnet.json @@ -28,6 +28,8 @@ "/nodes-distribution>moreDescription": "Una visualizaci贸n de la distribuci贸n geogr谩fica de los nodos de esta red.", "/accounts>moreDescription": "Esta herramienta le ayuda a buscar informaci贸n sobre cuentas y contratos de la red. Escriba el nombre de un contrato o cuenta en el espacio provisto para comenzar a buscar. Obtendr谩 los datos de las acciones del contrato, tablas de contrato, alcance, l铆mites superior e inferior y l铆mites.", "/block-distribution>moreDescription": "Una visualizaci贸n de la distribuci贸n de bloques producida por los nodos de la red.", - "/missed-blocks>moreDescription": "Una lista de bloques programados, producidos y perdidos por cada cuenta en la red." + "/missed-blocks>moreDescription": "Una lista de bloques programados, producidos y perdidos por cada cuenta en la red.", + "/evm>moreDescription": "Supervise las estad铆sticas del Telos EVM, como el hist贸rico de la cantidad de transacciones, el precio del gas y las wallets creadas totales.", + "/evm-rpc-endpoints>moreDescription": "Una lista de puntos finales de Telos EVM, con sus estado de salud y latencia en milisegundos." } } diff --git a/webapp/src/language/es.telos.json b/webapp/src/language/es.telos.json index 2f231596..fb302043 100644 --- a/webapp/src/language/es.telos.json +++ b/webapp/src/language/es.telos.json @@ -28,6 +28,8 @@ "/nodes-distribution>moreDescription": "Una visualizaci贸n de la distribuci贸n geogr谩fica de los nodos de esta red.", "/accounts>moreDescription": "Esta herramienta le ayuda a buscar informaci贸n sobre cuentas y contratos de la red. Escriba el nombre de un contrato o cuenta en el espacio provisto para comenzar a buscar. Obtendr谩 los datos de las acciones del contrato, tablas de contrato, alcance, l铆mites superior e inferior y l铆mites.", "/block-distribution>moreDescription": "Una visualizaci贸n de la distribuci贸n de bloques producida por los nodos de la red.", - "/missed-blocks>moreDescription": "Una lista de bloques programados, producidos y perdidos por cada cuenta en la red." + "/missed-blocks>moreDescription": "Una lista de bloques programados, producidos y perdidos por cada cuenta en la red.", + "/evm>moreDescription": "Supervise las estad铆sticas del Telos EVM, como el hist贸rico de la cantidad de transacciones, el precio del gas y las wallets creadas totales.", + "/evm-rpc-endpoints>moreDescription": "Una lista de puntos finales de Telos EVM, con sus estado de salud y latencia en milisegundos." } } diff --git a/webapp/src/routes/EVMDashboard/index.js b/webapp/src/routes/EVMDashboard/index.js new file mode 100644 index 00000000..296a4f55 --- /dev/null +++ b/webapp/src/routes/EVMDashboard/index.js @@ -0,0 +1,204 @@ +import React from 'react' +import { useTheme } from '@mui/material/styles' +import { useTranslation } from 'react-i18next' +import { makeStyles } from '@mui/styles' + +import { formatWithThousandSeparator, getEVMBlockNumUrl } from '../../utils' +import { eosConfig, evmConfig } from '../../config' +import SimpleDataCard from '../../components/SimpleDataCard' +import BodyGraphValue from '../../components/SimpleDataCard/BodyGraphValue' +import TransactionsChartContainer from '../../components/TransactionsChartContainer' + +import styles from './styles' +import useEVMState from './useEVMstate' + +const useStyles = makeStyles(styles) + +const EVMDashboard = () => { + const classes = useStyles() + const theme = useTheme() + const { t } = useTranslation('evmDashboardRoute') + + const [ + { + EVMStats, + tokenHistoryData, + transactionsHistoryData, + options, + liveOption, + loading, + selected, + isPaused, + isLive, + }, + { handleSelect, handlePause }, + ] = useEVMState(theme, t) + + return ( + <> +
+ + +
+
+
+ handleSelect('txs', option), + isLive: isLive, + isHistoryEnabled: true, + }} + data={transactionsHistoryData} + chartLabelFormat={{ + yAxisText: t('transactions'), + blockTime: evmConfig.avgBlockTime, + customFormatter: (element) => { + const series = element?.series + const point = element?.point + + let pointName = '' + + if (point?.name) { + pointName = !isLive + ? `${point.name}` + : `Block Height: ${formatWithThousandSeparator(point.name)}` + } + + const resourcesDetail = point?.gas + ? `
${t('gasUsed')}: ${formatWithThousandSeparator( + point?.gas, + 3, + )} %` + : '' + + return ( + pointName + + '
' + + `${series?.name}: ${point?.y}` + + resourcesDetail + ) + }, + }} + /> +
+
+ handleSelect('token', option), + isHistoryEnabled: true, + isLive: false, + }} + data={tokenHistoryData} + chartLabelFormat={{ + yAxisText: eosConfig.tokenSymbol, + shared: true, + customFormatter: (element) => { + const points = element?.points + const pointName = points[0]?.point?.name || '' + + return ( + pointName + + points.reduce((tooltipText, point) => { + const series = point?.series + + return ( + tooltipText + + '
' + + `${series?.name}: ${formatWithThousandSeparator( + point?.y, + )}` + ) + }, '') + ) + }, + }} + /> +
+
+
+ + + getEVMBlockNumUrl(block), + )} + /> + + + + + + + + +
+ + ) +} + +export default EVMDashboard diff --git a/webapp/src/routes/EVMDashboard/styles.js b/webapp/src/routes/EVMDashboard/styles.js new file mode 100644 index 00000000..827a428e --- /dev/null +++ b/webapp/src/routes/EVMDashboard/styles.js @@ -0,0 +1,21 @@ +export default (theme) => ({ + container: { + display: 'flex', + marginBottom: theme.spacing(2), + gap: '10px', + }, + column: { + width: '50%', + [theme.breakpoints.down('md')]: { + width: '100%', + } + }, + cardsContainer: { + flexWrap: 'wrap', + }, + chartsContainer: { + [theme.breakpoints.down('md')]: { + flexDirection: 'column', + } + }, +}) diff --git a/webapp/src/routes/EVMDashboard/useEVMstate.js b/webapp/src/routes/EVMDashboard/useEVMstate.js new file mode 100644 index 00000000..04bd1526 --- /dev/null +++ b/webapp/src/routes/EVMDashboard/useEVMstate.js @@ -0,0 +1,263 @@ +import { useState, useEffect, useRef } from 'react' +import { useSubscription, useLazyQuery } from '@apollo/client' +import moment from 'moment' + +import { + EVM_STATS_SUBSCRIPTION, + EVM_HISTORICAL_STATS_SUBSCRIPTION, + EVM_TRANSACTION_QUERY, + EVM_TOKEN_QUERY, +} from '../../gql' +import eosApi from '../../utils/eosapi' +import ethApi from '../../utils/ethapi' +import { rangeOptions } from '../../utils' +import { evmConfig } from '../../config' + +const useEVMState = (theme, t) => { + const { data: stats, loading } = useSubscription(EVM_STATS_SUBSCRIPTION) + const { data: historicalStats, loading: historicalLoading } = useSubscription( + EVM_HISTORICAL_STATS_SUBSCRIPTION, + ) + const [getTransactionHistory, { data: transactionsData }] = useLazyQuery( + EVM_TRANSACTION_QUERY, + { fetchPolicy: 'network-only' }, + ) + const [getTokenHistory, { data: tokenData }] = useLazyQuery(EVM_TOKEN_QUERY, { + fetchPolicy: 'network-only', + }) + + const [EVMStats, setEVMStats] = useState() + const [blocksList, setBlockList] = useState( + new Array(evmConfig.maxTPSDataSize).fill({ y: 0 }), + ) + const [transactionsHistoryData, setTransactionsHistoryData] = useState() + const [tokenHistoryData, setTokenHistoryData] = useState() + + const liveOption = 'Live (30s)' + const [pause, setPause] = useState(false) + const [selected, setSelected] = useState({ + txs: liveOption, + token: '1 Month', + }) + + const pauseRef = useRef(pause) + const timeoutId = useRef(0) + + pauseRef.current = pause + + const handleSelect = (chart, option) => { + setSelected(prev => ({ ...prev, [chart]: option })) + if (chart === 'txs') { + if (option !== liveOption) { + setPause(true) + getTransactionHistory({ + variables: { + range: option, + }, + }) + } else { + setPause(false) + } + } else { + getTokenHistory({ + variables: { + range: option, + }, + }) + } + } + + const getWalletsCreated = async () => { + try { + const { rows } = await eosApi.getTableRows({ + code: evmConfig.account, + scope: evmConfig.account, + table: 'account', + reverse: true, + limit: 1, + json: true, + lower_bound: null, + }) + + return rows[0]?.index + 1 + } catch (error) {} + } + + useEffect(() => { + const updateStats = async () => { + const lastBlock = await ethApi.getLastBlock() + + setEVMStats(prev => ({ + ...prev, + last_block: lastBlock, + ...(historicalStats && historicalStats.evm_historical_stats[0]), + ...(stats && stats.evm_stats[0]), + })) + } + + updateStats() + }, [stats, loading, historicalStats, historicalLoading]) + + useEffect(() => { + const updateStats = async () => { + const gasPrice = await ethApi.getGasPrice() + const amount = await getWalletsCreated() + + setEVMStats(prev => ({ + ...prev, + gas_price: gasPrice / 10 ** 9, + wallets_created_count: amount, + })) + } + + if (selected.txs !== liveOption) { + getTransactionHistory({ + variables: { + range: selected.txs, + }, + }) + } + getTokenHistory({ + variables: { + range: selected.token, + }, + }) + + updateStats() + // eslint-disable-next-line + }, []) + + useEffect(() => { + if (tokenData?.evm_token_history) { + const { incoming, outgoing } = tokenData?.evm_token_history.reduce( + (history, tokenHistory) => { + const name = moment(tokenHistory.datetime)?.format('ll') + const datetime = new Date(tokenHistory.datetime).getTime() + + history.incoming.push({ + name, + y: parseInt(tokenHistory.incoming) || 0, + x: datetime, + }) + + history.outgoing.push({ + name, + y: parseInt(tokenHistory.outgoing) || 0, + x: datetime, + }) + + return history + }, + { incoming: [], outgoing: [] }, + ) + + setTokenHistoryData([ + { + name: t('incoming'), + color: theme.palette.secondary.main, + data: incoming, + }, + { + name: t('outgoing'), + color: theme.palette.tertiary.main, + data: outgoing, + }, + ]) + } + }, [tokenData, t, theme]) + + useEffect(() => { + if (transactionsData?.transactions) { + const data = transactionsData?.transactions.map((transaction) => ({ + name: moment(transaction.datetime)?.format('ll'), + gas: transaction.avg_gas_used || 0, + y: parseInt(transaction.transactions_count) || 0, + x: new Date(transaction.datetime).getTime(), + })) + + setTransactionsHistoryData([ + { + name: t('transactions'), + color: theme.palette.secondary.main, + data, + }, + ]) + } + }, [transactionsData, t, theme]) + + useEffect(() => { + const updateTPB = async blockNum => { + if (!blockNum) { + blockNum = await ethApi.getLastBlock() + } + + if (!pauseRef.current) { + ethApi.getBlock(blockNum).then(block => { + setBlockList(prev => { + let data = JSON.parse(JSON.stringify(prev)) + + if (data.length >= evmConfig.maxTPSDataSize) { + data.pop() + } + + data = [ + { + name: blockNum, + gas: (block?.gasUsed / block?.gasLimit) * 100 || 0, + y: block?.transactions?.length || 0, + }, + ...data, + ] + + return data.map((point, index) => { + point.x = index + return point + }) + }) + }) + } + + timeoutId.current = setTimeout(() => { + updateTPB(blockNum + 1) + }, evmConfig.avgBlockTime * 1000) + } + + updateTPB() + + return () => { + clearTimeout(timeoutId.current) + } + }, []) + + useEffect(() => { + setTransactionsHistoryData([ + { + name: t('transactions'), + color: theme.palette.secondary.main, + data: blocksList, + }, + ]) + }, [blocksList, t, theme]) + + return [ + { + EVMStats, + liveOption, + options: rangeOptions, + selected, + isPaused: pause, + isLive: selected.txs === liveOption, + transactionsHistoryData, + tokenHistoryData, + loading, + }, + { + handleSelect, + handlePause: () => { + setPause(prev => !prev) + }, + }, + ] +} + +export default useEVMState diff --git a/webapp/src/routes/EVMEndpointsList/index.js b/webapp/src/routes/EVMEndpointsList/index.js new file mode 100644 index 00000000..51b02158 --- /dev/null +++ b/webapp/src/routes/EVMEndpointsList/index.js @@ -0,0 +1,92 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import { makeStyles } from '@mui/styles' +import Button from '@mui/material/Button' +import Card from '@mui/material/Card' +import CardContent from '@mui/material/CardContent' +import Table from '@mui/material/Table' +import TableBody from '@mui/material/TableBody' +import TableCell from '@mui/material/TableCell' +import TableContainer from '@mui/material/TableContainer' +import TableHead from '@mui/material/TableHead' +import TableRow from '@mui/material/TableRow' +import Typography from '@mui/material/Typography' +import AutorenewOutlinedIcon from '@mui/icons-material/AutorenewOutlined' + +import HealthCheck from 'components/HealthCheck' +import HealthCheckInfo from 'components/HealthCheck/HealthCheckInfo' +import HealthInfoModal from '../../components/HealthCheck/InfoModal' + +import styles from './styles' +import useRPCEndpointsState from './useRPCEndpointsState' +import { getStatus, formatWithThousandSeparator } from 'utils' + +const useStyles = makeStyles(styles) + +const EVMEndpointsList = () => { + const classes = useStyles() + const { t } = useTranslation('evmEndpointsRoute') + + const [{ endpoints }, { runHealthCheck }] = useRPCEndpointsState() + + return ( + + +
+ + {t('title')} + + +
+
+ +
+
+ + + + + {t('rpcEndpoint')} + {t('lastBlock')} + {t('latency')} + + + + {endpoints?.map((endpoint, index) => ( + + +
+ {endpoint.url} + + + +
+
+ + {formatWithThousandSeparator(endpoint.height) || 'N/A'} + + + {endpoint.latency + ? `${formatWithThousandSeparator(endpoint.latency)} ms` + : 'N/A'} + +
+ ))} +
+
+
+
+
+
+ ) +} + +export default EVMEndpointsList diff --git a/webapp/src/routes/EVMEndpointsList/styles.js b/webapp/src/routes/EVMEndpointsList/styles.js new file mode 100644 index 00000000..aa5b25f6 --- /dev/null +++ b/webapp/src/routes/EVMEndpointsList/styles.js @@ -0,0 +1,36 @@ +export default (theme) => ({ + cardShadow: { + boxShadow: '0px 1px 5px rgba(0, 0, 0, 0.15) !important', + }, + healthContainer: { + display: 'flex', + maxWidth: '300px', + justifyContent: 'space-between', + }, + titleContainer: { + display: 'flex', + gap: theme.spacing(4), + alignItems: 'center', + }, + buttonContainer: { + padding: '0 0 0 25%', + marginTop: theme.spacing(4), + [theme.breakpoints.down('md')]: { + padding: 0, + }, + }, + tableContainer: { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + '& .MuiTableContainer-root': { + width: '80%', + [theme.breakpoints.down('md')]: { + width: '100%', + }, + [theme.breakpoints.up('lg')]: { + width: '50%', + } + }, + }, +}) diff --git a/webapp/src/routes/EVMEndpointsList/useRPCEndpointsState.js b/webapp/src/routes/EVMEndpointsList/useRPCEndpointsState.js new file mode 100644 index 00000000..2df17ed7 --- /dev/null +++ b/webapp/src/routes/EVMEndpointsList/useRPCEndpointsState.js @@ -0,0 +1,108 @@ +import { useCallback, useEffect, useState } from 'react' +import axios from 'axios' + +import { evmConfig } from '../../config' + +const useRPCEndpointsState = () => { + const [endpoints, setEndpoints] = useState(evmConfig.endpoints.map(url => ({ url, response: {} }))) + + const customAxios = axios.create() + + customAxios.interceptors.request.use( + config => { + config.startTime = new Date() + + return config + }, + error => Promise.reject(error), + ) + + customAxios.interceptors.response.use( + response => { + response.latency = new Date() - response.config?.startTime + + return response + }, + error => Promise.reject(error), + ) + + const getEndpointHealthCheck = async endpointUrl => { + try { + const { + data: { result: height }, + } = await axios.post(endpointUrl, { + method: 'eth_blockNumber', + params: [], + id: 1, + jsonrpc: '2.0', + }) + + const { data, latency, status, statusText } = await customAxios.post( + endpointUrl, + { + method: 'eth_getBlockByNumber', + params: [height.toString(), false], + id: 2, + jsonrpc: '2.0', + }, + ) + + return { + url: endpointUrl, + latency, + height: parseInt(height), + updated_at: new Date(), + head_block_time: new Date(parseInt(data?.result?.timestamp) * 1000), + response: { status, statusText, isWorking: status === 200 }, + } + } catch (error) { + return { + url: endpointUrl, + updated_at: new Date(), + response: { + statusText: error?.message, + status: null, + isWorking: false, + }, + } + } + } + + const runHealthCheck = useCallback(() => { + setEndpoints(prev => prev.map(endpoint => ({ url: endpoint.url, response: {} }))) + + const rpcList = JSON.parse(JSON.stringify(endpoints)) + + rpcList.forEach(async ({ url }, index) => { + const endpoint = await getEndpointHealthCheck(url) + + setEndpoints(prev => { + const newEndpoints = [ + ...prev.slice(0, index), + endpoint, + ...prev.slice(index + 1), + ] + + if (newEndpoints.every(endpoint => !!endpoint.response.statusText)) { + newEndpoints.sort((e1, e2) => + e1?.height === e2?.height + ? e1?.latency - e2?.latency + : e2?.height - e1?.height, + ) + } + + return newEndpoints + }) + }) + // eslint-disable-next-line + }, [endpoints]) + + useEffect(() => { + runHealthCheck() + // eslint-disable-next-line + }, []) + + return [{ endpoints }, { runHealthCheck }] +} + +export default useRPCEndpointsState diff --git a/webapp/src/routes/Faucet/index.js b/webapp/src/routes/Faucet/index.js index 1c6a8fb7..dd7172eb 100644 --- a/webapp/src/routes/Faucet/index.js +++ b/webapp/src/routes/Faucet/index.js @@ -25,12 +25,13 @@ const useStyles = makeStyles(styles) const Faucet = () => { const classes = useStyles() const { t } = useTranslation('faucetRoute') + const isUltraTestnet = eosConfig.networkName === 'ultra-testnet' const [, { showMessage }] = useSnackbarMessageState() const [account, setAccount] = useState('') const [createAccountValues, setCreateAccountValues] = useState({}) const [transferTokensTransaction, setTransferTokensTransaction] = useState('') const [createFaucetAccount, { loading: loadingCreateAccount }] = useMutation( - CREATE_ACCOUNT_MUTATION(eosConfig.networkName !== 'ultra-testnet'), + CREATE_ACCOUNT_MUTATION(!isUltraTestnet), ) const [transferFaucetTokens, { loading: loadingTransferFaucetTokens }] = useMutation(TRANFER_FAUCET_TOKENS_MUTATION) @@ -42,23 +43,23 @@ const Faucet = () => { if ( !reCaptchaToken || !createAccountValues.publicKey || - (eosConfig.networkName !== 'ultra-testnet' && + (!isUltraTestnet && !createAccountValues.accountName) ) { showMessage({ type: 'error', - content: 'Fill out the fields to create an account', + content: t('emptyFields'), }) return } if ( - eosConfig.networkName !== 'ultra-testnet' && + !isUltraTestnet && !isValidAccountName(createAccountValues.accountName) ) { showMessage({ type: 'error', - content: 'Please enter a valid account name', + content: t('invalidAccount'), }) return } @@ -102,12 +103,12 @@ const Faucet = () => { const reCaptchaToken = await executeRecaptcha?.('submit') - if (!reCaptchaToken || !account) return + if (!reCaptchaToken) return - if (!isValidAccountName(account)) { + if (!account || !isValidAccountName(account)) { showMessage({ type: 'error', - content: 'Please enter a valid account name', + content: t('invalidAccount'), }) return } @@ -129,7 +130,11 @@ const Faucet = () => { showMessage({ type: 'success', content: ( - + {`${t('transferTokensTransaction')} ${tx.slice(0, 7)}`} ), @@ -150,13 +155,18 @@ const Faucet = () => { } const isValidAccountName = name => { - const regex = /^[.12345abcdefghijklmnopqrstuvwxyz]+$/i + const regex = /^[.12345abcdefghijklmnopqrstuvwxyz]+$/ return name?.length < 13 && regex.test(name) } return ( -
+
@@ -174,11 +184,11 @@ const Faucet = () => { ...{ publicKey: e.target.value }, }) } - error={!createAccountValues.publicKey} + helperText={t('keyFormat')} required />
- {eosConfig.networkName !== 'ultra-testnet' && ( + {!isUltraTestnet && (
{ ...{ accountName: e.target.value }, }) } - error={!isValidAccountName(createAccountValues.accountName)} + error={!!createAccountValues.accountName && !isValidAccountName(createAccountValues.accountName)} + helperText={t('accountFormat')} required />
@@ -221,16 +232,17 @@ const Faucet = () => {
- {t('issueTokens')} + {`${t('issueTokens')} (500 ${eosConfig.tokenSymbol})`}
setAccount(e.target.value)} - error={!isValidAccountName(account)} + error={!!account && !isValidAccountName(account)} + helperText={t('accountFormat')} required />
diff --git a/webapp/src/routes/Faucet/styles.js b/webapp/src/routes/Faucet/styles.js index b775ee3d..03c5538b 100644 --- a/webapp/src/routes/Faucet/styles.js +++ b/webapp/src/routes/Faucet/styles.js @@ -1,21 +1,30 @@ export default (theme) => ({ formControl: { - margin: theme.spacing(2), + margin: theme.spacing(6, 4, 4), display: 'flex', flexDirection: 'column', gap: theme.spacing(4), + minHeight: '150px', + justifyContent: 'center', + '& .MuiFormControl-root': { + width: '300px', + }, }, test: { display: 'flex', + justifyContent: 'center', [theme.breakpoints.down('md')]: { - display: 'block', + flexWrap: 'wrap', + height: '100% !important', }, + marginBottom: theme.spacing(4), }, card: { padding: '10px', height: '100%', '& .MuiPaper-root': { + height: '100%', boxShadow: '0px 1px 5px rgba(0, 0, 0, 0.15) !important', - } + }, }, }) diff --git a/webapp/src/routes/Home/BlockProducerInfo.js b/webapp/src/routes/Home/BlockProducerInfo.js index 70fdba1a..0e6d5ac8 100644 --- a/webapp/src/routes/Home/BlockProducerInfo.js +++ b/webapp/src/routes/Home/BlockProducerInfo.js @@ -84,30 +84,27 @@ const BlockProducerInfo = ({ t, classes }) => { return ( <>
- - {t('currentProducer')} - - {info.head_block_producer} - - - - {t('scheduleVersion')} - - {schedule?.version} - - - - {t('headBlock')} - - {formatWithThousandSeparator(info.head_block_num)} - - - - {t('lastBlock')} - - {formatWithThousandSeparator(info.last_irreversible_block_num)} - - + + + +
@@ -128,7 +125,6 @@ const BlockProducerInfo = ({ t, classes }) => { <> { total={total} /> - - {t('timeToFinality')} - - {schedule.producers + - + : '0 s' + } + /> } /> diff --git a/webapp/src/routes/Home/TransactionInfo.js b/webapp/src/routes/Home/TransactionInfo.js index c879c3b7..c7ea65cd 100644 --- a/webapp/src/routes/Home/TransactionInfo.js +++ b/webapp/src/routes/Home/TransactionInfo.js @@ -1,35 +1,19 @@ /* eslint camelcase: 0 */ import React, { useEffect, useState } from 'react' import { useLazyQuery } from '@apollo/client' -import { makeStyles } from '@mui/styles' import { useTheme } from '@mui/material/styles' -import clsx from 'clsx' import PropTypes from 'prop-types' -import Select from '@mui/material/Select' -import Card from '@mui/material/Card' -import MenuItem from '@mui/material/MenuItem' -import FormControl from '@mui/material/FormControl' -import InputLabel from '@mui/material/InputLabel' -import CardContent from '@mui/material/CardContent' -import Typography from '@mui/material/Typography' -import PlayArrowIcon from '@mui/icons-material/PlayArrow' -import LinearProgress from '@mui/material/LinearProgress' +import moment from 'moment' import { TRANSACTION_QUERY } from '../../gql' import { formatWithThousandSeparator, rangeOptions } from '../../utils' -import TransactionsLineChart from '../../components/TransactionsLineChart' import { useSharedState } from '../../context/state.context' import { generalConfig } from '../../config' - -import EqualIcon from './EqualIcon' -import styles from './styles' - -const useStyles = makeStyles(styles) +import TransactionsChartContainer from '../../components/TransactionsChartContainer' const options = ['Live (30s)', ...rangeOptions] const TransactionInfo = ({ t, startTrackingInfo, stopTrackingInfo }) => { - const classes = useStyles() const theme = useTheme() const [{ tps, tpb }] = useSharedState() const [graphicData, setGraphicData] = useState([ @@ -39,7 +23,7 @@ const TransactionInfo = ({ t, startTrackingInfo, stopTrackingInfo }) => { }, { name: t('transactionsPerBlock'), - color: '#00C853', + color: theme.palette.tertiary.main, }, ]) const [option, setOption] = useState(options[0]) @@ -83,7 +67,7 @@ const TransactionInfo = ({ t, startTrackingInfo, stopTrackingInfo }) => { }, { name: t('transactionsPerBlock'), - color: '#00C853', + color: theme.palette.tertiary.main, data: trxPerBlock, }, ]) @@ -119,6 +103,7 @@ const TransactionInfo = ({ t, startTrackingInfo, stopTrackingInfo }) => { const { trxPerBlock, trxPerSecond } = data.transactions.reduce( (history, transactionHistory) => { history.trxPerBlock.push({ + name: moment(transactionHistory.datetime)?.format('ll'), cpu: transactionHistory.cpu || 0, net: transactionHistory.net || 0, y: transactionHistory.transactions_count || 0, @@ -126,6 +111,7 @@ const TransactionInfo = ({ t, startTrackingInfo, stopTrackingInfo }) => { }) history.trxPerSecond.push({ + name: moment(transactionHistory.datetime)?.format('ll'), cpu: transactionHistory.cpu / 2 || 0, net: transactionHistory.net / 2 || 0, y: transactionHistory.transactions_count * 2 || 0, @@ -139,13 +125,13 @@ const TransactionInfo = ({ t, startTrackingInfo, stopTrackingInfo }) => { setGraphicData([ { - name: t('transactionsPerSecond'), + name: t('average') + ' ' + t('transactionsPerSecond'), color: theme.palette.secondary.main, data: trxPerSecond, }, { - name: t('transactionsPerBlock'), - color: '#00C853', + name: t('average') + ' ' + t('transactionsPerBlock'), + color: theme.palette.tertiary.main, data: trxPerBlock, }, ]) @@ -153,98 +139,50 @@ const TransactionInfo = ({ t, startTrackingInfo, stopTrackingInfo }) => { }, [data, t]) return ( - - -
- - {t('transactions')} - -
- - {generalConfig.historyEnabled && ( - <> - {t('timeFrame')} - - - )} - -
{ - if (option === options[0]) { - setPause(!pause) - if (pause) { - startTrackingInfo() - } else { - stopTrackingInfo() - } - } - }} - className={clsx(classes.pauseButton, { - [classes.disableButton]: option !== options[0], - })} - > - {pause ? ( - - ) : ( - - )} - {pause ? t('play') : t('pause')} -
-
-
- {loading && } - -
-
+ { + if (option === options[0]) { + setPause(!pause) + if (pause) { + startTrackingInfo() + } else { + stopTrackingInfo() + } + } + }} + historyState={{ + value: option, + options: options, + isLive: option === options[0], + isHistoryEnabled: generalConfig.historyEnabled, + onSelect: setOption, + }} + data={graphicData} + chartLabelFormat={{ + ariaLabel: 'select time filter', + yAxisText: t('transactions'), + blockTime: 1, + customFormatter: element => { + const series = element?.series + const point = element?.point + + const pointName = point?.name ? `${point.name}
` : '' + const resourcesDetail = + point?.net && point?.cpu + ? `
${t('netUsage')}:${point.net} %
${t( + 'cpuUsage', + )}:${point.cpu} %` + : '' + + return ( + pointName + `${series?.name}: ${point?.y}` + resourcesDetail + ) + }, + }} + /> ) } diff --git a/webapp/src/routes/Home/styles.js b/webapp/src/routes/Home/styles.js index 6b67330b..f37cc49a 100644 --- a/webapp/src/routes/Home/styles.js +++ b/webapp/src/routes/Home/styles.js @@ -10,80 +10,6 @@ export default (theme) => ({ display: 'block', }, }, - bottomRow: { - [theme.breakpoints.up('md')]: { - paddingTop: theme.spacing(1), - }, - }, - boxIrreversible: { - display: 'flex', - alignItems: 'baseline', - paddingTop: theme.spacing(3), - '& .MuiTypography-body1': { - marginBottom: '0 !important', - letterSpacing: '0.09px', - color: 'rgba(0, 0, 0, 0.54)', - '& strong': { - color: '#212121', - }, - }, - }, - pauseButton: { - display: 'flex', - width: 75, - height: 24, - '&:hover': { - cursor: 'pointer', - }, - }, - disableButton: { - color: theme.palette.action.disabled, - }, - headerTransactionLine: { - display: 'flex', - justifyContent: 'space-between', - flexDirection: 'column', - alignItems: 'baseline', - padding: theme.spacing(1), - [theme.breakpoints.up('lg')]: { - justifyContent: 'space-between', - alignItems: 'center', - flexDirection: 'row', - }, - }, - formControl: { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - width: '100%', - '& .MuiFormControl-root': { - width: 200, - }, - '& .MuiInputLabel-formControl': { - position: 'relative', - marginBottom: `-${theme.spacing(2)}`, - }, - [theme.breakpoints.up('lg')]: { - width: 300, - }, - }, - cards: { - textTransform: 'capitalize', - minHeight: '90px', - '& .MuiTypography-h6': { - display: 'flex', - justifyContent: 'center', - textAlign: 'center', - marginTop: theme.spacing(2), - }, - }, - cardLink: { - fontSize: 15, - marginBottom: 2, - }, - lowercase: { - textTransform: 'lowercase !important', - }, cardShadow: { boxShadow: '0px 1px 3px 1px rgba(0, 0, 0, 0.15) !important', }, @@ -96,9 +22,6 @@ export default (theme) => ({ display: 'block', }, }, - uniquelocations: { - flexGrow: '1 !important', - }, divTrans: { width: '50%', [theme.breakpoints.down('md')]: { diff --git a/webapp/src/routes/index.js b/webapp/src/routes/index.js index f4c12d86..9349814a 100644 --- a/webapp/src/routes/index.js +++ b/webapp/src/routes/index.js @@ -14,6 +14,8 @@ import { BarChart as BarChartIcon, } from 'react-feather' import QueryStatsIcon from '@mui/icons-material/QueryStats' +import StackedLineChartIcon from '@mui/icons-material/StackedLineChart' +import ListAltOutlined from '@mui/icons-material/ListAltOutlined'; import { eosConfig, generalConfig } from '../config' import { @@ -26,7 +28,6 @@ import { TopologySvg, RewardsSvg, } from '../components/Icons' -import StressTestDashboard from './StressTestDashboard' const Home = lazy(() => import('./Home')) const CPUBenchmark = lazy(() => import('./CPUBenchmark')) @@ -46,6 +47,9 @@ const BlockDistribution = lazy(() => import('./BlockDistribution')) const MissedBlocks = lazy(() => import('./MissedBlocks')) const EndpointsList = lazy(() => import('./EndpointsList')) const NonCompliantBPs = lazy(() => import('./NonCompliantBPs')) +const StressTestDashboard = lazy(() => import('./StressTestDashboard')) +const EVMDashboard = lazy(() => import('./EVMDashboard')) +const EVMEndpointsList = lazy(() => import('./EVMEndpointsList')) const LacchainNetwork = lazy(() => import('./Lacchain/LacchainNetwork')) const LacchainManagement = lazy(() => import('./Lacchain/LacchainManagement')) const LacchainNodeConfig = lazy(() => import('./Lacchain/LacchainNodeConfig')) @@ -143,6 +147,21 @@ const defaultRoutes = [ path: '/ricardian-contract', exact: true, }, + { + header: 'EVM', + name: 'evm', + icon: , + component: EVMDashboard, + path: '/evm', + exact: true, + }, + { + name: 'evm-rpc-endpoints', + icon: , + component: EVMEndpointsList, + path: '/evm-rpc-endpoints', + exact: true, + }, { header: 'tools', name: 'accounts', @@ -159,6 +178,7 @@ const defaultRoutes = [ exact: true, }, ] + const lacchainRoutes = [ { header: 'networkInformation', diff --git a/webapp/src/theme/variants.js b/webapp/src/theme/variants.js index e663fcc0..609f07bf 100644 --- a/webapp/src/theme/variants.js +++ b/webapp/src/theme/variants.js @@ -10,6 +10,10 @@ const lightVariant = { secondary: { main: blue[600], contrastText: '#FFF' + }, + tertiary: { + main: '#00C853', + contrastText: '#FFF' } }, header: { diff --git a/webapp/src/utils/eosapi.js b/webapp/src/utils/eosapi.js index 3ffffe29..e772228b 100644 --- a/webapp/src/utils/eosapi.js +++ b/webapp/src/utils/eosapi.js @@ -30,7 +30,11 @@ const callEosApi = async method => { const headBlockTime = response.head_block_time if (headBlockTime) { - const diffBlockTimems = new Date() - new Date(headBlockTime) + const nowUTC = new Date() + + nowUTC.setMinutes(nowUTC.getMinutes() + nowUTC.getTimezoneOffset()) + + const diffBlockTimems = nowUTC - new Date(headBlockTime) if (diffBlockTimems > eosConfig.syncToleranceInterval) { throw new Error(`The endpoint ${eosApi.endpoint} is outdated`) diff --git a/webapp/src/utils/ethapi.js b/webapp/src/utils/ethapi.js new file mode 100644 index 00000000..2fbed92c --- /dev/null +++ b/webapp/src/utils/ethapi.js @@ -0,0 +1,31 @@ +import axios from 'axios' + +import { evmConfig } from '../config' + +const queryEthApi = async (method, params = []) => { + try { + const { + data: { result }, + } = await axios.post(evmConfig.endpoint, { + method, + params, + id: 1, + jsonrpc: '2.0', + }) + + return parseInt(result) || result + } catch (error) {} +} + +const getGasPrice = async () => await queryEthApi('eth_gasPrice') +const getLastBlock = async () => await queryEthApi('eth_blockNumber') +const getChainId = async () => await queryEthApi('eth_chainId') +const getBlock = async blockNum => + await queryEthApi('eth_getBlockByNumber', [blockNum.toString(), false]) + +export default { + getGasPrice, + getLastBlock, + getChainId, + getBlock, +} diff --git a/webapp/src/utils/get-endpoint-health-status.js b/webapp/src/utils/get-endpoint-health-status.js new file mode 100644 index 00000000..7c6571c3 --- /dev/null +++ b/webapp/src/utils/get-endpoint-health-status.js @@ -0,0 +1,28 @@ +import { eosConfig, generalConfig } from '../config' + +const { healthLights } = generalConfig + +const isSynchronized = endpoint => { + const diffBlockTimems = + new Date(endpoint.updated_at) - new Date(endpoint.head_block_time) + + return diffBlockTimems <= eosConfig.syncToleranceInterval +} + +export const getStatus = endpoint => { + if (endpoint.response.status === undefined) return + + if (endpoint.response?.isWorking) { + return !endpoint.head_block_time || isSynchronized(endpoint) + ? healthLights.greenLight + : healthLights.timerOff + } + + switch (Math.floor(endpoint.response?.status / 100)) { + case 4: + case 5: + return healthLights.yellowLight + default: + return healthLights.redLight + } +} diff --git a/webapp/src/utils/get-evmblocknum-url.js b/webapp/src/utils/get-evmblocknum-url.js new file mode 100644 index 00000000..282e0bbe --- /dev/null +++ b/webapp/src/utils/get-evmblocknum-url.js @@ -0,0 +1,11 @@ +import { evmConfig } from '../config' + +export const getEVMBlockNumUrl = blockNum => { + if (!blockNum || !evmConfig.blockExplorerUrl) { + return + } + + return evmConfig.blockExplorerUrl.replace('(block)', blockNum) +} + +export default getEVMBlockNumUrl diff --git a/webapp/src/utils/index.js b/webapp/src/utils/index.js index f60d12e8..2041205c 100644 --- a/webapp/src/utils/index.js +++ b/webapp/src/utils/index.js @@ -7,3 +7,5 @@ export * from './get-range-options' export * from './get-transaction-url' export * from './validate-image' export * from './validate-url' +export * from './get-evmblocknum-url' +export * from './get-endpoint-health-status'