diff --git a/.dialyzer-ignore b/.dialyzer-ignore
index 84162c2785e0..6dd625f3298f 100644
--- a/.dialyzer-ignore
+++ b/.dialyzer-ignore
@@ -6,8 +6,8 @@
lib/ethereum_jsonrpc/rolling_window.ex:171
lib/explorer/smart_contract/solidity/publisher_worker.ex:1
lib/explorer/smart_contract/vyper/publisher_worker.ex:1
-lib/explorer/smart_contract/solidity/publisher_worker.ex:6
-lib/explorer/smart_contract/vyper/publisher_worker.ex:6
+lib/explorer/smart_contract/solidity/publisher_worker.ex:8
+lib/explorer/smart_contract/vyper/publisher_worker.ex:8
lib/block_scout_web/router.ex:1
lib/block_scout_web/schema/types.ex:31
lib/phoenix/router.ex:324
diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml
index 6bbec02ea1cb..645ad98490ba 100644
--- a/.github/workflows/config.yml
+++ b/.github/workflows/config.yml
@@ -12,6 +12,8 @@ on:
- production-sokol-stg
- production-rsk-stg
- production-lukso-stg
+ - production-immutable-stg
+ - production-zksync-stg
- staging-l2
pull_request:
branches:
@@ -47,7 +49,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-
@@ -105,7 +107,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -129,7 +131,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -152,7 +154,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -161,7 +163,7 @@ jobs:
id: dialyzer-cache
with:
path: priv/plts
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-dialyzer-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-dialyzer-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-dialyzer-"
@@ -192,7 +194,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -218,7 +220,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -247,7 +249,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -295,7 +297,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -341,7 +343,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -398,7 +400,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -452,7 +454,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -517,7 +519,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -581,7 +583,7 @@ jobs:
path: |
deps
_build
- key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_20-${{ hashFiles('mix.lock') }}
+ key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash_22-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-"
@@ -624,7 +626,7 @@ jobs:
PGUSER: postgres
ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Nethermind.Mox"
ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Mox"
- CHAIN_ID: "77"
+ CHAIN_ID: "10200"
API_RATE_LIMIT_DISABLED: "true"
ADMIN_PANEL_ENABLED: "true"
ACCOUNT_ENABLED: "true"
diff --git a/.github/workflows/publish-docker-image-every-push.yml b/.github/workflows/publish-docker-image-every-push.yml
index a2205707247d..c748dfd25ea2 100644
--- a/.github/workflows/publish-docker-image-every-push.yml
+++ b/.github/workflows/publish-docker-image-every-push.yml
@@ -7,7 +7,7 @@ on:
env:
OTP_VERSION: '25.2.1'
ELIXIR_VERSION: '1.14.3'
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
jobs:
push_to_registry:
diff --git a/.github/workflows/publish-docker-image-for-core.yml b/.github/workflows/publish-docker-image-for-core.yml
index cf8c9344c091..48470e040e3a 100644
--- a/.github/workflows/publish-docker-image-for-core.yml
+++ b/.github/workflows/publish-docker-image-for-core.yml
@@ -14,7 +14,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
DOCKER_CHAIN_NAME: poa
steps:
- name: Check out the repo
@@ -44,9 +44,9 @@ jobs:
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:latest, blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}
build-args: |
CACHE_EXCHANGE_RATES_PERIOD=
- DISABLE_READ_API=false
+ API_V1_READ_METHODS_DISABLED=false
DISABLE_WEBAPP=false
- DISABLE_WRITE_API=false
+ API_V1_WRITE_METHODS_DISABLED=false
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=
ADMIN_PANEL_ENABLED=false
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
diff --git a/.github/workflows/publish-docker-image-for-eth-goerli.yml b/.github/workflows/publish-docker-image-for-eth-goerli.yml
index 99da783794be..95c8e9fa996f 100644
--- a/.github/workflows/publish-docker-image-for-eth-goerli.yml
+++ b/.github/workflows/publish-docker-image-for-eth-goerli.yml
@@ -14,7 +14,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
DOCKER_CHAIN_NAME: eth-goerli
steps:
- name: Check out the repo
@@ -44,9 +44,9 @@ jobs:
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:latest, blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}
build-args: |
CACHE_EXCHANGE_RATES_PERIOD=
- DISABLE_READ_API=false
+ API_V1_READ_METHODS_DISABLED=false
DISABLE_WEBAPP=false
- DISABLE_WRITE_API=false
+ API_V1_WRITE_METHODS_DISABLED=false
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=
ADMIN_PANEL_ENABLED=false
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
diff --git a/.github/workflows/publish-docker-image-for-eth.yml b/.github/workflows/publish-docker-image-for-eth.yml
index a4598fa845b4..237eec76e5cd 100644
--- a/.github/workflows/publish-docker-image-for-eth.yml
+++ b/.github/workflows/publish-docker-image-for-eth.yml
@@ -14,7 +14,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
DOCKER_CHAIN_NAME: mainnet
steps:
- name: Check out the repo
@@ -44,9 +44,9 @@ jobs:
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}-experimental
build-args: |
CACHE_EXCHANGE_RATES_PERIOD=
- DISABLE_READ_API=false
+ API_V1_READ_METHODS_DISABLED=false
DISABLE_WEBAPP=false
- DISABLE_WRITE_API=false
+ API_V1_WRITE_METHODS_DISABLED=false
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=false
ADMIN_PANEL_ENABLED=false
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
diff --git a/.github/workflows/publish-docker-image-for-immutable.yml b/.github/workflows/publish-docker-image-for-immutable.yml
index abf6071504bc..92eff232935f 100644
--- a/.github/workflows/publish-docker-image-for-immutable.yml
+++ b/.github/workflows/publish-docker-image-for-immutable.yml
@@ -17,7 +17,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
DOCKER_CHAIN_NAME: immutable
steps:
- name: Check out the repo
@@ -53,9 +53,9 @@ jobs:
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:latest, blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}
build-args: |
CACHE_EXCHANGE_RATES_PERIOD=
- DISABLE_READ_API=false
+ API_V1_READ_METHODS_DISABLED=false
DISABLE_WEBAPP=false
- DISABLE_WRITE_API=false
+ API_V1_WRITE_METHODS_DISABLED=false
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=
ADMIN_PANEL_ENABLED=false
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
diff --git a/.github/workflows/publish-docker-image-for-l2-staging.yml b/.github/workflows/publish-docker-image-for-l2-staging.yml
index 4a85493e9efb..a95c63ad9e66 100644
--- a/.github/workflows/publish-docker-image-for-l2-staging.yml
+++ b/.github/workflows/publish-docker-image-for-l2-staging.yml
@@ -14,7 +14,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
DOCKER_CHAIN_NAME: optimism-l2-advanced
steps:
- name: Check out the repo
@@ -44,9 +44,9 @@ jobs:
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:latest, blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}
build-args: |
CACHE_EXCHANGE_RATES_PERIOD=
- DISABLE_READ_API=false
+ API_V1_READ_METHODS_DISABLED=false
DISABLE_WEBAPP=false
- DISABLE_WRITE_API=false
+ API_V1_WRITE_METHODS_DISABLED=false
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=
ADMIN_PANEL_ENABLED=false
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
diff --git a/.github/workflows/publish-docker-image-for-lukso.yml b/.github/workflows/publish-docker-image-for-lukso.yml
index 96109f811cf1..8279c009f00f 100644
--- a/.github/workflows/publish-docker-image-for-lukso.yml
+++ b/.github/workflows/publish-docker-image-for-lukso.yml
@@ -14,7 +14,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
DOCKER_CHAIN_NAME: lukso
steps:
- name: Check out the repo
@@ -44,9 +44,9 @@ jobs:
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:latest, blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}
build-args: |
CACHE_EXCHANGE_RATES_PERIOD=
- DISABLE_READ_API=false
+ API_V1_READ_METHODS_DISABLED=false
DISABLE_WEBAPP=false
- DISABLE_WRITE_API=false
+ API_V1_WRITE_METHODS_DISABLED=false
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=
ADMIN_PANEL_ENABLED=false
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
diff --git a/.github/workflows/publish-docker-image-for-optimism.yml b/.github/workflows/publish-docker-image-for-optimism.yml
index e1406ee5a24f..7c7bd2f11e64 100644
--- a/.github/workflows/publish-docker-image-for-optimism.yml
+++ b/.github/workflows/publish-docker-image-for-optimism.yml
@@ -14,7 +14,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
DOCKER_CHAIN_NAME: optimism
steps:
- name: Check out the repo
@@ -44,9 +44,9 @@ jobs:
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:latest, blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}
build-args: |
CACHE_EXCHANGE_RATES_PERIOD=
- DISABLE_READ_API=false
+ API_V1_READ_METHODS_DISABLED=false
DISABLE_WEBAPP=false
- DISABLE_WRITE_API=false
+ API_V1_WRITE_METHODS_DISABLED=false
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=
ADMIN_PANEL_ENABLED=false
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
diff --git a/.github/workflows/publish-docker-image-for-rsk.yml b/.github/workflows/publish-docker-image-for-rsk.yml
index fca3a4d13f04..5eb97cf0de37 100644
--- a/.github/workflows/publish-docker-image-for-rsk.yml
+++ b/.github/workflows/publish-docker-image-for-rsk.yml
@@ -14,7 +14,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
DOCKER_CHAIN_NAME: rsk
steps:
- name: Check out the repo
@@ -44,9 +44,9 @@ jobs:
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:latest, blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}
build-args: |
CACHE_EXCHANGE_RATES_PERIOD=
- DISABLE_READ_API=false
+ API_V1_READ_METHODS_DISABLED=false
DISABLE_WEBAPP=false
- DISABLE_WRITE_API=false
+ API_V1_WRITE_METHODS_DISABLED=false
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=
ADMIN_PANEL_ENABLED=false
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
diff --git a/.github/workflows/publish-docker-image-for-xdai.yml b/.github/workflows/publish-docker-image-for-xdai.yml
index 1f047a818b84..37295fedd354 100644
--- a/.github/workflows/publish-docker-image-for-xdai.yml
+++ b/.github/workflows/publish-docker-image-for-xdai.yml
@@ -17,7 +17,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
DOCKER_CHAIN_NAME: xdai
steps:
- name: Check out the repo
@@ -53,9 +53,9 @@ jobs:
tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:latest, blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}
build-args: |
CACHE_EXCHANGE_RATES_PERIOD=
- DISABLE_READ_API=false
+ API_V1_READ_METHODS_DISABLED=false
DISABLE_WEBAPP=false
- DISABLE_WRITE_API=false
+ API_V1_WRITE_METHODS_DISABLED=false
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=
ADMIN_PANEL_ENABLED=false
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
diff --git a/.github/workflows/publish-docker-image-for-zksync.yml b/.github/workflows/publish-docker-image-for-zksync.yml
new file mode 100644
index 000000000000..e37e195a118a
--- /dev/null
+++ b/.github/workflows/publish-docker-image-for-zksync.yml
@@ -0,0 +1,54 @@
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+
+name: Publish Docker image for specific chain branches
+
+on:
+ push:
+ branches:
+ - production-zksync-stg
+jobs:
+ push_to_registry:
+ name: Push Docker image to Docker Hub
+ runs-on: ubuntu-latest
+ env:
+ RELEASE_VERSION: 5.2.2
+ DOCKER_CHAIN_NAME: zksync
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v3
+
+ - name: Log in to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
+
+ - name: Extract metadata (tags, labels) for Docker
+ id: meta
+ uses: docker/metadata-action@v4
+ with:
+ images: blockscout/blockscout
+
+ - name: Add SHORT_SHA env property with commit short sha
+ run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v3
+ with:
+ context: .
+ file: ./docker/Dockerfile
+ push: true
+ tags: blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:latest, blockscout/blockscout-${{ env.DOCKER_CHAIN_NAME }}:${{ env.RELEASE_VERSION }}-postrelease-${{ env.SHORT_SHA }}
+ build-args: |
+ CACHE_EXCHANGE_RATES_PERIOD=
+ API_V1_READ_METHODS_DISABLED=false
+ DISABLE_WEBAPP=false
+ API_V1_WRITE_METHODS_DISABLED=false
+ CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED=
+ ADMIN_PANEL_ENABLED=false
+ CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL=
+ BLOCKSCOUT_VERSION=v${{ env.RELEASE_VERSION }}-beta.+commit.${{ env.SHORT_SHA }}
+ RELEASE_VERSION=${{ env.RELEASE_VERSION }}
\ No newline at end of file
diff --git a/.github/workflows/publish-docker-image-release.yml b/.github/workflows/publish-docker-image-release.yml
index 689f3d7ec858..918abd13067d 100644
--- a/.github/workflows/publish-docker-image-release.yml
+++ b/.github/workflows/publish-docker-image-release.yml
@@ -18,7 +18,7 @@ jobs:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
env:
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
steps:
- name: Check out the repo
uses: actions/checkout@v3
@@ -82,6 +82,7 @@ jobs:
production-xdai-stg
production-polygon-supernets-stg
production-rsk-stg
+ production-immutable-stg
steps:
- uses: actions/checkout@v2
- name: Set Git config
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 000000000000..505db0421db5
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,5 @@
+repos:
+ - repo: https://github.com/gitleaks/gitleaks
+ rev: v8.17.0
+ hooks:
+ - id: gitleaks
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 811490b27479..8660565682db 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,21 +4,120 @@
### Features
+- [#8382](https://github.com/blockscout/blockscout/pull/8382) - Add sitemap.xml
+- [#8313](https://github.com/blockscout/blockscout/pull/8313) - Add batches to TokenInstance fetchers
+- [#8285](https://github.com/blockscout/blockscout/pull/8285), [#8399](https://github.com/blockscout/blockscout/pull/8399) - Add CG/CMC coin price sources
+- [#8181](https://github.com/blockscout/blockscout/pull/8181) - Insert current token balances placeholders along with historical
+- [#8210](https://github.com/blockscout/blockscout/pull/8210) - Drop address foreign keys
+- [#8292](https://github.com/blockscout/blockscout/pull/8292) - Add ETHEREUM_JSONRPC_WAIT_PER_TIMEOUT env var
+- [#8269](https://github.com/blockscout/blockscout/pull/8269) - Don't push back to sequence on catchup exception
+- [#8362](https://github.com/blockscout/blockscout/pull/8362), [#8398](https://github.com/blockscout/blockscout/pull/8398) - Drop token balances tokens foreign key
+
+### Fixes
+
+- [#8446](https://github.com/blockscout/blockscout/pull/8446) - Fix market cap calculation in case of CMC
+- [#8431](https://github.com/blockscout/blockscout/pull/8431) - Fix contracts' output decoding
+- [#8354](https://github.com/blockscout/blockscout/pull/8354) - Hotfix for proper addresses' tokens displaying
+- [#8350](https://github.com/blockscout/blockscout/pull/8350) - Add Base Mainnet support for tx actions
+- [#8282](https://github.com/blockscout/blockscout/pull/8282) - NFT fetcher improvements
+- [#8287](https://github.com/blockscout/blockscout/pull/8287) - Add separate hackney pool for TokenInstance fetchers
+- [#8293](https://github.com/blockscout/blockscout/pull/8293) - Add ETHEREUM_JSONRPC_TRACE_URL for Geth in docker-compose.yml
+- [#8240](https://github.com/blockscout/blockscout/pull/8240) - Refactor and fix paging params in API v2
+- [#8242](https://github.com/blockscout/blockscout/pull/8242) - Fixing visualizer service CORS issue when running docker-compose
+- [#8355](https://github.com/blockscout/blockscout/pull/8355) - Fix current token balances redefining
+
+### Chore
+
+- [#8442](https://github.com/blockscout/blockscout/pull/8442) - Unify burn address definition
+- [#8321](https://github.com/blockscout/blockscout/pull/8321) - Add curl into resulting Docker image
+- [#8319](https://github.com/blockscout/blockscout/pull/8319) - Add MIX_ENV: 'prod' to docker-compose
+- [#8281](https://github.com/blockscout/blockscout/pull/8281) - Planned removal of duplicate API endpoints: for CSV export and GraphQL
+
+
+ Dependencies version bumps
+
+
+
+## 5.2.2-beta
+
+### Features
+
+- [#8218](https://github.com/blockscout/blockscout/pull/8218) - Add `/api/v2/search/quick` method
+- [#8202](https://github.com/blockscout/blockscout/pull/8202) - Add `/api/v2/addresses/:address_hash/tabs-counters` endpoint
+- [#8156](https://github.com/blockscout/blockscout/pull/8156) - Add `is_verified_via_admin_panel` property to tokens table
+- [#8165](https://github.com/blockscout/blockscout/pull/8165), [#8201](https://github.com/blockscout/blockscout/pull/8201) - Add broadcast of updated address_current_token_balances
+- [#7952](https://github.com/blockscout/blockscout/pull/7952) - Add parsing constructor arguments for sourcify contracts
- [#6190](https://github.com/blockscout/blockscout/pull/6190) - Add EIP-1559 support to gas price oracle
+- [#7977](https://github.com/blockscout/blockscout/pull/7977) - GraphQL: extend schema with new field for existing objects
+- [#8158](https://github.com/blockscout/blockscout/pull/8158), [#8164](https://github.com/blockscout/blockscout/pull/8164) - Include unfetched balances in TokenBalanceOnDemand fetcher
### Fixes
+- [#8233](https://github.com/blockscout/blockscout/pull/8233) - Fix API v2 broken tx response
+- [#8147](https://github.com/blockscout/blockscout/pull/8147) - Switch sourcify tests from POA Sokol to Gnosis Chiado
+- [#8145](https://github.com/blockscout/blockscout/pull/8145) - Handle negative holders count in API v2
- [#8040](https://github.com/blockscout/blockscout/pull/8040) - Resolve issue with Docker image for Mac M1/M2
- [#8060](https://github.com/blockscout/blockscout/pull/8060) - Fix eth_getLogs API endpoint
- [#8082](https://github.com/blockscout/blockscout/pull/8082), [#8088](https://github.com/blockscout/blockscout/pull/8088) - Fix Rootstock charts API
+- [#7992](https://github.com/blockscout/blockscout/pull/7992) - Fix missing range insert
+- [#8022](https://github.com/blockscout/blockscout/pull/8022) - Don't add reorg block number to missing blocks
### Chore
-- [#8100](https://github.com/blockscout/blockscout/pull/8100) - Extend docker-compose configs with new config when front is running externally
+- [#8222](https://github.com/blockscout/blockscout/pull/8222) - docker-compose for new UI with external backend
+- [#8177](https://github.com/blockscout/blockscout/pull/8177) - Refactor address counter functions
+- [#8183](https://github.com/blockscout/blockscout/pull/8183) - Update frontend envs in order to pass their validation
+- [#8167](https://github.com/blockscout/blockscout/pull/8167) - Manage concurrency for Token and TokenBalance fetcher
+- [#8179](https://github.com/blockscout/blockscout/pull/8179) - Enhance nginx config
+- [#8146](https://github.com/blockscout/blockscout/pull/8146) - Add method_id to write methods in API v2 response
+- [#8105](https://github.com/blockscout/blockscout/pull/8105) - Extend API v1 with endpoints used by new UI
+- [#8104](https://github.com/blockscout/blockscout/pull/8104) - remove "TODO" from API v2 response
+- [#8100](https://github.com/blockscout/blockscout/pull/8100), [#8103](https://github.com/blockscout/blockscout/pull/8103) - Extend docker-compose configs with new config when front is running externally
+- [#8012](https://github.com/blockscout/blockscout/pull/8012) - API v2 smart-contract verification extended logging
Dependencies version bumps
+- [#7980](https://github.com/blockscout/blockscout/pull/7980) - Bump solc from 0.8.20 to 0.8.21 in /apps/explorer
+- [#7986](https://github.com/blockscout/blockscout/pull/7986) - Bump sass from 1.63.6 to 1.64.0 in /apps/block_scout_web/assets
+- [#8030](https://github.com/blockscout/blockscout/pull/8030) - Bump sweetalert2 from 11.7.18 to 11.7.20 in /apps/block_scout_web/assets
+- [#8029](https://github.com/blockscout/blockscout/pull/8029) - Bump viewerjs from 1.11.3 to 1.11.4 in /apps/block_scout_web/assets
+- [#8028](https://github.com/blockscout/blockscout/pull/8028) - Bump sass from 1.64.0 to 1.64.1 in /apps/block_scout_web/assets
+- [#8026](https://github.com/blockscout/blockscout/pull/8026) - Bump dataloader from 1.0.10 to 1.0.11
+- [#8036](https://github.com/blockscout/blockscout/pull/8036) - Bump ex_cldr_numbers from 2.31.1 to 2.31.3
+- [#8027](https://github.com/blockscout/blockscout/pull/8027) - Bump absinthe from 1.7.4 to 1.7.5
+- [#8035](https://github.com/blockscout/blockscout/pull/8035) - Bump wallaby from 0.30.4 to 0.30.5
+- [#8038](https://github.com/blockscout/blockscout/pull/8038) - Bump chart.js from 4.3.0 to 4.3.1 in /apps/block_scout_web/assets
+- [#8047](https://github.com/blockscout/blockscout/pull/8047) - Bump chart.js from 4.3.1 to 4.3.2 in /apps/block_scout_web/assets
+- [#8000](https://github.com/blockscout/blockscout/pull/8000) - Bump postcss from 8.4.26 to 8.4.27 in /apps/block_scout_web/assets
+- [#8052](https://github.com/blockscout/blockscout/pull/8052) - Bump @amplitude/analytics-browser from 2.1.2 to 2.1.3 in /apps/block_scout_web/assets
+- [#8054](https://github.com/blockscout/blockscout/pull/8054) - Bump jest-environment-jsdom from 29.6.1 to 29.6.2 in /apps/block_scout_web/assets
+- [#8063](https://github.com/blockscout/blockscout/pull/8063) - Bump eslint from 8.45.0 to 8.46.0 in /apps/block_scout_web/assets
+- [#8066](https://github.com/blockscout/blockscout/pull/8066) - Bump ex_json_schema from 0.9.3 to 0.10.1
+- [#8064](https://github.com/blockscout/blockscout/pull/8064) - Bump core-js from 3.31.1 to 3.32.0 in /apps/block_scout_web/assets
+- [#8053](https://github.com/blockscout/blockscout/pull/8053) - Bump jest from 29.6.1 to 29.6.2 in /apps/block_scout_web/assets
+- [#8065](https://github.com/blockscout/blockscout/pull/8065) - Bump eslint-plugin-import from 2.27.5 to 2.28.0 in /apps/block_scout_web/assets
+- [#8092](https://github.com/blockscout/blockscout/pull/8092) - Bump exvcr from 0.14.1 to 0.14.2
+- [#8091](https://github.com/blockscout/blockscout/pull/8091) - Bump sass from 1.64.1 to 1.64.2 in /apps/block_scout_web/assets
+- [#8114](https://github.com/blockscout/blockscout/pull/8114) - Bump ex_doc from 0.30.3 to 0.30.4
+- [#8115](https://github.com/blockscout/blockscout/pull/8115) - Bump chart.js from 4.3.2 to 4.3.3 in /apps/block_scout_web/assets
+- [#8116](https://github.com/blockscout/blockscout/pull/8116) - Bump @fortawesome/fontawesome-free from 6.4.0 to 6.4.2 in /apps/block_scout_web/assets
+- [#8142](https://github.com/blockscout/blockscout/pull/8142) - Bump sobelow from 0.12.2 to 0.13.0
+- [#8141](https://github.com/blockscout/blockscout/pull/8141) - Bump @babel/core from 7.22.9 to 7.22.10 in /apps/block_scout_web/assets
+- [#8140](https://github.com/blockscout/blockscout/pull/8140) - Bump @babel/preset-env from 7.22.9 to 7.22.10 in /apps/block_scout_web/assets
+- [#8160](https://github.com/blockscout/blockscout/pull/8160) - Bump exvcr from 0.14.2 to 0.14.3
+- [#8159](https://github.com/blockscout/blockscout/pull/8159) - Bump luxon from 3.3.0 to 3.4.0 in /apps/block_scout_web/assets
+- [#8169](https://github.com/blockscout/blockscout/pull/8169) - Bump sass from 1.64.2 to 1.65.1 in /apps/block_scout_web/assets
+- [#8170](https://github.com/blockscout/blockscout/pull/8170) - Bump sweetalert2 from 11.7.20 to 11.7.22 in /apps/block_scout_web/assets
+- [#8188](https://github.com/blockscout/blockscout/pull/8188) - Bump eslint from 8.46.0 to 8.47.0 in /apps/block_scout_web/assets
+- [#8204](https://github.com/blockscout/blockscout/pull/8204) - Bump ex_doc from 0.30.4 to 0.30.5
+- [#8207](https://github.com/blockscout/blockscout/pull/8207) - Bump wallaby from 0.30.5 to 0.30.6
+- [#8212](https://github.com/blockscout/blockscout/pull/8212) - Bump sweetalert2 from 11.7.22 to 11.7.23 in /apps/block_scout_web/assets
+- [#8203](https://github.com/blockscout/blockscout/pull/8203) - Bump autoprefixer from 10.4.14 to 10.4.15 in /apps/block_scout_web/assets
+- [#8214](https://github.com/blockscout/blockscout/pull/8214) - Bump @amplitude/analytics-browser from 2.1.3 to 2.2.0 in /apps/block_scout_web/assets
+- [#8225](https://github.com/blockscout/blockscout/pull/8225) - Bump postcss from 8.4.27 to 8.4.28 in /apps/block_scout_web/assets
+- [#8224](https://github.com/blockscout/blockscout/pull/8224) - Bump gettext from 0.22.3 to 0.23.1
+
## 5.2.1-beta
@@ -42,6 +141,7 @@
### Fixes
+- [#8187](https://github.com/blockscout/blockscout/pull/8187) - API v1 500 error convert to 404, if requested path is incorrect
- [#7852](https://github.com/blockscout/blockscout/pull/7852) - Token balances refactoring & fixes
- [#7872](https://github.com/blockscout/blockscout/pull/7872) - Fix pending gas price in pending tx
- [#7875](https://github.com/blockscout/blockscout/pull/7875) - Fix twin compiler version
@@ -94,7 +194,7 @@
- [#7867](https://github.com/blockscout/blockscout/pull/7867) - Bump postcss from 8.4.24 to 8.4.25 in /apps/block_scout_web/assets
- [#7871](https://github.com/blockscout/blockscout/pull/7871) - Bump @babel/core from 7.22.6 to 7.22.8 in /apps/block_scout_web/assets
- [#7868](https://github.com/blockscout/blockscout/pull/7868) - Bump jest-environment-jsdom from 29.6.0 to 29.6.1 in /apps/block_scout_web/assets
-- [#7866](https://github.com/blockscout/blockscout/pull/7866) - Bump @babel/preset-env from 7.22.6 to 7.22.7 in /apps/block_scout_web/assets
+- [#7866](https://github.com/blockscout/blockscout/pull/7866) - Bump @babel/preset-env from 7.22.6 to 7.22.7 in /apps/block_scout_web/assets
- [#7869](https://github.com/blockscout/blockscout/pull/7869) - Bump core-js from 3.31.0 to 3.31.1 in /apps/block_scout_web/assets
- [#7884](https://github.com/blockscout/blockscout/pull/7884) - Bump ecto from 3.10.2 to 3.10.3
- [#7882](https://github.com/blockscout/blockscout/pull/7882) - Bump jason from 1.4.0 to 1.4.1
@@ -221,7 +321,7 @@
- [#7702](https://github.com/blockscout/blockscout/pull/7702) - Bump @amplitude/analytics-browser from 1.10.8 to 1.11.0 in /apps/block_scout_web/assets
- [#7708](https://github.com/blockscout/blockscout/pull/7708) - Bump phoenix_pubsub from 2.1.2 to 2.1.3
- [#7707](https://github.com/blockscout/blockscout/pull/7707) - Bump @amplitude/analytics-browser from 1.11.0 to 2.0.0 in /apps/block_scout_web/assets
-- [#7706](https://github.com/blockscout/blockscout/pull/7706) - Bump webpack from 5.86.0 to 5.87.0 in /apps/block_scout_web/assets
+- [#7706](https://github.com/blockscout/blockscout/pull/7706) - Bump webpack from 5.86.0 to 5.87.0 in /apps/block_scout_web/assets
- [#7705](https://github.com/blockscout/blockscout/pull/7705) - Bump sass from 1.63.3 to 1.63.4 in /apps/block_scout_web/assets
- [#7714](https://github.com/blockscout/blockscout/pull/7714) - Bump ex_cldr_units from 3.16.1 to 3.16.2
- [#7748](https://github.com/blockscout/blockscout/pull/7748) - Bump mock from 0.3.7 to 0.3.8
diff --git a/apps/block_scout_web/assets/css/components/_tile.scss b/apps/block_scout_web/assets/css/components/_tile.scss
index c1a741f460bb..209008e240a5 100644
--- a/apps/block_scout_web/assets/css/components/_tile.scss
+++ b/apps/block_scout_web/assets/css/components/_tile.scss
@@ -184,6 +184,12 @@ $tile-body-a-color: #5959d8 !default;
color: $tile-body-a-color;
}
+ &[class*="status--error"] {
+ .tile-transaction-type-block {
+ word-break: break-word;
+ }
+ }
+
.tile-body {
a {
color: $tile-body-a-color;
@@ -353,8 +359,8 @@ $tile-body-a-color: #5959d8 !default;
padding-right: 6px;
}
}
- .tile-type-block {
- overflow: hidden;
+ .tile-type-block {
+ overflow: hidden;
}
.row {
@include media-breakpoint-down(lg) {
diff --git a/apps/block_scout_web/assets/package-lock.json b/apps/block_scout_web/assets/package-lock.json
index 99113b248e40..5e1b1f86300a 100644
--- a/apps/block_scout_web/assets/package-lock.json
+++ b/apps/block_scout_web/assets/package-lock.json
@@ -7,24 +7,24 @@
"name": "blockscout",
"license": "GPL-3.0",
"dependencies": {
- "@amplitude/analytics-browser": "^2.1.3",
- "@fortawesome/fontawesome-free": "^6.4.0",
+ "@amplitude/analytics-browser": "^2.2.3",
+ "@fortawesome/fontawesome-free": "^6.4.2",
"@tarekraafat/autocomplete.js": "^10.2.7",
"@walletconnect/web3-provider": "^1.8.0",
- "assert": "^2.0.0",
- "bignumber.js": "^9.1.1",
+ "assert": "^2.1.0",
+ "bignumber.js": "^9.1.2",
"bootstrap": "^4.6.0",
- "chart.js": "^4.3.2",
+ "chart.js": "^4.4.0",
"chartjs-adapter-luxon": "^1.3.1",
"clipboard": "^2.0.11",
- "core-js": "^3.32.0",
+ "core-js": "^3.32.2",
"crypto-browserify": "^3.12.0",
"dropzone": "^5.9.3",
"eth-net-props": "^1.0.41",
"highlight.js": "^11.8.0",
"https-browserify": "^1.0.0",
"humps": "^2.0.1",
- "jquery": "^3.7.0",
+ "jquery": "^3.7.1",
"js-cookie": "^3.0.5",
"lodash.debounce": "^4.0.8",
"lodash.differenceby": "^4.8.0",
@@ -44,7 +44,7 @@
"lodash.omit": "^4.5.0",
"lodash.rangeright": "^4.2.0",
"lodash.reduce": "^4.6.0",
- "luxon": "^3.3.0",
+ "luxon": "^3.4.3",
"malihu-custom-scrollbar-plugin": "3.1.5",
"mixpanel-browser": "^2.47.0",
"moment": "^2.29.4",
@@ -54,42 +54,42 @@
"path-parser": "^6.1.0",
"phoenix": "file:../../../deps/phoenix",
"phoenix_html": "file:../../../deps/phoenix_html",
- "photoswipe": "^5.3.8",
+ "photoswipe": "^5.4.0",
"pikaday": "^1.8.2",
"popper.js": "^1.14.7",
"reduce-reducers": "^1.0.4",
"redux": "^4.2.1",
"stream-browserify": "^3.0.0",
"stream-http": "^3.1.1",
- "sweetalert2": "^11.7.20",
+ "sweetalert2": "^11.7.27",
"urijs": "^1.19.11",
- "url": "^0.11.1",
+ "url": "^0.11.2",
"util": "^0.12.5",
- "viewerjs": "^1.11.4",
+ "viewerjs": "^1.11.5",
"web3": "^1.10.0",
"web3modal": "^1.9.12",
"xss": "^1.0.14"
},
"devDependencies": {
- "@babel/core": "^7.22.9",
- "@babel/preset-env": "^7.22.9",
- "autoprefixer": "^10.4.14",
+ "@babel/core": "^7.22.17",
+ "@babel/preset-env": "^7.22.15",
+ "autoprefixer": "^10.4.15",
"babel-loader": "^9.1.3",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^5.2.7",
"css-minimizer-webpack-plugin": "^5.0.1",
- "eslint": "^8.46.0",
+ "eslint": "^8.49.0",
"eslint-config-standard": "^17.1.0",
- "eslint-plugin-import": "^2.28.0",
+ "eslint-plugin-import": "^2.28.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"file-loader": "^6.2.0",
- "jest": "^29.6.2",
- "jest-environment-jsdom": "^29.6.2",
+ "jest": "^29.6.4",
+ "jest-environment-jsdom": "^29.6.4",
"mini-css-extract-plugin": "^2.7.6",
- "postcss": "^8.4.27",
+ "postcss": "^8.4.29",
"postcss-loader": "^7.3.3",
- "sass": "^1.64.2",
+ "sass": "^1.66.1",
"sass-loader": "^13.3.2",
"style-loader": "^3.3.3",
"webpack": "^5.88.2",
@@ -116,15 +116,15 @@
}
},
"node_modules/@amplitude/analytics-browser": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.1.3.tgz",
- "integrity": "sha512-DQqjyRdkmUEHxGBuMEDOPNTssE0of+xZa2WtjmsxEZcIhtUSjViEJfRMg6Eup8O72m+7S+wQO3psfQecuZ1OnQ==",
- "dependencies": {
- "@amplitude/analytics-client-common": "^2.0.4",
- "@amplitude/analytics-core": "^2.0.3",
- "@amplitude/analytics-types": "^2.1.1",
- "@amplitude/plugin-page-view-tracking-browser": "^2.0.5",
- "@amplitude/plugin-web-attribution-browser": "^2.0.5",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.2.3.tgz",
+ "integrity": "sha512-vuKG8/jqtsAFe0xK0ZGtXDxH7oPx989VIoCpUi97bkfxholySCNHjVMd5Q8D4Mqm/3eDH7YZhkFwEb0JFyCAfA==",
+ "dependencies": {
+ "@amplitude/analytics-client-common": "^2.0.5",
+ "@amplitude/analytics-core": "^2.0.4",
+ "@amplitude/analytics-types": "^2.1.2",
+ "@amplitude/plugin-page-view-tracking-browser": "^2.0.9",
+ "@amplitude/plugin-web-attribution-browser": "^2.0.9",
"tslib": "^2.4.1"
}
},
@@ -134,75 +134,75 @@
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA=="
},
"node_modules/@amplitude/analytics-client-common": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-client-common/-/analytics-client-common-2.0.4.tgz",
- "integrity": "sha512-X0+zE8sODcQ2ioj9ZB98Gr/9FCRDiJuSixefaLrfng/4x5VwHK0if8biCqqBHXu6HlMpeMFrCyiABUTDT87QVA==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-client-common/-/analytics-client-common-2.0.5.tgz",
+ "integrity": "sha512-5BrGl188h4Ayx4Z2e1x4I3Z8ykC+ap65cy8ShBByiaBBrR40gnXSuLZR7xeex3lvTp2b5lMBcVCqArdRbeZrgQ==",
"dependencies": {
"@amplitude/analytics-connector": "^1.4.8",
- "@amplitude/analytics-core": "^2.0.3",
- "@amplitude/analytics-types": "^2.1.1",
+ "@amplitude/analytics-core": "^2.0.4",
+ "@amplitude/analytics-types": "^2.1.2",
"tslib": "^2.4.1"
}
},
"node_modules/@amplitude/analytics-client-common/node_modules/tslib": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
- "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/@amplitude/analytics-connector": {
- "version": "1.4.8",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.4.8.tgz",
- "integrity": "sha512-dFW7c7Wb6Ng7vbmzwbaXZSpqfBx37ukamJV9ErFYYS8vGZK/Hkbt3M7fZHBI4WFU6CCwakr2ZXPme11uGPYWkQ=="
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.5.0.tgz",
+ "integrity": "sha512-T8mOYzB9RRxckzhL0NTHwdge9xuFxXEOplC8B1Y3UX3NHa3BLh7DlBUZlCOwQgMc2nxDfnSweDL5S3bhC+W90g=="
},
"node_modules/@amplitude/analytics-core": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.0.3.tgz",
- "integrity": "sha512-tpD1gCmPpzPNPumQT1ecOJtuan5OsQdKp9AX8YKc7t1/K3xHzGo3FH3JvdaAJVYYWeZV40bp/JL6wJiYIzyZjA==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.0.4.tgz",
+ "integrity": "sha512-AM4g1ucaAJuFqaMBg7FiqwKHveyV2QpZ3yPxw3OxNCgZz2QmqeYE1bp47x4FlfzNsoGyuYqRKs1mCbmGobAYWA==",
"dependencies": {
- "@amplitude/analytics-types": "^2.1.1",
+ "@amplitude/analytics-types": "^2.1.2",
"tslib": "^2.4.1"
}
},
"node_modules/@amplitude/analytics-core/node_modules/tslib": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
- "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/@amplitude/analytics-types": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-2.1.1.tgz",
- "integrity": "sha512-H3vebPR9onRdp0WzAZmI/4qmAE903uLOd2ZfMeHsVc1zaFTTCk46SoCuV4IrlF+VILrDw9Fy6gC9yl5N2PZcJQ=="
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-2.1.2.tgz",
+ "integrity": "sha512-ASKwH9g+5gglTHr7h7miK8J/ofIzuEtGRDCjnZAtRbE6+laoOfCLYPPJXMYz0k1x+rIhLO/6I6WWjT7zchmpyA=="
},
"node_modules/@amplitude/plugin-page-view-tracking-browser": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.0.5.tgz",
- "integrity": "sha512-dmW2dckEaI/Z9DQ+3RNJU32cF4c6iYsFamvu73LDu/sttE0gmqWDRvZhh/B7j/VDxYmobySMUEV1kinjbn8vXg==",
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.0.9.tgz",
+ "integrity": "sha512-OjhAxvQ52lDcRap2sjUbYEcSM6bzeDa6SdBx6vCaeXswvjafcH9LeDPawLUHgaqvQJiAhA7lxrQ7ThfH0P6c0g==",
"dependencies": {
- "@amplitude/analytics-client-common": "^2.0.4",
- "@amplitude/analytics-types": "^2.1.1",
+ "@amplitude/analytics-client-common": "^2.0.5",
+ "@amplitude/analytics-types": "^2.1.2",
"tslib": "^2.4.1"
}
},
"node_modules/@amplitude/plugin-page-view-tracking-browser/node_modules/tslib": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
- "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/@amplitude/plugin-web-attribution-browser": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@amplitude/plugin-web-attribution-browser/-/plugin-web-attribution-browser-2.0.5.tgz",
- "integrity": "sha512-apLZ4XV0Xbq4E3sHY25zubiyqHX9IWupWk+RTMNqHZJyhC7JuA3ttVFU3p0fWM/XeumITMRPL2NcG9R9WO4y9Q==",
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/@amplitude/plugin-web-attribution-browser/-/plugin-web-attribution-browser-2.0.9.tgz",
+ "integrity": "sha512-QrNgieAEXEBbtnsxYzfeJl2U/5XwCCvO3Dg0hntAtnTdu1A3HlN5ItRtoHg0jGBbu4jpSbvag72UlkCotqJ+Yg==",
"dependencies": {
- "@amplitude/analytics-client-common": "^2.0.4",
- "@amplitude/analytics-core": "^2.0.3",
- "@amplitude/analytics-types": "^2.1.1",
+ "@amplitude/analytics-client-common": "^2.0.5",
+ "@amplitude/analytics-core": "^2.0.4",
+ "@amplitude/analytics-types": "^2.1.2",
"tslib": "^2.4.1"
}
},
"node_modules/@amplitude/plugin-web-attribution-browser/node_modules/tslib": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
- "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/@ampproject/remapping": {
"version": "2.2.0",
@@ -229,11 +229,12 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
- "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dependencies": {
- "@babel/highlight": "^7.22.5"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
@@ -248,24 +249,24 @@
}
},
"node_modules/@babel/core": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz",
- "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==",
+ "version": "7.22.17",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.17.tgz",
+ "integrity": "sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ==",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.9",
- "@babel/helper-compilation-targets": "^7.22.9",
- "@babel/helper-module-transforms": "^7.22.9",
- "@babel/helpers": "^7.22.6",
- "@babel/parser": "^7.22.7",
- "@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.8",
- "@babel/types": "^7.22.5",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.22.15",
+ "@babel/helper-compilation-targets": "^7.22.15",
+ "@babel/helper-module-transforms": "^7.22.17",
+ "@babel/helpers": "^7.22.15",
+ "@babel/parser": "^7.22.16",
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.22.17",
+ "@babel/types": "^7.22.17",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
- "json5": "^2.2.2",
+ "json5": "^2.2.3",
"semver": "^6.3.1"
},
"engines": {
@@ -277,11 +278,11 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz",
- "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz",
+ "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==",
"dependencies": {
- "@babel/types": "^7.22.5",
+ "@babel/types": "^7.22.15",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -314,21 +315,18 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz",
- "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
+ "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
"dependencies": {
"@babel/compat-data": "^7.22.9",
- "@babel/helper-validator-option": "^7.22.5",
+ "@babel/helper-validator-option": "^7.22.15",
"browserslist": "^4.21.9",
"lru-cache": "^5.1.1",
"semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
@@ -345,9 +343,9 @@
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
},
"node_modules/@babel/helper-create-class-features-plugin": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.5.tgz",
- "integrity": "sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.11.tgz",
+ "integrity": "sha512-y1grdYL4WzmUDBRGK0pDbIoFd7UZKoDurDzWEoNMYoj1EL+foGRQNyPWDcC+YyegN5y1DUsFFmzjGijB3nSVAQ==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
@@ -355,10 +353,10 @@
"@babel/helper-function-name": "^7.22.5",
"@babel/helper-member-expression-to-functions": "^7.22.5",
"@babel/helper-optimise-call-expression": "^7.22.5",
- "@babel/helper-replace-supers": "^7.22.5",
+ "@babel/helper-replace-supers": "^7.22.9",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.5",
- "semver": "^6.3.0"
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
@@ -444,26 +442,26 @@
}
},
"node_modules/@babel/helper-module-imports": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz",
- "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
+ "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz",
- "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==",
+ "version": "7.22.17",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz",
+ "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==",
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-module-imports": "^7.22.5",
+ "@babel/helper-module-imports": "^7.22.15",
"@babel/helper-simple-access": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/helper-validator-identifier": "^7.22.5"
+ "@babel/helper-validator-identifier": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
@@ -493,15 +491,14 @@
}
},
"node_modules/@babel/helper-remap-async-to-generator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.5.tgz",
- "integrity": "sha512-cU0Sq1Rf4Z55fgz7haOakIyM7+x/uCFwXpLPaeRzfoUtAEAuUZjZvFPjL/rk5rW693dIgn2hng1W7xbT7lWT4g==",
+ "version": "7.22.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz",
+ "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-wrap-function": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/helper-wrap-function": "^7.22.9"
},
"engines": {
"node": ">=6.9.0"
@@ -511,20 +508,20 @@
}
},
"node_modules/@babel/helper-replace-supers": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.5.tgz",
- "integrity": "sha512-aLdNM5I3kdI/V9xGNyKSF3X/gTyMUBohTZ+/3QdQKAA9vxIiy12E+8E2HoOP1/DjeqU+g6as35QHJNMDDYpuCg==",
+ "version": "7.22.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz",
+ "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==",
"dev": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-member-expression-to-functions": "^7.22.5",
- "@babel/helper-optimise-call-expression": "^7.22.5",
- "@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/helper-optimise-call-expression": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-simple-access": {
@@ -570,56 +567,55 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
- "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz",
+ "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-option": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz",
- "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
+ "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-wrap-function": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.5.tgz",
- "integrity": "sha512-bYqLIBSEshYcYQyfks8ewYA8S30yaGSeRslcvKMvoUk6HHPySbxHq9YRi6ghhzEU+yhQv9bP/jXnygkStOcqZw==",
+ "version": "7.22.10",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz",
+ "integrity": "sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ==",
"dev": true,
"dependencies": {
"@babel/helper-function-name": "^7.22.5",
"@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.22.10"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz",
- "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz",
+ "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==",
"dependencies": {
- "@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.6",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.22.15",
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/highlight": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
- "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz",
+ "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==",
"dependencies": {
"@babel/helper-validator-identifier": "^7.22.5",
- "chalk": "^2.0.0",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"engines": {
@@ -627,9 +623,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.22.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
- "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
+ "version": "7.22.16",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
+ "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -638,9 +634,9 @@
}
},
"node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz",
- "integrity": "sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz",
+ "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -653,14 +649,14 @@
}
},
"node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz",
- "integrity": "sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz",
+ "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
- "@babel/plugin-transform-optional-chaining": "^7.22.5"
+ "@babel/plugin-transform-optional-chaining": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
@@ -681,22 +677,6 @@
"@babel/core": "^7.0.0-0"
}
},
- "node_modules/@babel/plugin-proposal-unicode-property-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz",
- "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==",
- "dev": true,
- "dependencies": {
- "@babel/helper-create-regexp-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
"node_modules/@babel/plugin-syntax-async-generators": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
@@ -990,14 +970,14 @@
}
},
"node_modules/@babel/plugin-transform-async-generator-functions": {
- "version": "7.22.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz",
- "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz",
+ "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==",
"dev": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
- "@babel/helper-remap-async-to-generator": "^7.22.5",
+ "@babel/helper-remap-async-to-generator": "^7.22.9",
"@babel/plugin-syntax-async-generators": "^7.8.4"
},
"engines": {
@@ -1040,9 +1020,9 @@
}
},
"node_modules/@babel/plugin-transform-block-scoping": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz",
- "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz",
+ "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1071,12 +1051,12 @@
}
},
"node_modules/@babel/plugin-transform-class-static-block": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz",
- "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz",
+ "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==",
"dev": true,
"dependencies": {
- "@babel/helper-create-class-features-plugin": "^7.22.5",
+ "@babel/helper-create-class-features-plugin": "^7.22.11",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-class-static-block": "^7.14.5"
},
@@ -1088,18 +1068,18 @@
}
},
"node_modules/@babel/plugin-transform-classes": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz",
- "integrity": "sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz",
+ "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-compilation-targets": "^7.22.6",
+ "@babel/helper-compilation-targets": "^7.22.15",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
"@babel/helper-optimise-call-expression": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
- "@babel/helper-replace-supers": "^7.22.5",
+ "@babel/helper-replace-supers": "^7.22.9",
"@babel/helper-split-export-declaration": "^7.22.6",
"globals": "^11.1.0"
},
@@ -1127,9 +1107,9 @@
}
},
"node_modules/@babel/plugin-transform-destructuring": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz",
- "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz",
+ "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1173,9 +1153,9 @@
}
},
"node_modules/@babel/plugin-transform-dynamic-import": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz",
- "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz",
+ "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1205,9 +1185,9 @@
}
},
"node_modules/@babel/plugin-transform-export-namespace-from": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz",
- "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz",
+ "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1221,9 +1201,9 @@
}
},
"node_modules/@babel/plugin-transform-for-of": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz",
- "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz",
+ "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1253,9 +1233,9 @@
}
},
"node_modules/@babel/plugin-transform-json-strings": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz",
- "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz",
+ "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1284,9 +1264,9 @@
}
},
"node_modules/@babel/plugin-transform-logical-assignment-operators": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz",
- "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz",
+ "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1331,12 +1311,12 @@
}
},
"node_modules/@babel/plugin-transform-modules-commonjs": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz",
- "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz",
+ "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==",
"dev": true,
"dependencies": {
- "@babel/helper-module-transforms": "^7.22.5",
+ "@babel/helper-module-transforms": "^7.22.15",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-simple-access": "^7.22.5"
},
@@ -1348,13 +1328,13 @@
}
},
"node_modules/@babel/plugin-transform-modules-systemjs": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz",
- "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz",
+ "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==",
"dev": true,
"dependencies": {
"@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-module-transforms": "^7.22.5",
+ "@babel/helper-module-transforms": "^7.22.9",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.5"
},
@@ -1413,9 +1393,9 @@
}
},
"node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz",
- "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz",
+ "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1429,9 +1409,9 @@
}
},
"node_modules/@babel/plugin-transform-numeric-separator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz",
- "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz",
+ "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1445,16 +1425,16 @@
}
},
"node_modules/@babel/plugin-transform-object-rest-spread": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz",
- "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz",
+ "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==",
"dev": true,
"dependencies": {
- "@babel/compat-data": "^7.22.5",
- "@babel/helper-compilation-targets": "^7.22.5",
+ "@babel/compat-data": "^7.22.9",
+ "@babel/helper-compilation-targets": "^7.22.15",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-transform-parameters": "^7.22.5"
+ "@babel/plugin-transform-parameters": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
@@ -1480,9 +1460,9 @@
}
},
"node_modules/@babel/plugin-transform-optional-catch-binding": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz",
- "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz",
+ "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1496,9 +1476,9 @@
}
},
"node_modules/@babel/plugin-transform-optional-chaining": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz",
- "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz",
+ "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -1513,9 +1493,9 @@
}
},
"node_modules/@babel/plugin-transform-parameters": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz",
- "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz",
+ "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1544,13 +1524,13 @@
}
},
"node_modules/@babel/plugin-transform-private-property-in-object": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz",
- "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz",
+ "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-create-class-features-plugin": "^7.22.5",
+ "@babel/helper-create-class-features-plugin": "^7.22.11",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
},
@@ -1577,13 +1557,13 @@
}
},
"node_modules/@babel/plugin-transform-regenerator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz",
- "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==",
+ "version": "7.22.10",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz",
+ "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
- "regenerator-transform": "^0.15.1"
+ "regenerator-transform": "^0.15.2"
},
"engines": {
"node": ">=6.9.0"
@@ -1715,9 +1695,9 @@
}
},
"node_modules/@babel/plugin-transform-unicode-escapes": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz",
- "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==",
+ "version": "7.22.10",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz",
+ "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -1778,17 +1758,17 @@
}
},
"node_modules/@babel/preset-env": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz",
- "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.15.tgz",
+ "integrity": "sha512-tZFHr54GBkHk6hQuVA8w4Fmq+MSPsfvMG0vPnOYyTnJpyfMqybL8/MbNCPRT9zc2KBO2pe4tq15g6Uno4Jpoag==",
"dev": true,
"dependencies": {
"@babel/compat-data": "^7.22.9",
- "@babel/helper-compilation-targets": "^7.22.9",
+ "@babel/helper-compilation-targets": "^7.22.15",
"@babel/helper-plugin-utils": "^7.22.5",
- "@babel/helper-validator-option": "^7.22.5",
- "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5",
- "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5",
+ "@babel/helper-validator-option": "^7.22.15",
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15",
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15",
"@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
"@babel/plugin-syntax-async-generators": "^7.8.4",
"@babel/plugin-syntax-class-properties": "^7.12.13",
@@ -1809,58 +1789,58 @@
"@babel/plugin-syntax-top-level-await": "^7.14.5",
"@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
"@babel/plugin-transform-arrow-functions": "^7.22.5",
- "@babel/plugin-transform-async-generator-functions": "^7.22.7",
+ "@babel/plugin-transform-async-generator-functions": "^7.22.15",
"@babel/plugin-transform-async-to-generator": "^7.22.5",
"@babel/plugin-transform-block-scoped-functions": "^7.22.5",
- "@babel/plugin-transform-block-scoping": "^7.22.5",
+ "@babel/plugin-transform-block-scoping": "^7.22.15",
"@babel/plugin-transform-class-properties": "^7.22.5",
- "@babel/plugin-transform-class-static-block": "^7.22.5",
- "@babel/plugin-transform-classes": "^7.22.6",
+ "@babel/plugin-transform-class-static-block": "^7.22.11",
+ "@babel/plugin-transform-classes": "^7.22.15",
"@babel/plugin-transform-computed-properties": "^7.22.5",
- "@babel/plugin-transform-destructuring": "^7.22.5",
+ "@babel/plugin-transform-destructuring": "^7.22.15",
"@babel/plugin-transform-dotall-regex": "^7.22.5",
"@babel/plugin-transform-duplicate-keys": "^7.22.5",
- "@babel/plugin-transform-dynamic-import": "^7.22.5",
+ "@babel/plugin-transform-dynamic-import": "^7.22.11",
"@babel/plugin-transform-exponentiation-operator": "^7.22.5",
- "@babel/plugin-transform-export-namespace-from": "^7.22.5",
- "@babel/plugin-transform-for-of": "^7.22.5",
+ "@babel/plugin-transform-export-namespace-from": "^7.22.11",
+ "@babel/plugin-transform-for-of": "^7.22.15",
"@babel/plugin-transform-function-name": "^7.22.5",
- "@babel/plugin-transform-json-strings": "^7.22.5",
+ "@babel/plugin-transform-json-strings": "^7.22.11",
"@babel/plugin-transform-literals": "^7.22.5",
- "@babel/plugin-transform-logical-assignment-operators": "^7.22.5",
+ "@babel/plugin-transform-logical-assignment-operators": "^7.22.11",
"@babel/plugin-transform-member-expression-literals": "^7.22.5",
"@babel/plugin-transform-modules-amd": "^7.22.5",
- "@babel/plugin-transform-modules-commonjs": "^7.22.5",
- "@babel/plugin-transform-modules-systemjs": "^7.22.5",
+ "@babel/plugin-transform-modules-commonjs": "^7.22.15",
+ "@babel/plugin-transform-modules-systemjs": "^7.22.11",
"@babel/plugin-transform-modules-umd": "^7.22.5",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5",
"@babel/plugin-transform-new-target": "^7.22.5",
- "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5",
- "@babel/plugin-transform-numeric-separator": "^7.22.5",
- "@babel/plugin-transform-object-rest-spread": "^7.22.5",
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11",
+ "@babel/plugin-transform-numeric-separator": "^7.22.11",
+ "@babel/plugin-transform-object-rest-spread": "^7.22.15",
"@babel/plugin-transform-object-super": "^7.22.5",
- "@babel/plugin-transform-optional-catch-binding": "^7.22.5",
- "@babel/plugin-transform-optional-chaining": "^7.22.6",
- "@babel/plugin-transform-parameters": "^7.22.5",
+ "@babel/plugin-transform-optional-catch-binding": "^7.22.11",
+ "@babel/plugin-transform-optional-chaining": "^7.22.15",
+ "@babel/plugin-transform-parameters": "^7.22.15",
"@babel/plugin-transform-private-methods": "^7.22.5",
- "@babel/plugin-transform-private-property-in-object": "^7.22.5",
+ "@babel/plugin-transform-private-property-in-object": "^7.22.11",
"@babel/plugin-transform-property-literals": "^7.22.5",
- "@babel/plugin-transform-regenerator": "^7.22.5",
+ "@babel/plugin-transform-regenerator": "^7.22.10",
"@babel/plugin-transform-reserved-words": "^7.22.5",
"@babel/plugin-transform-shorthand-properties": "^7.22.5",
"@babel/plugin-transform-spread": "^7.22.5",
"@babel/plugin-transform-sticky-regex": "^7.22.5",
"@babel/plugin-transform-template-literals": "^7.22.5",
"@babel/plugin-transform-typeof-symbol": "^7.22.5",
- "@babel/plugin-transform-unicode-escapes": "^7.22.5",
+ "@babel/plugin-transform-unicode-escapes": "^7.22.10",
"@babel/plugin-transform-unicode-property-regex": "^7.22.5",
"@babel/plugin-transform-unicode-regex": "^7.22.5",
"@babel/plugin-transform-unicode-sets-regex": "^7.22.5",
- "@babel/preset-modules": "^0.1.5",
- "@babel/types": "^7.22.5",
- "babel-plugin-polyfill-corejs2": "^0.4.4",
- "babel-plugin-polyfill-corejs3": "^0.8.2",
- "babel-plugin-polyfill-regenerator": "^0.5.1",
+ "@babel/preset-modules": "0.1.6-no-external-plugins",
+ "@babel/types": "^7.22.15",
+ "babel-plugin-polyfill-corejs2": "^0.4.5",
+ "babel-plugin-polyfill-corejs3": "^0.8.3",
+ "babel-plugin-polyfill-regenerator": "^0.5.2",
"core-js-compat": "^3.31.0",
"semver": "^6.3.1"
},
@@ -1872,9 +1852,9 @@
}
},
"node_modules/@babel/preset-env/node_modules/@babel/helper-define-polyfill-provider": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz",
- "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==",
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz",
+ "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==",
"dev": true,
"dependencies": {
"@babel/helper-compilation-targets": "^7.22.6",
@@ -1884,49 +1864,47 @@
"resolve": "^1.14.2"
},
"peerDependencies": {
- "@babel/core": "^7.4.0-0"
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
"node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs2": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.4.tgz",
- "integrity": "sha512-9WeK9snM1BfxB38goUEv2FLnA6ja07UMfazFHzCXUb3NyDZAwfXvQiURQ6guTTMeHcOsdknULm1PDhs4uWtKyA==",
+ "version": "0.4.5",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz",
+ "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==",
"dev": true,
"dependencies": {
"@babel/compat-data": "^7.22.6",
- "@babel/helper-define-polyfill-provider": "^0.4.1",
- "@nicolo-ribaudo/semver-v6": "^6.3.3"
+ "@babel/helper-define-polyfill-provider": "^0.4.2",
+ "semver": "^6.3.1"
},
"peerDependencies": {
- "@babel/core": "^7.0.0-0"
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
"node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-regenerator": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.1.tgz",
- "integrity": "sha512-L8OyySuI6OSQ5hFy9O+7zFjyr4WhAfRjLIOkhQGYl+emwJkd/S4XXT1JpfrgR1jrQ1NcGiOh+yAdGlF8pnC3Jw==",
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz",
+ "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==",
"dev": true,
"dependencies": {
- "@babel/helper-define-polyfill-provider": "^0.4.1"
+ "@babel/helper-define-polyfill-provider": "^0.4.2"
},
"peerDependencies": {
- "@babel/core": "^7.0.0-0"
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
"node_modules/@babel/preset-modules": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz",
- "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==",
+ "version": "0.1.6-no-external-plugins",
+ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
+ "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
- "@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
- "@babel/plugin-transform-dotall-regex": "^7.4.4",
"@babel/types": "^7.4.4",
"esutils": "^2.0.2"
},
"peerDependencies": {
- "@babel/core": "^7.0.0-0"
+ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0"
}
},
"node_modules/@babel/regjsgen": {
@@ -1947,31 +1925,31 @@
}
},
"node_modules/@babel/template": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
- "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dependencies": {
- "@babel/code-frame": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.22.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
- "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
+ "version": "7.22.17",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.17.tgz",
+ "integrity": "sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg==",
"dependencies": {
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.7",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.22.15",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.22.7",
- "@babel/types": "^7.22.5",
+ "@babel/parser": "^7.22.16",
+ "@babel/types": "^7.22.17",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -1980,12 +1958,12 @@
}
},
"node_modules/@babel/types": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
- "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
+ "version": "7.22.17",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz",
+ "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==",
"dependencies": {
"@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.15",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -2055,9 +2033,9 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz",
- "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+ "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
@@ -2084,9 +2062,9 @@
"dev": true
},
"node_modules/@eslint/eslintrc/node_modules/globals": {
- "version": "13.20.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
- "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "version": "13.21.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
+ "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
@@ -2123,9 +2101,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz",
- "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==",
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz",
+ "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -2524,18 +2502,18 @@
}
},
"node_modules/@fortawesome/fontawesome-free": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.0.tgz",
- "integrity": "sha512-0NyytTlPJwB/BF5LtRV8rrABDbe3TdTXqNB3PdZ+UUUZAEIrdOJdmABqKjt4AXwIoJNaRVVZEXxpNrqvE1GAYQ==",
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.2.tgz",
+ "integrity": "sha512-m5cPn3e2+FDCOgi1mz0RexTUvvQibBebOUlUlW0+YrMjDTPkiJ6VTKukA1GRsvRw+12KyJndNjj0O4AgTxm2Pg==",
"hasInstallScript": true,
"engines": {
"node": ">=6"
}
},
"node_modules/@humanwhocodes/config-array": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
- "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
+ "version": "0.11.11",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
+ "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
"dev": true,
"dependencies": {
"@humanwhocodes/object-schema": "^1.2.1",
@@ -2600,16 +2578,16 @@
}
},
"node_modules/@jest/console": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.2.tgz",
- "integrity": "sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.4.tgz",
+ "integrity": "sha512-wNK6gC0Ha9QeEPSkeJedQuTQqxZYnDPuDcDhVuVatRvMkL4D0VTvFVZj+Yuh6caG2aOfzkUZ36KtCmLNtR02hw==",
"dev": true,
"dependencies": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
- "jest-message-util": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-message-util": "^29.6.3",
+ "jest-util": "^29.6.3",
"slash": "^3.0.0"
},
"engines": {
@@ -2687,37 +2665,37 @@
}
},
"node_modules/@jest/core": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.2.tgz",
- "integrity": "sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.4.tgz",
+ "integrity": "sha512-U/vq5ccNTSVgYH7mHnodHmCffGWHJnz/E1BEWlLuK5pM4FZmGfBn/nrJGLjUsSmyx3otCeqc1T31F4y08AMDLg==",
"dev": true,
"dependencies": {
- "@jest/console": "^29.6.2",
- "@jest/reporters": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/console": "^29.6.4",
+ "@jest/reporters": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"ansi-escapes": "^4.2.1",
"chalk": "^4.0.0",
"ci-info": "^3.2.0",
"exit": "^0.1.2",
"graceful-fs": "^4.2.9",
- "jest-changed-files": "^29.5.0",
- "jest-config": "^29.6.2",
- "jest-haste-map": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-regex-util": "^29.4.3",
- "jest-resolve": "^29.6.2",
- "jest-resolve-dependencies": "^29.6.2",
- "jest-runner": "^29.6.2",
- "jest-runtime": "^29.6.2",
- "jest-snapshot": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-validate": "^29.6.2",
- "jest-watcher": "^29.6.2",
+ "jest-changed-files": "^29.6.3",
+ "jest-config": "^29.6.4",
+ "jest-haste-map": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.6.4",
+ "jest-resolve-dependencies": "^29.6.4",
+ "jest-runner": "^29.6.4",
+ "jest-runtime": "^29.6.4",
+ "jest-snapshot": "^29.6.4",
+ "jest-util": "^29.6.3",
+ "jest-validate": "^29.6.3",
+ "jest-watcher": "^29.6.4",
"micromatch": "^4.0.4",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"slash": "^3.0.0",
"strip-ansi": "^6.0.0"
},
@@ -2804,88 +2782,88 @@
}
},
"node_modules/@jest/environment": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.2.tgz",
- "integrity": "sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz",
+ "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==",
"dev": true,
"dependencies": {
- "@jest/fake-timers": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/fake-timers": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-mock": "^29.6.2"
+ "jest-mock": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/expect": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.2.tgz",
- "integrity": "sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.4.tgz",
+ "integrity": "sha512-Warhsa7d23+3X5bLbrbYvaehcgX5TLYhI03JKoedTiI8uJU4IhqYBWF7OSSgUyz4IgLpUYPkK0AehA5/fRclAA==",
"dev": true,
"dependencies": {
- "expect": "^29.6.2",
- "jest-snapshot": "^29.6.2"
+ "expect": "^29.6.4",
+ "jest-snapshot": "^29.6.4"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/expect-utils": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.2.tgz",
- "integrity": "sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.4.tgz",
+ "integrity": "sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg==",
"dev": true,
"dependencies": {
- "jest-get-type": "^29.4.3"
+ "jest-get-type": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/fake-timers": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.2.tgz",
- "integrity": "sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz",
+ "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==",
"dev": true,
"dependencies": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@sinonjs/fake-timers": "^10.0.2",
"@types/node": "*",
- "jest-message-util": "^29.6.2",
- "jest-mock": "^29.6.2",
- "jest-util": "^29.6.2"
+ "jest-message-util": "^29.6.3",
+ "jest-mock": "^29.6.3",
+ "jest-util": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/globals": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.2.tgz",
- "integrity": "sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.4.tgz",
+ "integrity": "sha512-wVIn5bdtjlChhXAzVXavcY/3PEjf4VqM174BM3eGL5kMxLiZD5CLnbmkEyA1Dwh9q8XjP6E8RwjBsY/iCWrWsA==",
"dev": true,
"dependencies": {
- "@jest/environment": "^29.6.2",
- "@jest/expect": "^29.6.2",
- "@jest/types": "^29.6.1",
- "jest-mock": "^29.6.2"
+ "@jest/environment": "^29.6.4",
+ "@jest/expect": "^29.6.4",
+ "@jest/types": "^29.6.3",
+ "jest-mock": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/reporters": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.2.tgz",
- "integrity": "sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.4.tgz",
+ "integrity": "sha512-sxUjWxm7QdchdrD3NfWKrL8FBsortZeibSJv4XLjESOOjSUOkjQcb0ZHJwfhEGIvBvTluTzfG2yZWZhkrXJu8g==",
"dev": true,
"dependencies": {
"@bcoe/v8-coverage": "^0.2.3",
- "@jest/console": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/console": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@jridgewell/trace-mapping": "^0.3.18",
"@types/node": "*",
"chalk": "^4.0.0",
@@ -2894,13 +2872,13 @@
"glob": "^7.1.3",
"graceful-fs": "^4.2.9",
"istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-instrument": "^5.1.0",
+ "istanbul-lib-instrument": "^6.0.0",
"istanbul-lib-report": "^3.0.0",
"istanbul-lib-source-maps": "^4.0.0",
"istanbul-reports": "^3.1.3",
- "jest-message-util": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-worker": "^29.6.2",
+ "jest-message-util": "^29.6.3",
+ "jest-util": "^29.6.3",
+ "jest-worker": "^29.6.4",
"slash": "^3.0.0",
"string-length": "^4.0.1",
"strip-ansi": "^6.0.0",
@@ -2977,13 +2955,13 @@
}
},
"node_modules/@jest/reporters/node_modules/jest-worker": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz",
- "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz",
+ "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==",
"dev": true,
"dependencies": {
"@types/node": "*",
- "jest-util": "^29.6.2",
+ "jest-util": "^29.6.3",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
@@ -3019,9 +2997,9 @@
}
},
"node_modules/@jest/schemas": {
- "version": "29.6.0",
- "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz",
- "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
"dev": true,
"dependencies": {
"@sinclair/typebox": "^0.27.8"
@@ -3031,9 +3009,9 @@
}
},
"node_modules/@jest/source-map": {
- "version": "29.6.0",
- "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.0.tgz",
- "integrity": "sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
+ "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
"dev": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.18",
@@ -3045,13 +3023,13 @@
}
},
"node_modules/@jest/test-result": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.2.tgz",
- "integrity": "sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.4.tgz",
+ "integrity": "sha512-uQ1C0AUEN90/dsyEirgMLlouROgSY+Wc/JanVVk0OiUKa5UFh7sJpMEM3aoUBAz2BRNvUJ8j3d294WFuRxSyOQ==",
"dev": true,
"dependencies": {
- "@jest/console": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/console": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"collect-v8-coverage": "^1.0.0"
},
@@ -3060,14 +3038,14 @@
}
},
"node_modules/@jest/test-sequencer": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz",
- "integrity": "sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.4.tgz",
+ "integrity": "sha512-E84M6LbpcRq3fT4ckfKs9ryVanwkaIB0Ws9bw3/yP4seRLg/VaCZ/LgW0MCq5wwk4/iP/qnilD41aj2fsw2RMg==",
"dev": true,
"dependencies": {
- "@jest/test-result": "^29.6.2",
+ "@jest/test-result": "^29.6.4",
"graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.6.2",
+ "jest-haste-map": "^29.6.4",
"slash": "^3.0.0"
},
"engines": {
@@ -3075,22 +3053,22 @@
}
},
"node_modules/@jest/transform": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.2.tgz",
- "integrity": "sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz",
+ "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==",
"dev": true,
"dependencies": {
"@babel/core": "^7.11.6",
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@jridgewell/trace-mapping": "^0.3.18",
"babel-plugin-istanbul": "^6.1.1",
"chalk": "^4.0.0",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.6.2",
- "jest-regex-util": "^29.4.3",
- "jest-util": "^29.6.2",
+ "jest-haste-map": "^29.6.4",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.6.3",
"micromatch": "^4.0.4",
"pirates": "^4.0.4",
"slash": "^3.0.0",
@@ -3177,12 +3155,12 @@
}
},
"node_modules/@jest/types": {
- "version": "29.6.1",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.1.tgz",
- "integrity": "sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
"dev": true,
"dependencies": {
- "@jest/schemas": "^29.6.0",
+ "@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
"@types/node": "*",
@@ -3326,15 +3304,6 @@
"resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz",
"integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q=="
},
- "node_modules/@nicolo-ribaudo/semver-v6": {
- "version": "6.3.3",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
- "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -4468,14 +4437,15 @@
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
},
"node_modules/assert": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz",
- "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz",
+ "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==",
"dependencies": {
- "es6-object-assign": "^1.1.0",
- "is-nan": "^1.2.1",
- "object-is": "^1.0.1",
- "util": "^0.12.0"
+ "call-bind": "^1.0.2",
+ "is-nan": "^1.3.2",
+ "object-is": "^1.1.5",
+ "object.assign": "^4.1.4",
+ "util": "^0.12.5"
}
},
"node_modules/assert-plus": {
@@ -4534,9 +4504,9 @@
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"node_modules/autoprefixer": {
- "version": "10.4.14",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
- "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==",
+ "version": "10.4.15",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz",
+ "integrity": "sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==",
"dev": true,
"funding": [
{
@@ -4546,11 +4516,15 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
- "browserslist": "^4.21.5",
- "caniuse-lite": "^1.0.30001464",
+ "browserslist": "^4.21.10",
+ "caniuse-lite": "^1.0.30001520",
"fraction.js": "^4.2.0",
"normalize-range": "^0.1.2",
"picocolors": "^1.0.0",
@@ -4591,15 +4565,15 @@
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
},
"node_modules/babel-jest": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.2.tgz",
- "integrity": "sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.4.tgz",
+ "integrity": "sha512-meLj23UlSLddj6PC+YTOFRgDAtjnZom8w/ACsrx0gtPtv5cJZk0A5Unk5bV4wixD7XaPCN1fQvpww8czkZURmw==",
"dev": true,
"dependencies": {
- "@jest/transform": "^29.6.2",
+ "@jest/transform": "^29.6.4",
"@types/babel__core": "^7.1.14",
"babel-plugin-istanbul": "^6.1.1",
- "babel-preset-jest": "^29.5.0",
+ "babel-preset-jest": "^29.6.3",
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
"slash": "^3.0.0"
@@ -4714,10 +4688,26 @@
"node": ">=8"
}
},
+ "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+ "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.12.3",
+ "@babel/parser": "^7.14.7",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.2.0",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/babel-plugin-jest-hoist": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz",
- "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
+ "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
"dev": true,
"dependencies": {
"@babel/template": "^7.3.3",
@@ -4743,22 +4733,22 @@
}
},
"node_modules/babel-plugin-polyfill-corejs3": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz",
- "integrity": "sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ==",
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz",
+ "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==",
"dev": true,
"dependencies": {
- "@babel/helper-define-polyfill-provider": "^0.4.1",
+ "@babel/helper-define-polyfill-provider": "^0.4.2",
"core-js-compat": "^3.31.0"
},
"peerDependencies": {
- "@babel/core": "^7.0.0-0"
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
"node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz",
- "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==",
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz",
+ "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==",
"dev": true,
"dependencies": {
"@babel/helper-compilation-targets": "^7.22.6",
@@ -4768,7 +4758,7 @@
"resolve": "^1.14.2"
},
"peerDependencies": {
- "@babel/core": "^7.4.0-0"
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
"node_modules/babel-plugin-polyfill-regenerator": {
@@ -4825,12 +4815,12 @@
}
},
"node_modules/babel-preset-jest": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz",
- "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
+ "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
"dev": true,
"dependencies": {
- "babel-plugin-jest-hoist": "^29.5.0",
+ "babel-plugin-jest-hoist": "^29.6.3",
"babel-preset-current-node-syntax": "^1.0.0"
},
"engines": {
@@ -4902,9 +4892,9 @@
}
},
"node_modules/bignumber.js": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
- "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==",
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
+ "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
"engines": {
"node": "*"
}
@@ -5114,9 +5104,9 @@
]
},
"node_modules/browserslist": {
- "version": "4.21.9",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
- "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
+ "version": "4.21.10",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
+ "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
"funding": [
{
"type": "opencollective",
@@ -5132,9 +5122,9 @@
}
],
"dependencies": {
- "caniuse-lite": "^1.0.30001503",
- "electron-to-chromium": "^1.4.431",
- "node-releases": "^2.0.12",
+ "caniuse-lite": "^1.0.30001517",
+ "electron-to-chromium": "^1.4.477",
+ "node-releases": "^2.0.13",
"update-browserslist-db": "^1.0.11"
},
"bin": {
@@ -5384,9 +5374,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001512",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz",
- "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==",
+ "version": "1.0.30001520",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001520.tgz",
+ "integrity": "sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA==",
"funding": [
{
"type": "opencollective",
@@ -5446,9 +5436,9 @@
}
},
"node_modules/chart.js": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.2.tgz",
- "integrity": "sha512-pvQNyFOY1QmbmIr8oDORL16/FFivfxj8V26VFpFilMo4cNvkV5WXLJetDio365pd9gKUHGdirUTbqJfw8tr+Dg==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.0.tgz",
+ "integrity": "sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==",
"dependencies": {
"@kurkle/color": "^0.3.0"
},
@@ -5824,9 +5814,9 @@
}
},
"node_modules/core-js": {
- "version": "3.32.0",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.0.tgz",
- "integrity": "sha512-rd4rYZNlF3WuoYuRIDEmbR/ga9CeuWX9U05umAvgrrZoHY4Z++cp/xwPQMvUpBB4Ag6J8KfD80G0zwCyaSxDww==",
+ "version": "3.32.2",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.2.tgz",
+ "integrity": "sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
@@ -6454,9 +6444,9 @@
}
},
"node_modules/dedent": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.3.0.tgz",
- "integrity": "sha512-7glNLfvdsMzZm3FpRY1CHuI2lbYDR+71YmrhmTZjYFD5pfT0ACgnGRdrrC9Mk2uICnzkcdelCx5at787UDGOvg==",
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz",
+ "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==",
"dev": true,
"peerDependencies": {
"babel-plugin-macros": "^3.1.0"
@@ -6578,9 +6568,9 @@
}
},
"node_modules/diff-sequences": {
- "version": "29.4.3",
- "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz",
- "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+ "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
"dev": true,
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -6722,9 +6712,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/electron-to-chromium": {
- "version": "1.4.450",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.450.tgz",
- "integrity": "sha512-BLG5HxSELlrMx7dJ2s+8SFlsCtJp37Zpk2VAxyC6CZtbc+9AJeZHfYHbrlSgdXp6saQ8StMqOTEDaBKgA7u1sw=="
+ "version": "1.4.490",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz",
+ "integrity": "sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A=="
},
"node_modules/elliptic": {
"version": "6.5.4",
@@ -6991,11 +6981,6 @@
"es6-symbol": "^3.1.1"
}
},
- "node_modules/es6-object-assign": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
- "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw="
- },
"node_modules/es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
@@ -7114,16 +7099,16 @@
}
},
"node_modules/eslint": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz",
- "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==",
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz",
+ "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.1",
- "@eslint/js": "^8.46.0",
- "@humanwhocodes/config-array": "^0.11.10",
+ "@eslint/eslintrc": "^2.1.2",
+ "@eslint/js": "8.49.0",
+ "@humanwhocodes/config-array": "^0.11.11",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.12.4",
@@ -7133,7 +7118,7 @@
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.2",
+ "eslint-visitor-keys": "^3.4.3",
"espree": "^9.6.1",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
@@ -7263,9 +7248,9 @@
}
},
"node_modules/eslint-plugin-import": {
- "version": "2.28.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz",
- "integrity": "sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==",
+ "version": "2.28.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz",
+ "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==",
"dev": true,
"dependencies": {
"array-includes": "^3.1.6",
@@ -7277,13 +7262,12 @@
"eslint-import-resolver-node": "^0.3.7",
"eslint-module-utils": "^2.8.0",
"has": "^1.0.3",
- "is-core-module": "^2.12.1",
+ "is-core-module": "^2.13.0",
"is-glob": "^4.0.3",
"minimatch": "^3.1.2",
"object.fromentries": "^2.0.6",
"object.groupby": "^1.0.0",
"object.values": "^1.1.6",
- "resolve": "^1.22.3",
"semver": "^6.3.1",
"tsconfig-paths": "^3.14.2"
},
@@ -7475,9 +7459,9 @@
}
},
"node_modules/eslint-visitor-keys": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz",
- "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==",
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -8338,17 +8322,16 @@
}
},
"node_modules/expect": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.2.tgz",
- "integrity": "sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.4.tgz",
+ "integrity": "sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==",
"dev": true,
"dependencies": {
- "@jest/expect-utils": "^29.6.2",
- "@types/node": "*",
- "jest-get-type": "^29.4.3",
- "jest-matcher-utils": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-util": "^29.6.2"
+ "@jest/expect-utils": "^29.6.4",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-util": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -9642,9 +9625,9 @@
}
},
"node_modules/is-core-module": {
- "version": "2.12.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
- "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+ "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
"dependencies": {
"has": "^1.0.3"
},
@@ -9960,19 +9943,34 @@
}
},
"node_modules/istanbul-lib-instrument": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
- "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz",
+ "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==",
"dev": true,
"dependencies": {
"@babel/core": "^7.12.3",
"@babel/parser": "^7.14.7",
"@istanbuljs/schema": "^0.1.2",
"istanbul-lib-coverage": "^3.2.0",
- "semver": "^6.3.0"
+ "semver": "^7.5.4"
},
"engines": {
- "node": ">=8"
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-lib-instrument/node_modules/semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
}
},
"node_modules/istanbul-lib-report": {
@@ -10038,15 +10036,15 @@
}
},
"node_modules/jest": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.2.tgz",
- "integrity": "sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.4.tgz",
+ "integrity": "sha512-tEFhVQFF/bzoYV1YuGyzLPZ6vlPrdfvDmmAxudA1dLEuiztqg2Rkx20vkKY32xiDROcD2KXlgZ7Cu8RPeEHRKw==",
"dev": true,
"dependencies": {
- "@jest/core": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/core": "^29.6.4",
+ "@jest/types": "^29.6.3",
"import-local": "^3.0.2",
- "jest-cli": "^29.6.2"
+ "jest-cli": "^29.6.4"
},
"bin": {
"jest": "bin/jest.js"
@@ -10064,12 +10062,13 @@
}
},
"node_modules/jest-changed-files": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz",
- "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.6.3.tgz",
+ "integrity": "sha512-G5wDnElqLa4/c66ma5PG9eRjE342lIbF6SUnTJi26C3J28Fv2TVY2rOyKB9YGbSA5ogwevgmxc4j4aVjrEK6Yg==",
"dev": true,
"dependencies": {
"execa": "^5.0.0",
+ "jest-util": "^29.6.3",
"p-limit": "^3.1.0"
},
"engines": {
@@ -10077,28 +10076,28 @@
}
},
"node_modules/jest-circus": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.2.tgz",
- "integrity": "sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.4.tgz",
+ "integrity": "sha512-YXNrRyntVUgDfZbjXWBMPslX1mQ8MrSG0oM/Y06j9EYubODIyHWP8hMUbjbZ19M3M+zamqEur7O80HODwACoJw==",
"dev": true,
"dependencies": {
- "@jest/environment": "^29.6.2",
- "@jest/expect": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/environment": "^29.6.4",
+ "@jest/expect": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"co": "^4.6.0",
"dedent": "^1.0.0",
"is-generator-fn": "^2.0.0",
- "jest-each": "^29.6.2",
- "jest-matcher-utils": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-runtime": "^29.6.2",
- "jest-snapshot": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-each": "^29.6.3",
+ "jest-matcher-utils": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-runtime": "^29.6.4",
+ "jest-snapshot": "^29.6.4",
+ "jest-util": "^29.6.3",
"p-limit": "^3.1.0",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"pure-rand": "^6.0.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.3"
@@ -10178,21 +10177,21 @@
}
},
"node_modules/jest-cli": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.2.tgz",
- "integrity": "sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.4.tgz",
+ "integrity": "sha512-+uMCQ7oizMmh8ZwRfZzKIEszFY9ksjjEQnTEMTaL7fYiL3Kw4XhqT9bYh+A4DQKUb67hZn2KbtEnDuHvcgK4pQ==",
"dev": true,
"dependencies": {
- "@jest/core": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/core": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/types": "^29.6.3",
"chalk": "^4.0.0",
"exit": "^0.1.2",
"graceful-fs": "^4.2.9",
"import-local": "^3.0.2",
- "jest-config": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-validate": "^29.6.2",
+ "jest-config": "^29.6.4",
+ "jest-util": "^29.6.3",
+ "jest-validate": "^29.6.3",
"prompts": "^2.0.1",
"yargs": "^17.3.1"
},
@@ -10282,31 +10281,31 @@
}
},
"node_modules/jest-config": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.2.tgz",
- "integrity": "sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.4.tgz",
+ "integrity": "sha512-JWohr3i9m2cVpBumQFv2akMEnFEPVOh+9L2xIBJhJ0zOaci2ZXuKJj0tgMKQCBZAKA09H049IR4HVS/43Qb19A==",
"dev": true,
"dependencies": {
"@babel/core": "^7.11.6",
- "@jest/test-sequencer": "^29.6.2",
- "@jest/types": "^29.6.1",
- "babel-jest": "^29.6.2",
+ "@jest/test-sequencer": "^29.6.4",
+ "@jest/types": "^29.6.3",
+ "babel-jest": "^29.6.4",
"chalk": "^4.0.0",
"ci-info": "^3.2.0",
"deepmerge": "^4.2.2",
"glob": "^7.1.3",
"graceful-fs": "^4.2.9",
- "jest-circus": "^29.6.2",
- "jest-environment-node": "^29.6.2",
- "jest-get-type": "^29.4.3",
- "jest-regex-util": "^29.4.3",
- "jest-resolve": "^29.6.2",
- "jest-runner": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-validate": "^29.6.2",
+ "jest-circus": "^29.6.4",
+ "jest-environment-node": "^29.6.4",
+ "jest-get-type": "^29.6.3",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.6.4",
+ "jest-runner": "^29.6.4",
+ "jest-util": "^29.6.3",
+ "jest-validate": "^29.6.3",
"micromatch": "^4.0.4",
"parse-json": "^5.2.0",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"slash": "^3.0.0",
"strip-json-comments": "^3.1.1"
},
@@ -10397,15 +10396,15 @@
}
},
"node_modules/jest-diff": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.2.tgz",
- "integrity": "sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz",
+ "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==",
"dev": true,
"dependencies": {
"chalk": "^4.0.0",
- "diff-sequences": "^29.4.3",
- "jest-get-type": "^29.4.3",
- "pretty-format": "^29.6.2"
+ "diff-sequences": "^29.6.3",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -10482,9 +10481,9 @@
}
},
"node_modules/jest-docblock": {
- "version": "29.4.3",
- "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz",
- "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.6.3.tgz",
+ "integrity": "sha512-2+H+GOTQBEm2+qFSQ7Ma+BvyV+waiIFxmZF5LdpBsAEjWX8QYjSCa4FrkIYtbfXUJJJnFCYrOtt6TZ+IAiTjBQ==",
"dev": true,
"dependencies": {
"detect-newline": "^3.0.0"
@@ -10494,16 +10493,16 @@
}
},
"node_modules/jest-each": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.2.tgz",
- "integrity": "sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.3.tgz",
+ "integrity": "sha512-KoXfJ42k8cqbkfshW7sSHcdfnv5agDdHCPA87ZBdmHP+zJstTJc0ttQaJ/x7zK6noAL76hOuTIJ6ZkQRS5dcyg==",
"dev": true,
"dependencies": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"chalk": "^4.0.0",
- "jest-get-type": "^29.4.3",
- "jest-util": "^29.6.2",
- "pretty-format": "^29.6.2"
+ "jest-get-type": "^29.6.3",
+ "jest-util": "^29.6.3",
+ "pretty-format": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -10580,18 +10579,18 @@
}
},
"node_modules/jest-environment-jsdom": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.6.2.tgz",
- "integrity": "sha512-7oa/+266AAEgkzae8i1awNEfTfjwawWKLpiw2XesZmaoVVj9u9t8JOYx18cG29rbPNtkUlZ8V4b5Jb36y/VxoQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.6.4.tgz",
+ "integrity": "sha512-K6wfgUJ16DoMs02JYFid9lOsqfpoVtyJxpRlnTxUHzvZWBnnh2VNGRB9EC1Cro96TQdq5TtSjb3qUjNaJP9IyA==",
"dev": true,
"dependencies": {
- "@jest/environment": "^29.6.2",
- "@jest/fake-timers": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/environment": "^29.6.4",
+ "@jest/fake-timers": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/jsdom": "^20.0.0",
"@types/node": "*",
- "jest-mock": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-mock": "^29.6.3",
+ "jest-util": "^29.6.3",
"jsdom": "^20.0.0"
},
"engines": {
@@ -10607,46 +10606,46 @@
}
},
"node_modules/jest-environment-node": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.2.tgz",
- "integrity": "sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.4.tgz",
+ "integrity": "sha512-i7SbpH2dEIFGNmxGCpSc2w9cA4qVD+wfvg2ZnfQ7XVrKL0NA5uDVBIiGH8SR4F0dKEv/0qI5r+aDomDf04DpEQ==",
"dev": true,
"dependencies": {
- "@jest/environment": "^29.6.2",
- "@jest/fake-timers": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/environment": "^29.6.4",
+ "@jest/fake-timers": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-mock": "^29.6.2",
- "jest-util": "^29.6.2"
+ "jest-mock": "^29.6.3",
+ "jest-util": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-get-type": {
- "version": "29.4.3",
- "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz",
- "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
+ "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
"dev": true,
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-haste-map": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.2.tgz",
- "integrity": "sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz",
+ "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==",
"dev": true,
"dependencies": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/graceful-fs": "^4.1.3",
"@types/node": "*",
"anymatch": "^3.0.3",
"fb-watchman": "^2.0.0",
"graceful-fs": "^4.2.9",
- "jest-regex-util": "^29.4.3",
- "jest-util": "^29.6.2",
- "jest-worker": "^29.6.2",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.6.3",
+ "jest-worker": "^29.6.4",
"micromatch": "^4.0.4",
"walker": "^1.0.8"
},
@@ -10667,13 +10666,13 @@
}
},
"node_modules/jest-haste-map/node_modules/jest-worker": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz",
- "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz",
+ "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==",
"dev": true,
"dependencies": {
"@types/node": "*",
- "jest-util": "^29.6.2",
+ "jest-util": "^29.6.3",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
@@ -10697,28 +10696,28 @@
}
},
"node_modules/jest-leak-detector": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz",
- "integrity": "sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz",
+ "integrity": "sha512-0kfbESIHXYdhAdpLsW7xdwmYhLf1BRu4AA118/OxFm0Ho1b2RcTmO4oF6aAMaxpxdxnJ3zve2rgwzNBD4Zbm7Q==",
"dev": true,
"dependencies": {
- "jest-get-type": "^29.4.3",
- "pretty-format": "^29.6.2"
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-matcher-utils": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz",
- "integrity": "sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz",
+ "integrity": "sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==",
"dev": true,
"dependencies": {
"chalk": "^4.0.0",
- "jest-diff": "^29.6.2",
- "jest-get-type": "^29.4.3",
- "pretty-format": "^29.6.2"
+ "jest-diff": "^29.6.4",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -10795,18 +10794,18 @@
}
},
"node_modules/jest-message-util": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.2.tgz",
- "integrity": "sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz",
+ "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.12.13",
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/stack-utils": "^2.0.0",
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
"micromatch": "^4.0.4",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"slash": "^3.0.0",
"stack-utils": "^2.0.3"
},
@@ -10885,14 +10884,14 @@
}
},
"node_modules/jest-mock": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.2.tgz",
- "integrity": "sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz",
+ "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==",
"dev": true,
"dependencies": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-util": "^29.6.2"
+ "jest-util": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -10916,26 +10915,26 @@
}
},
"node_modules/jest-regex-util": {
- "version": "29.4.3",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz",
- "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
+ "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
"dev": true,
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-resolve": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.2.tgz",
- "integrity": "sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.4.tgz",
+ "integrity": "sha512-fPRq+0vcxsuGlG0O3gyoqGTAxasagOxEuyoxHeyxaZbc9QNek0AmJWSkhjlMG+mTsj+8knc/mWb3fXlRNVih7Q==",
"dev": true,
"dependencies": {
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.6.2",
+ "jest-haste-map": "^29.6.4",
"jest-pnp-resolver": "^1.2.2",
- "jest-util": "^29.6.2",
- "jest-validate": "^29.6.2",
+ "jest-util": "^29.6.3",
+ "jest-validate": "^29.6.3",
"resolve": "^1.20.0",
"resolve.exports": "^2.0.0",
"slash": "^3.0.0"
@@ -10945,13 +10944,13 @@
}
},
"node_modules/jest-resolve-dependencies": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz",
- "integrity": "sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.4.tgz",
+ "integrity": "sha512-7+6eAmr1ZBF3vOAJVsfLj1QdqeXG+WYhidfLHBRZqGN24MFRIiKG20ItpLw2qRAsW/D2ZUUmCNf6irUr/v6KHA==",
"dev": true,
"dependencies": {
- "jest-regex-util": "^29.4.3",
- "jest-snapshot": "^29.6.2"
+ "jest-regex-util": "^29.6.3",
+ "jest-snapshot": "^29.6.4"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -11028,30 +11027,30 @@
}
},
"node_modules/jest-runner": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.2.tgz",
- "integrity": "sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.4.tgz",
+ "integrity": "sha512-SDaLrMmtVlQYDuG0iSPYLycG8P9jLI+fRm8AF/xPKhYDB2g6xDWjXBrR5M8gEWsK6KVFlebpZ4QsrxdyIX1Jaw==",
"dev": true,
"dependencies": {
- "@jest/console": "^29.6.2",
- "@jest/environment": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/console": "^29.6.4",
+ "@jest/environment": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"emittery": "^0.13.1",
"graceful-fs": "^4.2.9",
- "jest-docblock": "^29.4.3",
- "jest-environment-node": "^29.6.2",
- "jest-haste-map": "^29.6.2",
- "jest-leak-detector": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-resolve": "^29.6.2",
- "jest-runtime": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-watcher": "^29.6.2",
- "jest-worker": "^29.6.2",
+ "jest-docblock": "^29.6.3",
+ "jest-environment-node": "^29.6.4",
+ "jest-haste-map": "^29.6.4",
+ "jest-leak-detector": "^29.6.3",
+ "jest-message-util": "^29.6.3",
+ "jest-resolve": "^29.6.4",
+ "jest-runtime": "^29.6.4",
+ "jest-util": "^29.6.3",
+ "jest-watcher": "^29.6.4",
+ "jest-worker": "^29.6.4",
"p-limit": "^3.1.0",
"source-map-support": "0.5.13"
},
@@ -11118,13 +11117,13 @@
}
},
"node_modules/jest-runner/node_modules/jest-worker": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz",
- "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz",
+ "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==",
"dev": true,
"dependencies": {
"@types/node": "*",
- "jest-util": "^29.6.2",
+ "jest-util": "^29.6.3",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
@@ -11170,31 +11169,31 @@
}
},
"node_modules/jest-runtime": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.2.tgz",
- "integrity": "sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg==",
- "dev": true,
- "dependencies": {
- "@jest/environment": "^29.6.2",
- "@jest/fake-timers": "^29.6.2",
- "@jest/globals": "^29.6.2",
- "@jest/source-map": "^29.6.0",
- "@jest/test-result": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.4.tgz",
+ "integrity": "sha512-s/QxMBLvmwLdchKEjcLfwzP7h+jsHvNEtxGP5P+Fl1FMaJX2jMiIqe4rJw4tFprzCwuSvVUo9bn0uj4gNRXsbA==",
+ "dev": true,
+ "dependencies": {
+ "@jest/environment": "^29.6.4",
+ "@jest/fake-timers": "^29.6.4",
+ "@jest/globals": "^29.6.4",
+ "@jest/source-map": "^29.6.3",
+ "@jest/test-result": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"cjs-module-lexer": "^1.0.0",
"collect-v8-coverage": "^1.0.0",
"glob": "^7.1.3",
"graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-mock": "^29.6.2",
- "jest-regex-util": "^29.4.3",
- "jest-resolve": "^29.6.2",
- "jest-snapshot": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-haste-map": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-mock": "^29.6.3",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.6.4",
+ "jest-snapshot": "^29.6.4",
+ "jest-util": "^29.6.3",
"slash": "^3.0.0",
"strip-bom": "^4.0.0"
},
@@ -11273,9 +11272,9 @@
}
},
"node_modules/jest-snapshot": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.2.tgz",
- "integrity": "sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.4.tgz",
+ "integrity": "sha512-VC1N8ED7+4uboUKGIDsbvNAZb6LakgIPgAF4RSpF13dN6YaMokfRqO+BaqK4zIh6X3JffgwbzuGqDEjHm/MrvA==",
"dev": true,
"dependencies": {
"@babel/core": "^7.11.6",
@@ -11283,20 +11282,20 @@
"@babel/plugin-syntax-jsx": "^7.7.2",
"@babel/plugin-syntax-typescript": "^7.7.2",
"@babel/types": "^7.3.3",
- "@jest/expect-utils": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/expect-utils": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"babel-preset-current-node-syntax": "^1.0.0",
"chalk": "^4.0.0",
- "expect": "^29.6.2",
+ "expect": "^29.6.4",
"graceful-fs": "^4.2.9",
- "jest-diff": "^29.6.2",
- "jest-get-type": "^29.4.3",
- "jest-matcher-utils": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-diff": "^29.6.4",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-util": "^29.6.3",
"natural-compare": "^1.4.0",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"semver": "^7.5.3"
},
"engines": {
@@ -11389,12 +11388,12 @@
}
},
"node_modules/jest-util": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.2.tgz",
- "integrity": "sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz",
+ "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==",
"dev": true,
"dependencies": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"ci-info": "^3.2.0",
@@ -11476,17 +11475,17 @@
}
},
"node_modules/jest-validate": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.2.tgz",
- "integrity": "sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.3.tgz",
+ "integrity": "sha512-e7KWZcAIX+2W1o3cHfnqpGajdCs1jSM3DkXjGeLSNmCazv1EeI1ggTeK5wdZhF+7N+g44JI2Od3veojoaumlfg==",
"dev": true,
"dependencies": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"camelcase": "^6.2.0",
"chalk": "^4.0.0",
- "jest-get-type": "^29.4.3",
+ "jest-get-type": "^29.6.3",
"leven": "^3.1.0",
- "pretty-format": "^29.6.2"
+ "pretty-format": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -11575,18 +11574,18 @@
}
},
"node_modules/jest-watcher": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.2.tgz",
- "integrity": "sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.4.tgz",
+ "integrity": "sha512-oqUWvx6+On04ShsT00Ir9T4/FvBeEh2M9PTubgITPxDa739p4hoQweWPRGyYeaojgT0xTpZKF0Y/rSY1UgMxvQ==",
"dev": true,
"dependencies": {
- "@jest/test-result": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/test-result": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"ansi-escapes": "^4.2.1",
"chalk": "^4.0.0",
"emittery": "^0.13.1",
- "jest-util": "^29.6.2",
+ "jest-util": "^29.6.3",
"string-length": "^4.0.1"
},
"engines": {
@@ -11711,9 +11710,9 @@
}
},
"node_modules/jquery": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz",
- "integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ=="
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
+ "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
},
"node_modules/jquery-mousewheel": {
"version": "3.1.13",
@@ -12333,9 +12332,9 @@
"integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU="
},
"node_modules/luxon": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz",
- "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==",
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.3.tgz",
+ "integrity": "sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg==",
"engines": {
"node": ">=12"
}
@@ -12883,9 +12882,9 @@
"dev": true
},
"node_modules/node-releases": {
- "version": "2.0.12",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz",
- "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ=="
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+ "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ=="
},
"node_modules/normalize-path": {
"version": "3.0.0",
@@ -13023,7 +13022,6 @@
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
"integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.4",
@@ -13363,9 +13361,9 @@
"link": true
},
"node_modules/photoswipe": {
- "version": "5.3.8",
- "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.3.8.tgz",
- "integrity": "sha512-4vTzOQt8GP4Chsm0s+8j2xDtVHAEN252PxrU12A1zXauNn0zD5HRHgjALKO2GKTyBnTnOrJUOxbV8LTrFIMrYw==",
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.4.0.tgz",
+ "integrity": "sha512-PZvdK1D94TApU0MNWc9H6eXOolKJOMkgt7CJ9ZfIdkHR4CrEj47MOe4Vrlcv6ZpHslK+uKS6Ai3y3VIe7gsi+Q==",
"engines": {
"node": ">= 0.12.0"
}
@@ -13525,9 +13523,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.27",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
- "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
+ "version": "8.4.29",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz",
+ "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==",
"dev": true,
"funding": [
{
@@ -14100,12 +14098,12 @@
}
},
"node_modules/pretty-format": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz",
- "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz",
+ "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==",
"dev": true,
"dependencies": {
- "@jest/schemas": "^29.6.0",
+ "@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
"react-is": "^18.0.0"
},
@@ -14622,9 +14620,9 @@
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
},
"node_modules/regenerator-transform": {
- "version": "0.15.1",
- "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz",
- "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==",
+ "version": "0.15.2",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
+ "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.8.4"
@@ -14978,9 +14976,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sass": {
- "version": "1.64.2",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.2.tgz",
- "integrity": "sha512-TnDlfc+CRnUAgLO9D8cQLFu/GIjJIzJCGkE7o4ekIGQOH7T3GetiRR/PsTWJUHhkzcSPrARkPI+gNWn5alCzDg==",
+ "version": "1.66.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz",
+ "integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
@@ -15849,9 +15847,9 @@
}
},
"node_modules/sweetalert2": {
- "version": "11.7.20",
- "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.7.20.tgz",
- "integrity": "sha512-GdU1TkiLpGGC0mcPV8bKmS7G0MR7caxambPkEU8zyepRSNR9EaEvIjNhX5QNkL0VFVzHbI3l12NtuEklkJ0D4Q==",
+ "version": "11.7.27",
+ "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.7.27.tgz",
+ "integrity": "sha512-QbRXGQn1sb7HEhzA/K2xtWIwQHh/qkSbb1w6jYcTql2xy17876lTREEt1D4X6Q0x2wHtfUjKJ+Cb8IVkRoq7DQ==",
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/limonte"
@@ -16403,12 +16401,12 @@
"integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ=="
},
"node_modules/url": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/url/-/url-0.11.1.tgz",
- "integrity": "sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA==",
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.2.tgz",
+ "integrity": "sha512-7yIgNnrST44S7PJ5+jXbdIupfU1nWUdQJBFBeJRclPXiWgCvrSq5Frw8lr/i//n5sqDfzoKmBymMS81l4U/7cg==",
"dependencies": {
"punycode": "^1.4.1",
- "qs": "^6.11.0"
+ "qs": "^6.11.2"
}
},
"node_modules/url-parse": {
@@ -16537,9 +16535,9 @@
}
},
"node_modules/viewerjs": {
- "version": "1.11.4",
- "resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.4.tgz",
- "integrity": "sha512-/mnqMIwt5Bi9j59+48OqQtqgOx8oh186Xshdr/dqqBrakMSMlLt/jmeNHBod0PvOkesZf66ivQbWmtWYBlKetg=="
+ "version": "1.11.5",
+ "resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.5.tgz",
+ "integrity": "sha512-nsvQkC5jnqZ/2ggFYWUH5gpUGPtFAYidsFh8Q7B7sioAdqJzSJrELvbu9ozUm0W+A2uHN5XuuiheHHB+dWiPEA=="
},
"node_modules/w3c-hr-time": {
"version": "1.0.2",
@@ -17601,15 +17599,15 @@
"dev": true
},
"@amplitude/analytics-browser": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.1.3.tgz",
- "integrity": "sha512-DQqjyRdkmUEHxGBuMEDOPNTssE0of+xZa2WtjmsxEZcIhtUSjViEJfRMg6Eup8O72m+7S+wQO3psfQecuZ1OnQ==",
- "requires": {
- "@amplitude/analytics-client-common": "^2.0.4",
- "@amplitude/analytics-core": "^2.0.3",
- "@amplitude/analytics-types": "^2.1.1",
- "@amplitude/plugin-page-view-tracking-browser": "^2.0.5",
- "@amplitude/plugin-web-attribution-browser": "^2.0.5",
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-browser/-/analytics-browser-2.2.3.tgz",
+ "integrity": "sha512-vuKG8/jqtsAFe0xK0ZGtXDxH7oPx989VIoCpUi97bkfxholySCNHjVMd5Q8D4Mqm/3eDH7YZhkFwEb0JFyCAfA==",
+ "requires": {
+ "@amplitude/analytics-client-common": "^2.0.5",
+ "@amplitude/analytics-core": "^2.0.4",
+ "@amplitude/analytics-types": "^2.1.2",
+ "@amplitude/plugin-page-view-tracking-browser": "^2.0.9",
+ "@amplitude/plugin-web-attribution-browser": "^2.0.9",
"tslib": "^2.4.1"
},
"dependencies": {
@@ -17621,81 +17619,81 @@
}
},
"@amplitude/analytics-client-common": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-client-common/-/analytics-client-common-2.0.4.tgz",
- "integrity": "sha512-X0+zE8sODcQ2ioj9ZB98Gr/9FCRDiJuSixefaLrfng/4x5VwHK0if8biCqqBHXu6HlMpeMFrCyiABUTDT87QVA==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-client-common/-/analytics-client-common-2.0.5.tgz",
+ "integrity": "sha512-5BrGl188h4Ayx4Z2e1x4I3Z8ykC+ap65cy8ShBByiaBBrR40gnXSuLZR7xeex3lvTp2b5lMBcVCqArdRbeZrgQ==",
"requires": {
"@amplitude/analytics-connector": "^1.4.8",
- "@amplitude/analytics-core": "^2.0.3",
- "@amplitude/analytics-types": "^2.1.1",
+ "@amplitude/analytics-core": "^2.0.4",
+ "@amplitude/analytics-types": "^2.1.2",
"tslib": "^2.4.1"
},
"dependencies": {
"tslib": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
- "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
}
}
},
"@amplitude/analytics-connector": {
- "version": "1.4.8",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.4.8.tgz",
- "integrity": "sha512-dFW7c7Wb6Ng7vbmzwbaXZSpqfBx37ukamJV9ErFYYS8vGZK/Hkbt3M7fZHBI4WFU6CCwakr2ZXPme11uGPYWkQ=="
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.5.0.tgz",
+ "integrity": "sha512-T8mOYzB9RRxckzhL0NTHwdge9xuFxXEOplC8B1Y3UX3NHa3BLh7DlBUZlCOwQgMc2nxDfnSweDL5S3bhC+W90g=="
},
"@amplitude/analytics-core": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.0.3.tgz",
- "integrity": "sha512-tpD1gCmPpzPNPumQT1ecOJtuan5OsQdKp9AX8YKc7t1/K3xHzGo3FH3JvdaAJVYYWeZV40bp/JL6wJiYIzyZjA==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-core/-/analytics-core-2.0.4.tgz",
+ "integrity": "sha512-AM4g1ucaAJuFqaMBg7FiqwKHveyV2QpZ3yPxw3OxNCgZz2QmqeYE1bp47x4FlfzNsoGyuYqRKs1mCbmGobAYWA==",
"requires": {
- "@amplitude/analytics-types": "^2.1.1",
+ "@amplitude/analytics-types": "^2.1.2",
"tslib": "^2.4.1"
},
"dependencies": {
"tslib": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
- "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
}
}
},
"@amplitude/analytics-types": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-2.1.1.tgz",
- "integrity": "sha512-H3vebPR9onRdp0WzAZmI/4qmAE903uLOd2ZfMeHsVc1zaFTTCk46SoCuV4IrlF+VILrDw9Fy6gC9yl5N2PZcJQ=="
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@amplitude/analytics-types/-/analytics-types-2.1.2.tgz",
+ "integrity": "sha512-ASKwH9g+5gglTHr7h7miK8J/ofIzuEtGRDCjnZAtRbE6+laoOfCLYPPJXMYz0k1x+rIhLO/6I6WWjT7zchmpyA=="
},
"@amplitude/plugin-page-view-tracking-browser": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.0.5.tgz",
- "integrity": "sha512-dmW2dckEaI/Z9DQ+3RNJU32cF4c6iYsFamvu73LDu/sttE0gmqWDRvZhh/B7j/VDxYmobySMUEV1kinjbn8vXg==",
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/@amplitude/plugin-page-view-tracking-browser/-/plugin-page-view-tracking-browser-2.0.9.tgz",
+ "integrity": "sha512-OjhAxvQ52lDcRap2sjUbYEcSM6bzeDa6SdBx6vCaeXswvjafcH9LeDPawLUHgaqvQJiAhA7lxrQ7ThfH0P6c0g==",
"requires": {
- "@amplitude/analytics-client-common": "^2.0.4",
- "@amplitude/analytics-types": "^2.1.1",
+ "@amplitude/analytics-client-common": "^2.0.5",
+ "@amplitude/analytics-types": "^2.1.2",
"tslib": "^2.4.1"
},
"dependencies": {
"tslib": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
- "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
}
}
},
"@amplitude/plugin-web-attribution-browser": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@amplitude/plugin-web-attribution-browser/-/plugin-web-attribution-browser-2.0.5.tgz",
- "integrity": "sha512-apLZ4XV0Xbq4E3sHY25zubiyqHX9IWupWk+RTMNqHZJyhC7JuA3ttVFU3p0fWM/XeumITMRPL2NcG9R9WO4y9Q==",
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/@amplitude/plugin-web-attribution-browser/-/plugin-web-attribution-browser-2.0.9.tgz",
+ "integrity": "sha512-QrNgieAEXEBbtnsxYzfeJl2U/5XwCCvO3Dg0hntAtnTdu1A3HlN5ItRtoHg0jGBbu4jpSbvag72UlkCotqJ+Yg==",
"requires": {
- "@amplitude/analytics-client-common": "^2.0.4",
- "@amplitude/analytics-core": "^2.0.3",
- "@amplitude/analytics-types": "^2.1.1",
+ "@amplitude/analytics-client-common": "^2.0.5",
+ "@amplitude/analytics-core": "^2.0.4",
+ "@amplitude/analytics-types": "^2.1.2",
"tslib": "^2.4.1"
},
"dependencies": {
"tslib": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
- "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
}
}
},
@@ -17720,11 +17718,12 @@
}
},
"@babel/code-frame": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
- "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"requires": {
- "@babel/highlight": "^7.22.5"
+ "@babel/highlight": "^7.22.13",
+ "chalk": "^2.4.2"
}
},
"@babel/compat-data": {
@@ -17733,33 +17732,33 @@
"integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ=="
},
"@babel/core": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz",
- "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==",
+ "version": "7.22.17",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.17.tgz",
+ "integrity": "sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ==",
"requires": {
"@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.9",
- "@babel/helper-compilation-targets": "^7.22.9",
- "@babel/helper-module-transforms": "^7.22.9",
- "@babel/helpers": "^7.22.6",
- "@babel/parser": "^7.22.7",
- "@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.8",
- "@babel/types": "^7.22.5",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.22.15",
+ "@babel/helper-compilation-targets": "^7.22.15",
+ "@babel/helper-module-transforms": "^7.22.17",
+ "@babel/helpers": "^7.22.15",
+ "@babel/parser": "^7.22.16",
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.22.17",
+ "@babel/types": "^7.22.17",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
- "json5": "^2.2.2",
+ "json5": "^2.2.3",
"semver": "^6.3.1"
}
},
"@babel/generator": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz",
- "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz",
+ "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==",
"requires": {
- "@babel/types": "^7.22.5",
+ "@babel/types": "^7.22.15",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -17783,12 +17782,12 @@
}
},
"@babel/helper-compilation-targets": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz",
- "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz",
+ "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==",
"requires": {
"@babel/compat-data": "^7.22.9",
- "@babel/helper-validator-option": "^7.22.5",
+ "@babel/helper-validator-option": "^7.22.15",
"browserslist": "^4.21.9",
"lru-cache": "^5.1.1",
"semver": "^6.3.1"
@@ -17810,9 +17809,9 @@
}
},
"@babel/helper-create-class-features-plugin": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.5.tgz",
- "integrity": "sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.11.tgz",
+ "integrity": "sha512-y1grdYL4WzmUDBRGK0pDbIoFd7UZKoDurDzWEoNMYoj1EL+foGRQNyPWDcC+YyegN5y1DUsFFmzjGijB3nSVAQ==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
@@ -17820,10 +17819,10 @@
"@babel/helper-function-name": "^7.22.5",
"@babel/helper-member-expression-to-functions": "^7.22.5",
"@babel/helper-optimise-call-expression": "^7.22.5",
- "@babel/helper-replace-supers": "^7.22.5",
+ "@babel/helper-replace-supers": "^7.22.9",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.5",
- "semver": "^6.3.0"
+ "@babel/helper-split-export-declaration": "^7.22.6",
+ "semver": "^6.3.1"
}
},
"@babel/helper-create-regexp-features-plugin": {
@@ -17882,23 +17881,23 @@
}
},
"@babel/helper-module-imports": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz",
- "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
+ "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
"requires": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.22.15"
}
},
"@babel/helper-module-transforms": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz",
- "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==",
+ "version": "7.22.17",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz",
+ "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==",
"requires": {
"@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-module-imports": "^7.22.5",
+ "@babel/helper-module-imports": "^7.22.15",
"@babel/helper-simple-access": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/helper-validator-identifier": "^7.22.5"
+ "@babel/helper-validator-identifier": "^7.22.15"
}
},
"@babel/helper-optimise-call-expression": {
@@ -17916,29 +17915,25 @@
"integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg=="
},
"@babel/helper-remap-async-to-generator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.5.tgz",
- "integrity": "sha512-cU0Sq1Rf4Z55fgz7haOakIyM7+x/uCFwXpLPaeRzfoUtAEAuUZjZvFPjL/rk5rW693dIgn2hng1W7xbT7lWT4g==",
+ "version": "7.22.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz",
+ "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-wrap-function": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/helper-wrap-function": "^7.22.9"
}
},
"@babel/helper-replace-supers": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.5.tgz",
- "integrity": "sha512-aLdNM5I3kdI/V9xGNyKSF3X/gTyMUBohTZ+/3QdQKAA9vxIiy12E+8E2HoOP1/DjeqU+g6as35QHJNMDDYpuCg==",
+ "version": "7.22.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz",
+ "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==",
"dev": true,
"requires": {
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-member-expression-to-functions": "^7.22.5",
- "@babel/helper-optimise-call-expression": "^7.22.5",
- "@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/helper-optimise-call-expression": "^7.22.5"
}
},
"@babel/helper-simple-access": {
@@ -17972,70 +17967,69 @@
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw=="
},
"@babel/helper-validator-identifier": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
- "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ=="
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz",
+ "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ=="
},
"@babel/helper-validator-option": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz",
- "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw=="
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz",
+ "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA=="
},
"@babel/helper-wrap-function": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.5.tgz",
- "integrity": "sha512-bYqLIBSEshYcYQyfks8ewYA8S30yaGSeRslcvKMvoUk6HHPySbxHq9YRi6ghhzEU+yhQv9bP/jXnygkStOcqZw==",
+ "version": "7.22.10",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz",
+ "integrity": "sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.22.5",
"@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.22.10"
}
},
"@babel/helpers": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz",
- "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz",
+ "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==",
"requires": {
- "@babel/template": "^7.22.5",
- "@babel/traverse": "^7.22.6",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/traverse": "^7.22.15",
+ "@babel/types": "^7.22.15"
}
},
"@babel/highlight": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
- "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz",
+ "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==",
"requires": {
"@babel/helper-validator-identifier": "^7.22.5",
- "chalk": "^2.0.0",
+ "chalk": "^2.4.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
- "version": "7.22.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
- "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q=="
+ "version": "7.22.16",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
+ "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA=="
},
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz",
- "integrity": "sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz",
+ "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
},
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz",
- "integrity": "sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz",
+ "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
- "@babel/plugin-transform-optional-chaining": "^7.22.5"
+ "@babel/plugin-transform-optional-chaining": "^7.22.15"
}
},
"@babel/plugin-proposal-private-property-in-object": {
@@ -18045,16 +18039,6 @@
"dev": true,
"requires": {}
},
- "@babel/plugin-proposal-unicode-property-regex": {
- "version": "7.18.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz",
- "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==",
- "dev": true,
- "requires": {
- "@babel/helper-create-regexp-features-plugin": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
- }
- },
"@babel/plugin-syntax-async-generators": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
@@ -18255,14 +18239,14 @@
}
},
"@babel/plugin-transform-async-generator-functions": {
- "version": "7.22.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz",
- "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz",
+ "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==",
"dev": true,
"requires": {
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
- "@babel/helper-remap-async-to-generator": "^7.22.5",
+ "@babel/helper-remap-async-to-generator": "^7.22.9",
"@babel/plugin-syntax-async-generators": "^7.8.4"
}
},
@@ -18287,9 +18271,9 @@
}
},
"@babel/plugin-transform-block-scoping": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz",
- "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz",
+ "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -18306,29 +18290,29 @@
}
},
"@babel/plugin-transform-class-static-block": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz",
- "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz",
+ "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==",
"dev": true,
"requires": {
- "@babel/helper-create-class-features-plugin": "^7.22.5",
+ "@babel/helper-create-class-features-plugin": "^7.22.11",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-class-static-block": "^7.14.5"
}
},
"@babel/plugin-transform-classes": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz",
- "integrity": "sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz",
+ "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-compilation-targets": "^7.22.6",
+ "@babel/helper-compilation-targets": "^7.22.15",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
"@babel/helper-optimise-call-expression": "^7.22.5",
"@babel/helper-plugin-utils": "^7.22.5",
- "@babel/helper-replace-supers": "^7.22.5",
+ "@babel/helper-replace-supers": "^7.22.9",
"@babel/helper-split-export-declaration": "^7.22.6",
"globals": "^11.1.0"
}
@@ -18344,9 +18328,9 @@
}
},
"@babel/plugin-transform-destructuring": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz",
- "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz",
+ "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -18372,9 +18356,9 @@
}
},
"@babel/plugin-transform-dynamic-import": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz",
- "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz",
+ "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -18392,9 +18376,9 @@
}
},
"@babel/plugin-transform-export-namespace-from": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz",
- "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz",
+ "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -18402,9 +18386,9 @@
}
},
"@babel/plugin-transform-for-of": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz",
- "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz",
+ "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -18422,9 +18406,9 @@
}
},
"@babel/plugin-transform-json-strings": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz",
- "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz",
+ "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -18441,9 +18425,9 @@
}
},
"@babel/plugin-transform-logical-assignment-operators": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz",
- "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz",
+ "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -18470,24 +18454,24 @@
}
},
"@babel/plugin-transform-modules-commonjs": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz",
- "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz",
+ "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==",
"dev": true,
"requires": {
- "@babel/helper-module-transforms": "^7.22.5",
+ "@babel/helper-module-transforms": "^7.22.15",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-simple-access": "^7.22.5"
}
},
"@babel/plugin-transform-modules-systemjs": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz",
- "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz",
+ "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==",
"dev": true,
"requires": {
"@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-module-transforms": "^7.22.5",
+ "@babel/helper-module-transforms": "^7.22.9",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.5"
}
@@ -18522,9 +18506,9 @@
}
},
"@babel/plugin-transform-nullish-coalescing-operator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz",
- "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz",
+ "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -18532,9 +18516,9 @@
}
},
"@babel/plugin-transform-numeric-separator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz",
- "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz",
+ "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -18542,16 +18526,16 @@
}
},
"@babel/plugin-transform-object-rest-spread": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz",
- "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz",
+ "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==",
"dev": true,
"requires": {
- "@babel/compat-data": "^7.22.5",
- "@babel/helper-compilation-targets": "^7.22.5",
+ "@babel/compat-data": "^7.22.9",
+ "@babel/helper-compilation-targets": "^7.22.15",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-transform-parameters": "^7.22.5"
+ "@babel/plugin-transform-parameters": "^7.22.15"
}
},
"@babel/plugin-transform-object-super": {
@@ -18565,9 +18549,9 @@
}
},
"@babel/plugin-transform-optional-catch-binding": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz",
- "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz",
+ "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -18575,9 +18559,9 @@
}
},
"@babel/plugin-transform-optional-chaining": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz",
- "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz",
+ "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
@@ -18586,9 +18570,9 @@
}
},
"@babel/plugin-transform-parameters": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz",
- "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz",
+ "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -18605,13 +18589,13 @@
}
},
"@babel/plugin-transform-private-property-in-object": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz",
- "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==",
+ "version": "7.22.11",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz",
+ "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-create-class-features-plugin": "^7.22.5",
+ "@babel/helper-create-class-features-plugin": "^7.22.11",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
}
@@ -18626,13 +18610,13 @@
}
},
"@babel/plugin-transform-regenerator": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz",
- "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==",
+ "version": "7.22.10",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz",
+ "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
- "regenerator-transform": "^0.15.1"
+ "regenerator-transform": "^0.15.2"
}
},
"@babel/plugin-transform-reserved-words": {
@@ -18715,9 +18699,9 @@
}
},
"@babel/plugin-transform-unicode-escapes": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz",
- "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==",
+ "version": "7.22.10",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz",
+ "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
@@ -18754,17 +18738,17 @@
}
},
"@babel/preset-env": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz",
- "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.15.tgz",
+ "integrity": "sha512-tZFHr54GBkHk6hQuVA8w4Fmq+MSPsfvMG0vPnOYyTnJpyfMqybL8/MbNCPRT9zc2KBO2pe4tq15g6Uno4Jpoag==",
"dev": true,
"requires": {
"@babel/compat-data": "^7.22.9",
- "@babel/helper-compilation-targets": "^7.22.9",
+ "@babel/helper-compilation-targets": "^7.22.15",
"@babel/helper-plugin-utils": "^7.22.5",
- "@babel/helper-validator-option": "^7.22.5",
- "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5",
- "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5",
+ "@babel/helper-validator-option": "^7.22.15",
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15",
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15",
"@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
"@babel/plugin-syntax-async-generators": "^7.8.4",
"@babel/plugin-syntax-class-properties": "^7.12.13",
@@ -18785,66 +18769,66 @@
"@babel/plugin-syntax-top-level-await": "^7.14.5",
"@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
"@babel/plugin-transform-arrow-functions": "^7.22.5",
- "@babel/plugin-transform-async-generator-functions": "^7.22.7",
+ "@babel/plugin-transform-async-generator-functions": "^7.22.15",
"@babel/plugin-transform-async-to-generator": "^7.22.5",
"@babel/plugin-transform-block-scoped-functions": "^7.22.5",
- "@babel/plugin-transform-block-scoping": "^7.22.5",
+ "@babel/plugin-transform-block-scoping": "^7.22.15",
"@babel/plugin-transform-class-properties": "^7.22.5",
- "@babel/plugin-transform-class-static-block": "^7.22.5",
- "@babel/plugin-transform-classes": "^7.22.6",
+ "@babel/plugin-transform-class-static-block": "^7.22.11",
+ "@babel/plugin-transform-classes": "^7.22.15",
"@babel/plugin-transform-computed-properties": "^7.22.5",
- "@babel/plugin-transform-destructuring": "^7.22.5",
+ "@babel/plugin-transform-destructuring": "^7.22.15",
"@babel/plugin-transform-dotall-regex": "^7.22.5",
"@babel/plugin-transform-duplicate-keys": "^7.22.5",
- "@babel/plugin-transform-dynamic-import": "^7.22.5",
+ "@babel/plugin-transform-dynamic-import": "^7.22.11",
"@babel/plugin-transform-exponentiation-operator": "^7.22.5",
- "@babel/plugin-transform-export-namespace-from": "^7.22.5",
- "@babel/plugin-transform-for-of": "^7.22.5",
+ "@babel/plugin-transform-export-namespace-from": "^7.22.11",
+ "@babel/plugin-transform-for-of": "^7.22.15",
"@babel/plugin-transform-function-name": "^7.22.5",
- "@babel/plugin-transform-json-strings": "^7.22.5",
+ "@babel/plugin-transform-json-strings": "^7.22.11",
"@babel/plugin-transform-literals": "^7.22.5",
- "@babel/plugin-transform-logical-assignment-operators": "^7.22.5",
+ "@babel/plugin-transform-logical-assignment-operators": "^7.22.11",
"@babel/plugin-transform-member-expression-literals": "^7.22.5",
"@babel/plugin-transform-modules-amd": "^7.22.5",
- "@babel/plugin-transform-modules-commonjs": "^7.22.5",
- "@babel/plugin-transform-modules-systemjs": "^7.22.5",
+ "@babel/plugin-transform-modules-commonjs": "^7.22.15",
+ "@babel/plugin-transform-modules-systemjs": "^7.22.11",
"@babel/plugin-transform-modules-umd": "^7.22.5",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5",
"@babel/plugin-transform-new-target": "^7.22.5",
- "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5",
- "@babel/plugin-transform-numeric-separator": "^7.22.5",
- "@babel/plugin-transform-object-rest-spread": "^7.22.5",
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11",
+ "@babel/plugin-transform-numeric-separator": "^7.22.11",
+ "@babel/plugin-transform-object-rest-spread": "^7.22.15",
"@babel/plugin-transform-object-super": "^7.22.5",
- "@babel/plugin-transform-optional-catch-binding": "^7.22.5",
- "@babel/plugin-transform-optional-chaining": "^7.22.6",
- "@babel/plugin-transform-parameters": "^7.22.5",
+ "@babel/plugin-transform-optional-catch-binding": "^7.22.11",
+ "@babel/plugin-transform-optional-chaining": "^7.22.15",
+ "@babel/plugin-transform-parameters": "^7.22.15",
"@babel/plugin-transform-private-methods": "^7.22.5",
- "@babel/plugin-transform-private-property-in-object": "^7.22.5",
+ "@babel/plugin-transform-private-property-in-object": "^7.22.11",
"@babel/plugin-transform-property-literals": "^7.22.5",
- "@babel/plugin-transform-regenerator": "^7.22.5",
+ "@babel/plugin-transform-regenerator": "^7.22.10",
"@babel/plugin-transform-reserved-words": "^7.22.5",
"@babel/plugin-transform-shorthand-properties": "^7.22.5",
"@babel/plugin-transform-spread": "^7.22.5",
"@babel/plugin-transform-sticky-regex": "^7.22.5",
"@babel/plugin-transform-template-literals": "^7.22.5",
"@babel/plugin-transform-typeof-symbol": "^7.22.5",
- "@babel/plugin-transform-unicode-escapes": "^7.22.5",
+ "@babel/plugin-transform-unicode-escapes": "^7.22.10",
"@babel/plugin-transform-unicode-property-regex": "^7.22.5",
"@babel/plugin-transform-unicode-regex": "^7.22.5",
"@babel/plugin-transform-unicode-sets-regex": "^7.22.5",
- "@babel/preset-modules": "^0.1.5",
- "@babel/types": "^7.22.5",
- "babel-plugin-polyfill-corejs2": "^0.4.4",
- "babel-plugin-polyfill-corejs3": "^0.8.2",
- "babel-plugin-polyfill-regenerator": "^0.5.1",
+ "@babel/preset-modules": "0.1.6-no-external-plugins",
+ "@babel/types": "^7.22.15",
+ "babel-plugin-polyfill-corejs2": "^0.4.5",
+ "babel-plugin-polyfill-corejs3": "^0.8.3",
+ "babel-plugin-polyfill-regenerator": "^0.5.2",
"core-js-compat": "^3.31.0",
"semver": "^6.3.1"
},
"dependencies": {
"@babel/helper-define-polyfill-provider": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz",
- "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==",
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz",
+ "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==",
"dev": true,
"requires": {
"@babel/helper-compilation-targets": "^7.22.6",
@@ -18855,36 +18839,34 @@
}
},
"babel-plugin-polyfill-corejs2": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.4.tgz",
- "integrity": "sha512-9WeK9snM1BfxB38goUEv2FLnA6ja07UMfazFHzCXUb3NyDZAwfXvQiURQ6guTTMeHcOsdknULm1PDhs4uWtKyA==",
+ "version": "0.4.5",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz",
+ "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==",
"dev": true,
"requires": {
"@babel/compat-data": "^7.22.6",
- "@babel/helper-define-polyfill-provider": "^0.4.1",
- "@nicolo-ribaudo/semver-v6": "^6.3.3"
+ "@babel/helper-define-polyfill-provider": "^0.4.2",
+ "semver": "^6.3.1"
}
},
"babel-plugin-polyfill-regenerator": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.1.tgz",
- "integrity": "sha512-L8OyySuI6OSQ5hFy9O+7zFjyr4WhAfRjLIOkhQGYl+emwJkd/S4XXT1JpfrgR1jrQ1NcGiOh+yAdGlF8pnC3Jw==",
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz",
+ "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==",
"dev": true,
"requires": {
- "@babel/helper-define-polyfill-provider": "^0.4.1"
+ "@babel/helper-define-polyfill-provider": "^0.4.2"
}
}
}
},
"@babel/preset-modules": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz",
- "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==",
+ "version": "0.1.6-no-external-plugins",
+ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
+ "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
- "@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
- "@babel/plugin-transform-dotall-regex": "^7.4.4",
"@babel/types": "^7.4.4",
"esutils": "^2.0.2"
}
@@ -18904,39 +18886,39 @@
}
},
"@babel/template": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
- "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"requires": {
- "@babel/code-frame": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
}
},
"@babel/traverse": {
- "version": "7.22.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
- "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
+ "version": "7.22.17",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.17.tgz",
+ "integrity": "sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg==",
"requires": {
- "@babel/code-frame": "^7.22.5",
- "@babel/generator": "^7.22.7",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.22.15",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.22.7",
- "@babel/types": "^7.22.5",
+ "@babel/parser": "^7.22.16",
+ "@babel/types": "^7.22.17",
"debug": "^4.1.0",
"globals": "^11.1.0"
}
},
"@babel/types": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
- "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
+ "version": "7.22.17",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz",
+ "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==",
"requires": {
"@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.15",
"to-fast-properties": "^2.0.0"
}
},
@@ -18991,9 +18973,9 @@
"dev": true
},
"@eslint/eslintrc": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz",
- "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+ "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
@@ -19014,9 +18996,9 @@
"dev": true
},
"globals": {
- "version": "13.20.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
- "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+ "version": "13.21.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
+ "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
"dev": true,
"requires": {
"type-fest": "^0.20.2"
@@ -19040,9 +19022,9 @@
}
},
"@eslint/js": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz",
- "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==",
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz",
+ "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==",
"dev": true
},
"@ethereumjs/common": {
@@ -19258,14 +19240,14 @@
}
},
"@fortawesome/fontawesome-free": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.0.tgz",
- "integrity": "sha512-0NyytTlPJwB/BF5LtRV8rrABDbe3TdTXqNB3PdZ+UUUZAEIrdOJdmABqKjt4AXwIoJNaRVVZEXxpNrqvE1GAYQ=="
+ "version": "6.4.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.2.tgz",
+ "integrity": "sha512-m5cPn3e2+FDCOgi1mz0RexTUvvQibBebOUlUlW0+YrMjDTPkiJ6VTKukA1GRsvRw+12KyJndNjj0O4AgTxm2Pg=="
},
"@humanwhocodes/config-array": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
- "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
+ "version": "0.11.11",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
+ "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
"dev": true,
"requires": {
"@humanwhocodes/object-schema": "^1.2.1",
@@ -19313,16 +19295,16 @@
"dev": true
},
"@jest/console": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.2.tgz",
- "integrity": "sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.4.tgz",
+ "integrity": "sha512-wNK6gC0Ha9QeEPSkeJedQuTQqxZYnDPuDcDhVuVatRvMkL4D0VTvFVZj+Yuh6caG2aOfzkUZ36KtCmLNtR02hw==",
"dev": true,
"requires": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
- "jest-message-util": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-message-util": "^29.6.3",
+ "jest-util": "^29.6.3",
"slash": "^3.0.0"
},
"dependencies": {
@@ -19378,37 +19360,37 @@
}
},
"@jest/core": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.2.tgz",
- "integrity": "sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.4.tgz",
+ "integrity": "sha512-U/vq5ccNTSVgYH7mHnodHmCffGWHJnz/E1BEWlLuK5pM4FZmGfBn/nrJGLjUsSmyx3otCeqc1T31F4y08AMDLg==",
"dev": true,
"requires": {
- "@jest/console": "^29.6.2",
- "@jest/reporters": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/console": "^29.6.4",
+ "@jest/reporters": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"ansi-escapes": "^4.2.1",
"chalk": "^4.0.0",
"ci-info": "^3.2.0",
"exit": "^0.1.2",
"graceful-fs": "^4.2.9",
- "jest-changed-files": "^29.5.0",
- "jest-config": "^29.6.2",
- "jest-haste-map": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-regex-util": "^29.4.3",
- "jest-resolve": "^29.6.2",
- "jest-resolve-dependencies": "^29.6.2",
- "jest-runner": "^29.6.2",
- "jest-runtime": "^29.6.2",
- "jest-snapshot": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-validate": "^29.6.2",
- "jest-watcher": "^29.6.2",
+ "jest-changed-files": "^29.6.3",
+ "jest-config": "^29.6.4",
+ "jest-haste-map": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.6.4",
+ "jest-resolve-dependencies": "^29.6.4",
+ "jest-runner": "^29.6.4",
+ "jest-runtime": "^29.6.4",
+ "jest-snapshot": "^29.6.4",
+ "jest-util": "^29.6.3",
+ "jest-validate": "^29.6.3",
+ "jest-watcher": "^29.6.4",
"micromatch": "^4.0.4",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"slash": "^3.0.0",
"strip-ansi": "^6.0.0"
},
@@ -19465,73 +19447,73 @@
}
},
"@jest/environment": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.2.tgz",
- "integrity": "sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz",
+ "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==",
"dev": true,
"requires": {
- "@jest/fake-timers": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/fake-timers": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-mock": "^29.6.2"
+ "jest-mock": "^29.6.3"
}
},
"@jest/expect": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.2.tgz",
- "integrity": "sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.4.tgz",
+ "integrity": "sha512-Warhsa7d23+3X5bLbrbYvaehcgX5TLYhI03JKoedTiI8uJU4IhqYBWF7OSSgUyz4IgLpUYPkK0AehA5/fRclAA==",
"dev": true,
"requires": {
- "expect": "^29.6.2",
- "jest-snapshot": "^29.6.2"
+ "expect": "^29.6.4",
+ "jest-snapshot": "^29.6.4"
}
},
"@jest/expect-utils": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.2.tgz",
- "integrity": "sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.4.tgz",
+ "integrity": "sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg==",
"dev": true,
"requires": {
- "jest-get-type": "^29.4.3"
+ "jest-get-type": "^29.6.3"
}
},
"@jest/fake-timers": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.2.tgz",
- "integrity": "sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz",
+ "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==",
"dev": true,
"requires": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@sinonjs/fake-timers": "^10.0.2",
"@types/node": "*",
- "jest-message-util": "^29.6.2",
- "jest-mock": "^29.6.2",
- "jest-util": "^29.6.2"
+ "jest-message-util": "^29.6.3",
+ "jest-mock": "^29.6.3",
+ "jest-util": "^29.6.3"
}
},
"@jest/globals": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.2.tgz",
- "integrity": "sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.4.tgz",
+ "integrity": "sha512-wVIn5bdtjlChhXAzVXavcY/3PEjf4VqM174BM3eGL5kMxLiZD5CLnbmkEyA1Dwh9q8XjP6E8RwjBsY/iCWrWsA==",
"dev": true,
"requires": {
- "@jest/environment": "^29.6.2",
- "@jest/expect": "^29.6.2",
- "@jest/types": "^29.6.1",
- "jest-mock": "^29.6.2"
+ "@jest/environment": "^29.6.4",
+ "@jest/expect": "^29.6.4",
+ "@jest/types": "^29.6.3",
+ "jest-mock": "^29.6.3"
}
},
"@jest/reporters": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.2.tgz",
- "integrity": "sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.4.tgz",
+ "integrity": "sha512-sxUjWxm7QdchdrD3NfWKrL8FBsortZeibSJv4XLjESOOjSUOkjQcb0ZHJwfhEGIvBvTluTzfG2yZWZhkrXJu8g==",
"dev": true,
"requires": {
"@bcoe/v8-coverage": "^0.2.3",
- "@jest/console": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/console": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@jridgewell/trace-mapping": "^0.3.18",
"@types/node": "*",
"chalk": "^4.0.0",
@@ -19540,13 +19522,13 @@
"glob": "^7.1.3",
"graceful-fs": "^4.2.9",
"istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-instrument": "^5.1.0",
+ "istanbul-lib-instrument": "^6.0.0",
"istanbul-lib-report": "^3.0.0",
"istanbul-lib-source-maps": "^4.0.0",
"istanbul-reports": "^3.1.3",
- "jest-message-util": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-worker": "^29.6.2",
+ "jest-message-util": "^29.6.3",
+ "jest-util": "^29.6.3",
+ "jest-worker": "^29.6.4",
"slash": "^3.0.0",
"string-length": "^4.0.1",
"strip-ansi": "^6.0.0",
@@ -19594,13 +19576,13 @@
"dev": true
},
"jest-worker": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz",
- "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz",
+ "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==",
"dev": true,
"requires": {
"@types/node": "*",
- "jest-util": "^29.6.2",
+ "jest-util": "^29.6.3",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
@@ -19628,18 +19610,18 @@
}
},
"@jest/schemas": {
- "version": "29.6.0",
- "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.0.tgz",
- "integrity": "sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
"dev": true,
"requires": {
"@sinclair/typebox": "^0.27.8"
}
},
"@jest/source-map": {
- "version": "29.6.0",
- "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.0.tgz",
- "integrity": "sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
+ "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
"dev": true,
"requires": {
"@jridgewell/trace-mapping": "^0.3.18",
@@ -19648,46 +19630,46 @@
}
},
"@jest/test-result": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.2.tgz",
- "integrity": "sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.4.tgz",
+ "integrity": "sha512-uQ1C0AUEN90/dsyEirgMLlouROgSY+Wc/JanVVk0OiUKa5UFh7sJpMEM3aoUBAz2BRNvUJ8j3d294WFuRxSyOQ==",
"dev": true,
"requires": {
- "@jest/console": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/console": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"collect-v8-coverage": "^1.0.0"
}
},
"@jest/test-sequencer": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz",
- "integrity": "sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.4.tgz",
+ "integrity": "sha512-E84M6LbpcRq3fT4ckfKs9ryVanwkaIB0Ws9bw3/yP4seRLg/VaCZ/LgW0MCq5wwk4/iP/qnilD41aj2fsw2RMg==",
"dev": true,
"requires": {
- "@jest/test-result": "^29.6.2",
+ "@jest/test-result": "^29.6.4",
"graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.6.2",
+ "jest-haste-map": "^29.6.4",
"slash": "^3.0.0"
}
},
"@jest/transform": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.2.tgz",
- "integrity": "sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz",
+ "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==",
"dev": true,
"requires": {
"@babel/core": "^7.11.6",
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@jridgewell/trace-mapping": "^0.3.18",
"babel-plugin-istanbul": "^6.1.1",
"chalk": "^4.0.0",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.6.2",
- "jest-regex-util": "^29.4.3",
- "jest-util": "^29.6.2",
+ "jest-haste-map": "^29.6.4",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.6.3",
"micromatch": "^4.0.4",
"pirates": "^4.0.4",
"slash": "^3.0.0",
@@ -19752,12 +19734,12 @@
}
},
"@jest/types": {
- "version": "29.6.1",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.1.tgz",
- "integrity": "sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
"dev": true,
"requires": {
- "@jest/schemas": "^29.6.0",
+ "@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
"@types/node": "*",
@@ -19870,12 +19852,6 @@
"resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz",
"integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q=="
},
- "@nicolo-ribaudo/semver-v6": {
- "version": "6.3.3",
- "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz",
- "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==",
- "dev": true
- },
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -20850,14 +20826,15 @@
}
},
"assert": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz",
- "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz",
+ "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==",
"requires": {
- "es6-object-assign": "^1.1.0",
- "is-nan": "^1.2.1",
- "object-is": "^1.0.1",
- "util": "^0.12.0"
+ "call-bind": "^1.0.2",
+ "is-nan": "^1.3.2",
+ "object-is": "^1.1.5",
+ "object.assign": "^4.1.4",
+ "util": "^0.12.5"
}
},
"assert-plus": {
@@ -20912,13 +20889,13 @@
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"autoprefixer": {
- "version": "10.4.14",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
- "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==",
+ "version": "10.4.15",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz",
+ "integrity": "sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==",
"dev": true,
"requires": {
- "browserslist": "^4.21.5",
- "caniuse-lite": "^1.0.30001464",
+ "browserslist": "^4.21.10",
+ "caniuse-lite": "^1.0.30001520",
"fraction.js": "^4.2.0",
"normalize-range": "^0.1.2",
"picocolors": "^1.0.0",
@@ -20941,15 +20918,15 @@
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
},
"babel-jest": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.2.tgz",
- "integrity": "sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.4.tgz",
+ "integrity": "sha512-meLj23UlSLddj6PC+YTOFRgDAtjnZom8w/ACsrx0gtPtv5cJZk0A5Unk5bV4wixD7XaPCN1fQvpww8czkZURmw==",
"dev": true,
"requires": {
- "@jest/transform": "^29.6.2",
+ "@jest/transform": "^29.6.4",
"@types/babel__core": "^7.1.14",
"babel-plugin-istanbul": "^6.1.1",
- "babel-preset-jest": "^29.5.0",
+ "babel-preset-jest": "^29.6.3",
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
"slash": "^3.0.0"
@@ -21027,12 +21004,27 @@
"@istanbuljs/schema": "^0.1.2",
"istanbul-lib-instrument": "^5.0.4",
"test-exclude": "^6.0.0"
+ },
+ "dependencies": {
+ "istanbul-lib-instrument": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+ "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+ "dev": true,
+ "requires": {
+ "@babel/core": "^7.12.3",
+ "@babel/parser": "^7.14.7",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.2.0",
+ "semver": "^6.3.0"
+ }
+ }
}
},
"babel-plugin-jest-hoist": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz",
- "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
+ "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
"dev": true,
"requires": {
"@babel/template": "^7.3.3",
@@ -21052,19 +21044,19 @@
}
},
"babel-plugin-polyfill-corejs3": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.2.tgz",
- "integrity": "sha512-Cid+Jv1BrY9ReW9lIfNlNpsI53N+FN7gE+f73zLAUbr9C52W4gKLWSByx47pfDJsEysojKArqOtOKZSVIIUTuQ==",
+ "version": "0.8.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz",
+ "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==",
"dev": true,
"requires": {
- "@babel/helper-define-polyfill-provider": "^0.4.1",
+ "@babel/helper-define-polyfill-provider": "^0.4.2",
"core-js-compat": "^3.31.0"
},
"dependencies": {
"@babel/helper-define-polyfill-provider": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.1.tgz",
- "integrity": "sha512-kX4oXixDxG197yhX+J3Wp+NpL2wuCFjWQAr6yX2jtCnflK9ulMI51ULFGIrWiX1jGfvAxdHp+XQCcP2bZGPs9A==",
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz",
+ "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==",
"dev": true,
"requires": {
"@babel/helper-compilation-targets": "^7.22.6",
@@ -21121,12 +21113,12 @@
}
},
"babel-preset-jest": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz",
- "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
+ "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
"dev": true,
"requires": {
- "babel-plugin-jest-hoist": "^29.5.0",
+ "babel-plugin-jest-hoist": "^29.6.3",
"babel-preset-current-node-syntax": "^1.0.0"
}
},
@@ -21172,9 +21164,9 @@
"dev": true
},
"bignumber.js": {
- "version": "9.1.1",
- "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz",
- "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig=="
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
+ "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug=="
},
"binary-extensions": {
"version": "2.2.0",
@@ -21348,13 +21340,13 @@
}
},
"browserslist": {
- "version": "4.21.9",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz",
- "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==",
+ "version": "4.21.10",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
+ "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
"requires": {
- "caniuse-lite": "^1.0.30001503",
- "electron-to-chromium": "^1.4.431",
- "node-releases": "^2.0.12",
+ "caniuse-lite": "^1.0.30001517",
+ "electron-to-chromium": "^1.4.477",
+ "node-releases": "^2.0.13",
"update-browserslist-db": "^1.0.11"
}
},
@@ -21545,9 +21537,9 @@
}
},
"caniuse-lite": {
- "version": "1.0.30001512",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz",
- "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw=="
+ "version": "1.0.30001520",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001520.tgz",
+ "integrity": "sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA=="
},
"caseless": {
"version": "0.12.0",
@@ -21584,9 +21576,9 @@
"dev": true
},
"chart.js": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.2.tgz",
- "integrity": "sha512-pvQNyFOY1QmbmIr8oDORL16/FFivfxj8V26VFpFilMo4cNvkV5WXLJetDio365pd9gKUHGdirUTbqJfw8tr+Dg==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.0.tgz",
+ "integrity": "sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==",
"requires": {
"@kurkle/color": "^0.3.0"
}
@@ -21881,9 +21873,9 @@
}
},
"core-js": {
- "version": "3.32.0",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.0.tgz",
- "integrity": "sha512-rd4rYZNlF3WuoYuRIDEmbR/ga9CeuWX9U05umAvgrrZoHY4Z++cp/xwPQMvUpBB4Ag6J8KfD80G0zwCyaSxDww=="
+ "version": "3.32.2",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.2.tgz",
+ "integrity": "sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ=="
},
"core-js-compat": {
"version": "3.31.0",
@@ -22337,9 +22329,9 @@
}
},
"dedent": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.3.0.tgz",
- "integrity": "sha512-7glNLfvdsMzZm3FpRY1CHuI2lbYDR+71YmrhmTZjYFD5pfT0ACgnGRdrrC9Mk2uICnzkcdelCx5at787UDGOvg==",
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz",
+ "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==",
"dev": true,
"requires": {}
},
@@ -22426,9 +22418,9 @@
"dev": true
},
"diff-sequences": {
- "version": "29.4.3",
- "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz",
- "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+ "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
"dev": true
},
"diffie-hellman": {
@@ -22542,9 +22534,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"electron-to-chromium": {
- "version": "1.4.450",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.450.tgz",
- "integrity": "sha512-BLG5HxSELlrMx7dJ2s+8SFlsCtJp37Zpk2VAxyC6CZtbc+9AJeZHfYHbrlSgdXp6saQ8StMqOTEDaBKgA7u1sw=="
+ "version": "1.4.490",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz",
+ "integrity": "sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A=="
},
"elliptic": {
"version": "6.5.4",
@@ -22763,11 +22755,6 @@
"es6-symbol": "^3.1.1"
}
},
- "es6-object-assign": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
- "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw="
- },
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
@@ -22858,16 +22845,16 @@
}
},
"eslint": {
- "version": "8.46.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz",
- "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==",
+ "version": "8.49.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz",
+ "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.1",
- "@eslint/js": "^8.46.0",
- "@humanwhocodes/config-array": "^0.11.10",
+ "@eslint/eslintrc": "^2.1.2",
+ "@eslint/js": "8.49.0",
+ "@humanwhocodes/config-array": "^0.11.11",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.12.4",
@@ -22877,7 +22864,7 @@
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.2",
+ "eslint-visitor-keys": "^3.4.3",
"espree": "^9.6.1",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
@@ -23100,9 +23087,9 @@
}
},
"eslint-plugin-import": {
- "version": "2.28.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz",
- "integrity": "sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==",
+ "version": "2.28.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz",
+ "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==",
"dev": true,
"requires": {
"array-includes": "^3.1.6",
@@ -23114,13 +23101,12 @@
"eslint-import-resolver-node": "^0.3.7",
"eslint-module-utils": "^2.8.0",
"has": "^1.0.3",
- "is-core-module": "^2.12.1",
+ "is-core-module": "^2.13.0",
"is-glob": "^4.0.3",
"minimatch": "^3.1.2",
"object.fromentries": "^2.0.6",
"object.groupby": "^1.0.0",
"object.values": "^1.1.6",
- "resolve": "^1.22.3",
"semver": "^6.3.1",
"tsconfig-paths": "^3.14.2"
},
@@ -23252,9 +23238,9 @@
}
},
"eslint-visitor-keys": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz",
- "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==",
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true
},
"espree": {
@@ -23863,17 +23849,16 @@
"dev": true
},
"expect": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.2.tgz",
- "integrity": "sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.4.tgz",
+ "integrity": "sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==",
"dev": true,
"requires": {
- "@jest/expect-utils": "^29.6.2",
- "@types/node": "*",
- "jest-get-type": "^29.4.3",
- "jest-matcher-utils": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-util": "^29.6.2"
+ "@jest/expect-utils": "^29.6.4",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-util": "^29.6.3"
}
},
"express": {
@@ -24842,9 +24827,9 @@
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="
},
"is-core-module": {
- "version": "2.12.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
- "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+ "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
"requires": {
"has": "^1.0.3"
}
@@ -25057,16 +25042,27 @@
"dev": true
},
"istanbul-lib-instrument": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
- "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz",
+ "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==",
"dev": true,
"requires": {
"@babel/core": "^7.12.3",
"@babel/parser": "^7.14.7",
"@istanbuljs/schema": "^0.1.2",
"istanbul-lib-coverage": "^3.2.0",
- "semver": "^6.3.0"
+ "semver": "^7.5.4"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ }
}
},
"istanbul-lib-report": {
@@ -25119,50 +25115,51 @@
}
},
"jest": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.2.tgz",
- "integrity": "sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.4.tgz",
+ "integrity": "sha512-tEFhVQFF/bzoYV1YuGyzLPZ6vlPrdfvDmmAxudA1dLEuiztqg2Rkx20vkKY32xiDROcD2KXlgZ7Cu8RPeEHRKw==",
"dev": true,
"requires": {
- "@jest/core": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/core": "^29.6.4",
+ "@jest/types": "^29.6.3",
"import-local": "^3.0.2",
- "jest-cli": "^29.6.2"
+ "jest-cli": "^29.6.4"
}
},
"jest-changed-files": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz",
- "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.6.3.tgz",
+ "integrity": "sha512-G5wDnElqLa4/c66ma5PG9eRjE342lIbF6SUnTJi26C3J28Fv2TVY2rOyKB9YGbSA5ogwevgmxc4j4aVjrEK6Yg==",
"dev": true,
"requires": {
"execa": "^5.0.0",
+ "jest-util": "^29.6.3",
"p-limit": "^3.1.0"
}
},
"jest-circus": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.2.tgz",
- "integrity": "sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.4.tgz",
+ "integrity": "sha512-YXNrRyntVUgDfZbjXWBMPslX1mQ8MrSG0oM/Y06j9EYubODIyHWP8hMUbjbZ19M3M+zamqEur7O80HODwACoJw==",
"dev": true,
"requires": {
- "@jest/environment": "^29.6.2",
- "@jest/expect": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/environment": "^29.6.4",
+ "@jest/expect": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"co": "^4.6.0",
"dedent": "^1.0.0",
"is-generator-fn": "^2.0.0",
- "jest-each": "^29.6.2",
- "jest-matcher-utils": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-runtime": "^29.6.2",
- "jest-snapshot": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-each": "^29.6.3",
+ "jest-matcher-utils": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-runtime": "^29.6.4",
+ "jest-snapshot": "^29.6.4",
+ "jest-util": "^29.6.3",
"p-limit": "^3.1.0",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"pure-rand": "^6.0.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.3"
@@ -25220,21 +25217,21 @@
}
},
"jest-cli": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.2.tgz",
- "integrity": "sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.4.tgz",
+ "integrity": "sha512-+uMCQ7oizMmh8ZwRfZzKIEszFY9ksjjEQnTEMTaL7fYiL3Kw4XhqT9bYh+A4DQKUb67hZn2KbtEnDuHvcgK4pQ==",
"dev": true,
"requires": {
- "@jest/core": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/core": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/types": "^29.6.3",
"chalk": "^4.0.0",
"exit": "^0.1.2",
"graceful-fs": "^4.2.9",
"import-local": "^3.0.2",
- "jest-config": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-validate": "^29.6.2",
+ "jest-config": "^29.6.4",
+ "jest-util": "^29.6.3",
+ "jest-validate": "^29.6.3",
"prompts": "^2.0.1",
"yargs": "^17.3.1"
},
@@ -25291,31 +25288,31 @@
}
},
"jest-config": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.2.tgz",
- "integrity": "sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.4.tgz",
+ "integrity": "sha512-JWohr3i9m2cVpBumQFv2akMEnFEPVOh+9L2xIBJhJ0zOaci2ZXuKJj0tgMKQCBZAKA09H049IR4HVS/43Qb19A==",
"dev": true,
"requires": {
"@babel/core": "^7.11.6",
- "@jest/test-sequencer": "^29.6.2",
- "@jest/types": "^29.6.1",
- "babel-jest": "^29.6.2",
+ "@jest/test-sequencer": "^29.6.4",
+ "@jest/types": "^29.6.3",
+ "babel-jest": "^29.6.4",
"chalk": "^4.0.0",
"ci-info": "^3.2.0",
"deepmerge": "^4.2.2",
"glob": "^7.1.3",
"graceful-fs": "^4.2.9",
- "jest-circus": "^29.6.2",
- "jest-environment-node": "^29.6.2",
- "jest-get-type": "^29.4.3",
- "jest-regex-util": "^29.4.3",
- "jest-resolve": "^29.6.2",
- "jest-runner": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-validate": "^29.6.2",
+ "jest-circus": "^29.6.4",
+ "jest-environment-node": "^29.6.4",
+ "jest-get-type": "^29.6.3",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.6.4",
+ "jest-runner": "^29.6.4",
+ "jest-util": "^29.6.3",
+ "jest-validate": "^29.6.3",
"micromatch": "^4.0.4",
"parse-json": "^5.2.0",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"slash": "^3.0.0",
"strip-json-comments": "^3.1.1"
},
@@ -25372,15 +25369,15 @@
}
},
"jest-diff": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.2.tgz",
- "integrity": "sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz",
+ "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
- "diff-sequences": "^29.4.3",
- "jest-get-type": "^29.4.3",
- "pretty-format": "^29.6.2"
+ "diff-sequences": "^29.6.3",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.6.3"
},
"dependencies": {
"ansi-styles": {
@@ -25435,25 +25432,25 @@
}
},
"jest-docblock": {
- "version": "29.4.3",
- "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz",
- "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.6.3.tgz",
+ "integrity": "sha512-2+H+GOTQBEm2+qFSQ7Ma+BvyV+waiIFxmZF5LdpBsAEjWX8QYjSCa4FrkIYtbfXUJJJnFCYrOtt6TZ+IAiTjBQ==",
"dev": true,
"requires": {
"detect-newline": "^3.0.0"
}
},
"jest-each": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.2.tgz",
- "integrity": "sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.3.tgz",
+ "integrity": "sha512-KoXfJ42k8cqbkfshW7sSHcdfnv5agDdHCPA87ZBdmHP+zJstTJc0ttQaJ/x7zK6noAL76hOuTIJ6ZkQRS5dcyg==",
"dev": true,
"requires": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"chalk": "^4.0.0",
- "jest-get-type": "^29.4.3",
- "jest-util": "^29.6.2",
- "pretty-format": "^29.6.2"
+ "jest-get-type": "^29.6.3",
+ "jest-util": "^29.6.3",
+ "pretty-format": "^29.6.3"
},
"dependencies": {
"ansi-styles": {
@@ -25508,57 +25505,57 @@
}
},
"jest-environment-jsdom": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.6.2.tgz",
- "integrity": "sha512-7oa/+266AAEgkzae8i1awNEfTfjwawWKLpiw2XesZmaoVVj9u9t8JOYx18cG29rbPNtkUlZ8V4b5Jb36y/VxoQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.6.4.tgz",
+ "integrity": "sha512-K6wfgUJ16DoMs02JYFid9lOsqfpoVtyJxpRlnTxUHzvZWBnnh2VNGRB9EC1Cro96TQdq5TtSjb3qUjNaJP9IyA==",
"dev": true,
"requires": {
- "@jest/environment": "^29.6.2",
- "@jest/fake-timers": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/environment": "^29.6.4",
+ "@jest/fake-timers": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/jsdom": "^20.0.0",
"@types/node": "*",
- "jest-mock": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-mock": "^29.6.3",
+ "jest-util": "^29.6.3",
"jsdom": "^20.0.0"
}
},
"jest-environment-node": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.2.tgz",
- "integrity": "sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.4.tgz",
+ "integrity": "sha512-i7SbpH2dEIFGNmxGCpSc2w9cA4qVD+wfvg2ZnfQ7XVrKL0NA5uDVBIiGH8SR4F0dKEv/0qI5r+aDomDf04DpEQ==",
"dev": true,
"requires": {
- "@jest/environment": "^29.6.2",
- "@jest/fake-timers": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/environment": "^29.6.4",
+ "@jest/fake-timers": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-mock": "^29.6.2",
- "jest-util": "^29.6.2"
+ "jest-mock": "^29.6.3",
+ "jest-util": "^29.6.3"
}
},
"jest-get-type": {
- "version": "29.4.3",
- "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz",
- "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
+ "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
"dev": true
},
"jest-haste-map": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.2.tgz",
- "integrity": "sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz",
+ "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==",
"dev": true,
"requires": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/graceful-fs": "^4.1.3",
"@types/node": "*",
"anymatch": "^3.0.3",
"fb-watchman": "^2.0.0",
"fsevents": "^2.3.2",
"graceful-fs": "^4.2.9",
- "jest-regex-util": "^29.4.3",
- "jest-util": "^29.6.2",
- "jest-worker": "^29.6.2",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.6.3",
+ "jest-worker": "^29.6.4",
"micromatch": "^4.0.4",
"walker": "^1.0.8"
},
@@ -25570,13 +25567,13 @@
"dev": true
},
"jest-worker": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz",
- "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz",
+ "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==",
"dev": true,
"requires": {
"@types/node": "*",
- "jest-util": "^29.6.2",
+ "jest-util": "^29.6.3",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
}
@@ -25593,25 +25590,25 @@
}
},
"jest-leak-detector": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz",
- "integrity": "sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz",
+ "integrity": "sha512-0kfbESIHXYdhAdpLsW7xdwmYhLf1BRu4AA118/OxFm0Ho1b2RcTmO4oF6aAMaxpxdxnJ3zve2rgwzNBD4Zbm7Q==",
"dev": true,
"requires": {
- "jest-get-type": "^29.4.3",
- "pretty-format": "^29.6.2"
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.6.3"
}
},
"jest-matcher-utils": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz",
- "integrity": "sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz",
+ "integrity": "sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
- "jest-diff": "^29.6.2",
- "jest-get-type": "^29.4.3",
- "pretty-format": "^29.6.2"
+ "jest-diff": "^29.6.4",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.6.3"
},
"dependencies": {
"ansi-styles": {
@@ -25666,18 +25663,18 @@
}
},
"jest-message-util": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.2.tgz",
- "integrity": "sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz",
+ "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.12.13",
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/stack-utils": "^2.0.0",
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
"micromatch": "^4.0.4",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"slash": "^3.0.0",
"stack-utils": "^2.0.3"
},
@@ -25734,14 +25731,14 @@
}
},
"jest-mock": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.2.tgz",
- "integrity": "sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz",
+ "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==",
"dev": true,
"requires": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-util": "^29.6.2"
+ "jest-util": "^29.6.3"
}
},
"jest-pnp-resolver": {
@@ -25752,23 +25749,23 @@
"requires": {}
},
"jest-regex-util": {
- "version": "29.4.3",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz",
- "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
+ "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
"dev": true
},
"jest-resolve": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.2.tgz",
- "integrity": "sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.4.tgz",
+ "integrity": "sha512-fPRq+0vcxsuGlG0O3gyoqGTAxasagOxEuyoxHeyxaZbc9QNek0AmJWSkhjlMG+mTsj+8knc/mWb3fXlRNVih7Q==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.6.2",
+ "jest-haste-map": "^29.6.4",
"jest-pnp-resolver": "^1.2.2",
- "jest-util": "^29.6.2",
- "jest-validate": "^29.6.2",
+ "jest-util": "^29.6.3",
+ "jest-validate": "^29.6.3",
"resolve": "^1.20.0",
"resolve.exports": "^2.0.0",
"slash": "^3.0.0"
@@ -25826,40 +25823,40 @@
}
},
"jest-resolve-dependencies": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz",
- "integrity": "sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.4.tgz",
+ "integrity": "sha512-7+6eAmr1ZBF3vOAJVsfLj1QdqeXG+WYhidfLHBRZqGN24MFRIiKG20ItpLw2qRAsW/D2ZUUmCNf6irUr/v6KHA==",
"dev": true,
"requires": {
- "jest-regex-util": "^29.4.3",
- "jest-snapshot": "^29.6.2"
+ "jest-regex-util": "^29.6.3",
+ "jest-snapshot": "^29.6.4"
}
},
"jest-runner": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.2.tgz",
- "integrity": "sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.4.tgz",
+ "integrity": "sha512-SDaLrMmtVlQYDuG0iSPYLycG8P9jLI+fRm8AF/xPKhYDB2g6xDWjXBrR5M8gEWsK6KVFlebpZ4QsrxdyIX1Jaw==",
"dev": true,
"requires": {
- "@jest/console": "^29.6.2",
- "@jest/environment": "^29.6.2",
- "@jest/test-result": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/console": "^29.6.4",
+ "@jest/environment": "^29.6.4",
+ "@jest/test-result": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"emittery": "^0.13.1",
"graceful-fs": "^4.2.9",
- "jest-docblock": "^29.4.3",
- "jest-environment-node": "^29.6.2",
- "jest-haste-map": "^29.6.2",
- "jest-leak-detector": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-resolve": "^29.6.2",
- "jest-runtime": "^29.6.2",
- "jest-util": "^29.6.2",
- "jest-watcher": "^29.6.2",
- "jest-worker": "^29.6.2",
+ "jest-docblock": "^29.6.3",
+ "jest-environment-node": "^29.6.4",
+ "jest-haste-map": "^29.6.4",
+ "jest-leak-detector": "^29.6.3",
+ "jest-message-util": "^29.6.3",
+ "jest-resolve": "^29.6.4",
+ "jest-runtime": "^29.6.4",
+ "jest-util": "^29.6.3",
+ "jest-watcher": "^29.6.4",
+ "jest-worker": "^29.6.4",
"p-limit": "^3.1.0",
"source-map-support": "0.5.13"
},
@@ -25905,13 +25902,13 @@
"dev": true
},
"jest-worker": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.2.tgz",
- "integrity": "sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz",
+ "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==",
"dev": true,
"requires": {
"@types/node": "*",
- "jest-util": "^29.6.2",
+ "jest-util": "^29.6.3",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
@@ -25949,31 +25946,31 @@
}
},
"jest-runtime": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.2.tgz",
- "integrity": "sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg==",
- "dev": true,
- "requires": {
- "@jest/environment": "^29.6.2",
- "@jest/fake-timers": "^29.6.2",
- "@jest/globals": "^29.6.2",
- "@jest/source-map": "^29.6.0",
- "@jest/test-result": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.4.tgz",
+ "integrity": "sha512-s/QxMBLvmwLdchKEjcLfwzP7h+jsHvNEtxGP5P+Fl1FMaJX2jMiIqe4rJw4tFprzCwuSvVUo9bn0uj4gNRXsbA==",
+ "dev": true,
+ "requires": {
+ "@jest/environment": "^29.6.4",
+ "@jest/fake-timers": "^29.6.4",
+ "@jest/globals": "^29.6.4",
+ "@jest/source-map": "^29.6.3",
+ "@jest/test-result": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"cjs-module-lexer": "^1.0.0",
"collect-v8-coverage": "^1.0.0",
"glob": "^7.1.3",
"graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-mock": "^29.6.2",
- "jest-regex-util": "^29.4.3",
- "jest-resolve": "^29.6.2",
- "jest-snapshot": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-haste-map": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-mock": "^29.6.3",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.6.4",
+ "jest-snapshot": "^29.6.4",
+ "jest-util": "^29.6.3",
"slash": "^3.0.0",
"strip-bom": "^4.0.0"
},
@@ -26030,9 +26027,9 @@
}
},
"jest-snapshot": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.2.tgz",
- "integrity": "sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.4.tgz",
+ "integrity": "sha512-VC1N8ED7+4uboUKGIDsbvNAZb6LakgIPgAF4RSpF13dN6YaMokfRqO+BaqK4zIh6X3JffgwbzuGqDEjHm/MrvA==",
"dev": true,
"requires": {
"@babel/core": "^7.11.6",
@@ -26040,20 +26037,20 @@
"@babel/plugin-syntax-jsx": "^7.7.2",
"@babel/plugin-syntax-typescript": "^7.7.2",
"@babel/types": "^7.3.3",
- "@jest/expect-utils": "^29.6.2",
- "@jest/transform": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/expect-utils": "^29.6.4",
+ "@jest/transform": "^29.6.4",
+ "@jest/types": "^29.6.3",
"babel-preset-current-node-syntax": "^1.0.0",
"chalk": "^4.0.0",
- "expect": "^29.6.2",
+ "expect": "^29.6.4",
"graceful-fs": "^4.2.9",
- "jest-diff": "^29.6.2",
- "jest-get-type": "^29.4.3",
- "jest-matcher-utils": "^29.6.2",
- "jest-message-util": "^29.6.2",
- "jest-util": "^29.6.2",
+ "jest-diff": "^29.6.4",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.6.4",
+ "jest-message-util": "^29.6.3",
+ "jest-util": "^29.6.3",
"natural-compare": "^1.4.0",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.6.3",
"semver": "^7.5.3"
},
"dependencies": {
@@ -26118,12 +26115,12 @@
}
},
"jest-util": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.2.tgz",
- "integrity": "sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz",
+ "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==",
"dev": true,
"requires": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"chalk": "^4.0.0",
"ci-info": "^3.2.0",
@@ -26183,17 +26180,17 @@
}
},
"jest-validate": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.2.tgz",
- "integrity": "sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.3.tgz",
+ "integrity": "sha512-e7KWZcAIX+2W1o3cHfnqpGajdCs1jSM3DkXjGeLSNmCazv1EeI1ggTeK5wdZhF+7N+g44JI2Od3veojoaumlfg==",
"dev": true,
"requires": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"camelcase": "^6.2.0",
"chalk": "^4.0.0",
- "jest-get-type": "^29.4.3",
+ "jest-get-type": "^29.6.3",
"leven": "^3.1.0",
- "pretty-format": "^29.6.2"
+ "pretty-format": "^29.6.3"
},
"dependencies": {
"ansi-styles": {
@@ -26254,18 +26251,18 @@
}
},
"jest-watcher": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.2.tgz",
- "integrity": "sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA==",
+ "version": "29.6.4",
+ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.4.tgz",
+ "integrity": "sha512-oqUWvx6+On04ShsT00Ir9T4/FvBeEh2M9PTubgITPxDa739p4hoQweWPRGyYeaojgT0xTpZKF0Y/rSY1UgMxvQ==",
"dev": true,
"requires": {
- "@jest/test-result": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/test-result": "^29.6.4",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
"ansi-escapes": "^4.2.1",
"chalk": "^4.0.0",
"emittery": "^0.13.1",
- "jest-util": "^29.6.2",
+ "jest-util": "^29.6.3",
"string-length": "^4.0.1"
},
"dependencies": {
@@ -26355,9 +26352,9 @@
"dev": true
},
"jquery": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz",
- "integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ=="
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
+ "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
},
"jquery-mousewheel": {
"version": "3.1.13",
@@ -26894,9 +26891,9 @@
"integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU="
},
"luxon": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz",
- "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg=="
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.3.tgz",
+ "integrity": "sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg=="
},
"make-dir": {
"version": "4.0.0",
@@ -27347,9 +27344,9 @@
"dev": true
},
"node-releases": {
- "version": "2.0.12",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz",
- "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ=="
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+ "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ=="
},
"normalize-path": {
"version": "3.0.0",
@@ -27446,7 +27443,6 @@
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
"integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "dev": true,
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.4",
@@ -27702,9 +27698,9 @@
"version": "file:../../../deps/phoenix_html"
},
"photoswipe": {
- "version": "5.3.8",
- "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.3.8.tgz",
- "integrity": "sha512-4vTzOQt8GP4Chsm0s+8j2xDtVHAEN252PxrU12A1zXauNn0zD5HRHgjALKO2GKTyBnTnOrJUOxbV8LTrFIMrYw=="
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.4.0.tgz",
+ "integrity": "sha512-PZvdK1D94TApU0MNWc9H6eXOolKJOMkgt7CJ9ZfIdkHR4CrEj47MOe4Vrlcv6ZpHslK+uKS6Ai3y3VIe7gsi+Q=="
},
"picocolors": {
"version": "1.0.0",
@@ -27804,9 +27800,9 @@
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
},
"postcss": {
- "version": "8.4.27",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
- "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
+ "version": "8.4.29",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz",
+ "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==",
"dev": true,
"requires": {
"nanoid": "^3.3.6",
@@ -28154,12 +28150,12 @@
"dev": true
},
"pretty-format": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.2.tgz",
- "integrity": "sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz",
+ "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==",
"dev": true,
"requires": {
- "@jest/schemas": "^29.6.0",
+ "@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
"react-is": "^18.0.0"
},
@@ -28562,9 +28558,9 @@
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
},
"regenerator-transform": {
- "version": "0.15.1",
- "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz",
- "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==",
+ "version": "0.15.2",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
+ "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==",
"dev": true,
"requires": {
"@babel/runtime": "^7.8.4"
@@ -28833,9 +28829,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sass": {
- "version": "1.64.2",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.64.2.tgz",
- "integrity": "sha512-TnDlfc+CRnUAgLO9D8cQLFu/GIjJIzJCGkE7o4ekIGQOH7T3GetiRR/PsTWJUHhkzcSPrARkPI+gNWn5alCzDg==",
+ "version": "1.66.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz",
+ "integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==",
"dev": true,
"requires": {
"chokidar": ">=3.0.0 <4.0.0",
@@ -29463,9 +29459,9 @@
}
},
"sweetalert2": {
- "version": "11.7.20",
- "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.7.20.tgz",
- "integrity": "sha512-GdU1TkiLpGGC0mcPV8bKmS7G0MR7caxambPkEU8zyepRSNR9EaEvIjNhX5QNkL0VFVzHbI3l12NtuEklkJ0D4Q=="
+ "version": "11.7.27",
+ "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.7.27.tgz",
+ "integrity": "sha512-QbRXGQn1sb7HEhzA/K2xtWIwQHh/qkSbb1w6jYcTql2xy17876lTREEt1D4X6Q0x2wHtfUjKJ+Cb8IVkRoq7DQ=="
},
"symbol-tree": {
"version": "3.2.4",
@@ -29859,12 +29855,12 @@
"integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ=="
},
"url": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/url/-/url-0.11.1.tgz",
- "integrity": "sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA==",
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.11.2.tgz",
+ "integrity": "sha512-7yIgNnrST44S7PJ5+jXbdIupfU1nWUdQJBFBeJRclPXiWgCvrSq5Frw8lr/i//n5sqDfzoKmBymMS81l4U/7cg==",
"requires": {
"punycode": "^1.4.1",
- "qs": "^6.11.0"
+ "qs": "^6.11.2"
},
"dependencies": {
"punycode": {
@@ -29969,9 +29965,9 @@
}
},
"viewerjs": {
- "version": "1.11.4",
- "resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.4.tgz",
- "integrity": "sha512-/mnqMIwt5Bi9j59+48OqQtqgOx8oh186Xshdr/dqqBrakMSMlLt/jmeNHBod0PvOkesZf66ivQbWmtWYBlKetg=="
+ "version": "1.11.5",
+ "resolved": "https://registry.npmjs.org/viewerjs/-/viewerjs-1.11.5.tgz",
+ "integrity": "sha512-nsvQkC5jnqZ/2ggFYWUH5gpUGPtFAYidsFh8Q7B7sioAdqJzSJrELvbu9ozUm0W+A2uHN5XuuiheHHB+dWiPEA=="
},
"w3c-hr-time": {
"version": "1.0.2",
diff --git a/apps/block_scout_web/assets/package.json b/apps/block_scout_web/assets/package.json
index 28a60def3631..964bd513fb28 100644
--- a/apps/block_scout_web/assets/package.json
+++ b/apps/block_scout_web/assets/package.json
@@ -19,24 +19,24 @@
"eslint": "eslint js/**"
},
"dependencies": {
- "@fortawesome/fontawesome-free": "^6.4.0",
- "@amplitude/analytics-browser": "^2.1.3",
+ "@fortawesome/fontawesome-free": "^6.4.2",
+ "@amplitude/analytics-browser": "^2.2.3",
"@tarekraafat/autocomplete.js": "^10.2.7",
"@walletconnect/web3-provider": "^1.8.0",
- "assert": "^2.0.0",
- "bignumber.js": "^9.1.1",
+ "assert": "^2.1.0",
+ "bignumber.js": "^9.1.2",
"bootstrap": "^4.6.0",
- "chart.js": "^4.3.2",
+ "chart.js": "^4.4.0",
"chartjs-adapter-luxon": "^1.3.1",
"clipboard": "^2.0.11",
- "core-js": "^3.32.0",
+ "core-js": "^3.32.2",
"crypto-browserify": "^3.12.0",
"dropzone": "^5.9.3",
"eth-net-props": "^1.0.41",
"highlight.js": "^11.8.0",
"https-browserify": "^1.0.0",
"humps": "^2.0.1",
- "jquery": "^3.7.0",
+ "jquery": "^3.7.1",
"js-cookie": "^3.0.5",
"lodash.debounce": "^4.0.8",
"lodash.differenceby": "^4.8.0",
@@ -56,7 +56,7 @@
"lodash.omit": "^4.5.0",
"lodash.rangeright": "^4.2.0",
"lodash.reduce": "^4.6.0",
- "luxon": "^3.3.0",
+ "luxon": "^3.4.3",
"malihu-custom-scrollbar-plugin": "3.1.5",
"mixpanel-browser": "^2.47.0",
"moment": "^2.29.4",
@@ -66,42 +66,42 @@
"path-parser": "^6.1.0",
"phoenix": "file:../../../deps/phoenix",
"phoenix_html": "file:../../../deps/phoenix_html",
- "photoswipe": "^5.3.8",
+ "photoswipe": "^5.4.0",
"pikaday": "^1.8.2",
"popper.js": "^1.14.7",
"reduce-reducers": "^1.0.4",
"redux": "^4.2.1",
"stream-browserify": "^3.0.0",
"stream-http": "^3.1.1",
- "sweetalert2": "^11.7.20",
+ "sweetalert2": "^11.7.27",
"urijs": "^1.19.11",
- "url": "^0.11.1",
+ "url": "^0.11.2",
"util": "^0.12.5",
- "viewerjs": "^1.11.4",
+ "viewerjs": "^1.11.5",
"web3": "^1.10.0",
"web3modal": "^1.9.12",
"xss": "^1.0.14"
},
"devDependencies": {
- "@babel/core": "^7.22.9",
- "@babel/preset-env": "^7.22.9",
- "autoprefixer": "^10.4.14",
+ "@babel/core": "^7.22.17",
+ "@babel/preset-env": "^7.22.15",
+ "autoprefixer": "^10.4.15",
"babel-loader": "^9.1.3",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^5.2.7",
"css-minimizer-webpack-plugin": "^5.0.1",
- "eslint": "^8.46.0",
+ "eslint": "^8.49.0",
"eslint-config-standard": "^17.1.0",
- "eslint-plugin-import": "^2.28.0",
+ "eslint-plugin-import": "^2.28.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"file-loader": "^6.2.0",
- "jest": "^29.6.2",
- "jest-environment-jsdom": "^29.6.2",
+ "jest": "^29.6.4",
+ "jest-environment-jsdom": "^29.6.4",
"mini-css-extract-plugin": "^2.7.6",
- "postcss": "^8.4.27",
+ "postcss": "^8.4.29",
"postcss-loader": "^7.3.3",
- "sass": "^1.64.2",
+ "sass": "^1.66.1",
"sass-loader": "^13.3.2",
"style-loader": "^3.3.3",
"webpack": "^5.88.2",
diff --git a/apps/block_scout_web/lib/block_scout_web/api_router.ex b/apps/block_scout_web/lib/block_scout_web/api_router.ex
index 12245a9d9bd5..c422faed4620 100644
--- a/apps/block_scout_web/lib/block_scout_web/api_router.ex
+++ b/apps/block_scout_web/lib/block_scout_web/api_router.ex
@@ -13,7 +13,7 @@ defmodule BlockScoutWeb.ApiRouter do
Router for API
"""
use BlockScoutWeb, :router
- alias BlockScoutWeb.{APIKeyV2Router, SmartContractsApiV2Router}
+ alias BlockScoutWeb.{AddressTransactionController, APIKeyV2Router, SmartContractsApiV2Router}
alias BlockScoutWeb.Plug.{CheckAccountAPI, CheckApiV2, RateLimit}
forward("/v2/smart-contracts", SmartContractsApiV2Router)
@@ -124,6 +124,7 @@ defmodule BlockScoutWeb.ApiRouter do
scope "/search" do
get("/", V2.SearchController, :search)
get("/check-redirect", V2.SearchController, :check_redirect)
+ get("/quick", V2.SearchController, :quick_search)
end
scope "/config" do
@@ -134,12 +135,12 @@ defmodule BlockScoutWeb.ApiRouter do
scope "/transactions" do
get("/", V2.TransactionController, :transactions)
get("/watchlist", V2.TransactionController, :watchlist_transactions)
- get("/:transaction_hash", V2.TransactionController, :transaction)
- get("/:transaction_hash/token-transfers", V2.TransactionController, :token_transfers)
- get("/:transaction_hash/internal-transactions", V2.TransactionController, :internal_transactions)
- get("/:transaction_hash/logs", V2.TransactionController, :logs)
- get("/:transaction_hash/raw-trace", V2.TransactionController, :raw_trace)
- get("/:transaction_hash/state-changes", V2.TransactionController, :state_changes)
+ get("/:transaction_hash_param", V2.TransactionController, :transaction)
+ get("/:transaction_hash_param/token-transfers", V2.TransactionController, :token_transfers)
+ get("/:transaction_hash_param/internal-transactions", V2.TransactionController, :internal_transactions)
+ get("/:transaction_hash_param/logs", V2.TransactionController, :logs)
+ get("/:transaction_hash_param/raw-trace", V2.TransactionController, :raw_trace)
+ get("/:transaction_hash_param/state-changes", V2.TransactionController, :state_changes)
end
scope "/blocks" do
@@ -151,31 +152,32 @@ defmodule BlockScoutWeb.ApiRouter do
scope "/addresses" do
get("/", V2.AddressController, :addresses_list)
- get("/:address_hash", V2.AddressController, :address)
- get("/:address_hash/counters", V2.AddressController, :counters)
- get("/:address_hash/token-balances", V2.AddressController, :token_balances)
- get("/:address_hash/tokens", V2.AddressController, :tokens)
- get("/:address_hash/transactions", V2.AddressController, :transactions)
- get("/:address_hash/token-transfers", V2.AddressController, :token_transfers)
- get("/:address_hash/internal-transactions", V2.AddressController, :internal_transactions)
- get("/:address_hash/logs", V2.AddressController, :logs)
- get("/:address_hash/blocks-validated", V2.AddressController, :blocks_validated)
- get("/:address_hash/coin-balance-history", V2.AddressController, :coin_balance_history)
- get("/:address_hash/coin-balance-history-by-day", V2.AddressController, :coin_balance_history_by_day)
- get("/:address_hash/withdrawals", V2.AddressController, :withdrawals)
+ get("/:address_hash_param", V2.AddressController, :address)
+ get("/:address_hash_param/tabs-counters", V2.AddressController, :tabs_counters)
+ get("/:address_hash_param/counters", V2.AddressController, :counters)
+ get("/:address_hash_param/token-balances", V2.AddressController, :token_balances)
+ get("/:address_hash_param/tokens", V2.AddressController, :tokens)
+ get("/:address_hash_param/transactions", V2.AddressController, :transactions)
+ get("/:address_hash_param/token-transfers", V2.AddressController, :token_transfers)
+ get("/:address_hash_param/internal-transactions", V2.AddressController, :internal_transactions)
+ get("/:address_hash_param/logs", V2.AddressController, :logs)
+ get("/:address_hash_param/blocks-validated", V2.AddressController, :blocks_validated)
+ get("/:address_hash_param/coin-balance-history", V2.AddressController, :coin_balance_history)
+ get("/:address_hash_param/coin-balance-history-by-day", V2.AddressController, :coin_balance_history_by_day)
+ get("/:address_hash_param/withdrawals", V2.AddressController, :withdrawals)
end
scope "/tokens" do
get("/", V2.TokenController, :tokens_list)
- get("/:address_hash", V2.TokenController, :token)
- get("/:address_hash/counters", V2.TokenController, :counters)
- get("/:address_hash/transfers", V2.TokenController, :transfers)
- get("/:address_hash/holders", V2.TokenController, :holders)
- get("/:address_hash/instances", V2.TokenController, :instances)
- get("/:address_hash/instances/:token_id", V2.TokenController, :instance)
- get("/:address_hash/instances/:token_id/transfers", V2.TokenController, :transfers_by_instance)
- get("/:address_hash/instances/:token_id/holders", V2.TokenController, :holders_by_instance)
- get("/:address_hash/instances/:token_id/transfers-count", V2.TokenController, :transfers_count_by_instance)
+ get("/:address_hash_param", V2.TokenController, :token)
+ get("/:address_hash_param/counters", V2.TokenController, :counters)
+ get("/:address_hash_param/transfers", V2.TokenController, :transfers)
+ get("/:address_hash_param/holders", V2.TokenController, :holders)
+ get("/:address_hash_param/instances", V2.TokenController, :instances)
+ get("/:address_hash_param/instances/:token_id", V2.TokenController, :instance)
+ get("/:address_hash_param/instances/:token_id/transfers", V2.TokenController, :transfers_by_instance)
+ get("/:address_hash_param/instances/:token_id/holders", V2.TokenController, :holders_by_instance)
+ get("/:address_hash_param/instances/:token_id/transfers-count", V2.TokenController, :transfers_count_by_instance)
end
scope "/main-page" do
@@ -209,6 +211,22 @@ defmodule BlockScoutWeb.ApiRouter do
# leave the same endpoint in v1 in order to keep backward compatibility
get("/search", SearchController, :search)
+ @max_complexity 200
+
+ forward("/graphql", Absinthe.Plug,
+ schema: BlockScoutWeb.Schema,
+ analyze_complexity: true,
+ max_complexity: @max_complexity
+ )
+
+ get("/transactions-csv", AddressTransactionController, :transactions_csv)
+
+ get("/token-transfers-csv", AddressTransactionController, :token_transfers_csv)
+
+ get("/internal-transactions-csv", AddressTransactionController, :internal_transactions_csv)
+
+ get("/logs-csv", AddressTransactionController, :logs_csv)
+
scope "/health" do
get("/", HealthController, :health)
get("/liveness", HealthController, :liveness)
diff --git a/apps/block_scout_web/lib/block_scout_web/channels/address_channel.ex b/apps/block_scout_web/lib/block_scout_web/channels/address_channel.ex
index ba808cc16f2b..f0ead554c72d 100644
--- a/apps/block_scout_web/lib/block_scout_web/channels/address_channel.ex
+++ b/apps/block_scout_web/lib/block_scout_web/channels/address_channel.ex
@@ -4,6 +4,8 @@ defmodule BlockScoutWeb.AddressChannel do
"""
use BlockScoutWeb, :channel
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
alias BlockScoutWeb.API.V2.AddressView, as: AddressViewAPI
alias BlockScoutWeb.API.V2.SmartContractView, as: SmartContractViewAPI
alias BlockScoutWeb.API.V2.TransactionView, as: TransactionViewAPI
@@ -28,11 +30,13 @@ defmodule BlockScoutWeb.AddressChannel do
"transaction",
"verification_result",
"token_transfer",
- "pending_transaction"
+ "pending_transaction",
+ "address_current_token_balances"
])
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
+ @current_token_balances_limit 50
def join("addresses:" <> address_hash, _params, socket) do
{:ok, %{}, assign(socket, :address_hash, address_hash)}
@@ -225,6 +229,34 @@ defmodule BlockScoutWeb.AddressChannel do
def handle_out("pending_transaction", data, socket), do: handle_transaction(data, socket, "transaction")
+ def handle_out(
+ "address_current_token_balances",
+ %{address_current_token_balances: address_current_token_balances},
+ %Phoenix.Socket{handler: BlockScoutWeb.UserSocketV2} = socket
+ ) do
+ push_current_token_balances(socket, address_current_token_balances, "erc_20", "ERC-20")
+ push_current_token_balances(socket, address_current_token_balances, "erc_721", "ERC-721")
+ push_current_token_balances(socket, address_current_token_balances, "erc_1155", "ERC-1155")
+
+ {:noreply, socket}
+ end
+
+ def handle_out("address_current_token_balances", _, socket) do
+ {:noreply, socket}
+ end
+
+ defp push_current_token_balances(socket, address_current_token_balances, event_postfix, token_type) do
+ filtered_ctbs = address_current_token_balances |> Enum.filter(fn ctb -> ctb.token_type == token_type end)
+
+ push(socket, "updated_token_balances_" <> event_postfix, %{
+ token_balances:
+ AddressViewAPI.render("token_balances.json", %{
+ token_balances: Enum.take(filtered_ctbs, @current_token_balances_limit)
+ }),
+ overflow: Enum.count(filtered_ctbs) > @current_token_balances_limit
+ })
+ end
+
def push_current_coin_balance(
%Phoenix.Socket{handler: BlockScoutWeb.UserSocketV2} = socket,
block_number,
diff --git a/apps/block_scout_web/lib/block_scout_web/channels/token_channel.ex b/apps/block_scout_web/lib/block_scout_web/channels/token_channel.ex
index ac4295e6b010..0de43f328859 100644
--- a/apps/block_scout_web/lib/block_scout_web/channels/token_channel.ex
+++ b/apps/block_scout_web/lib/block_scout_web/channels/token_channel.ex
@@ -4,6 +4,8 @@ defmodule BlockScoutWeb.TokenChannel do
"""
use BlockScoutWeb, :channel
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
alias BlockScoutWeb.{CurrencyHelper, TokensView}
alias BlockScoutWeb.Tokens.TransferView
alias Explorer.Chain
@@ -12,7 +14,7 @@ defmodule BlockScoutWeb.TokenChannel do
intercept(["token_transfer", "token_total_supply"])
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def join("tokens:" <> _transaction_hash, _params, socket) do
diff --git a/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex b/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex
index df026d0b0b58..5c1247786a05 100644
--- a/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex
+++ b/apps/block_scout_web/lib/block_scout_web/channels/transaction_channel.ex
@@ -4,6 +4,8 @@ defmodule BlockScoutWeb.TransactionChannel do
"""
use BlockScoutWeb, :channel
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
alias BlockScoutWeb.API.V2.TransactionView, as: TransactionViewV2
alias BlockScoutWeb.{TransactionRawTraceView, TransactionView}
alias Explorer.Chain
@@ -12,7 +14,7 @@ defmodule BlockScoutWeb.TransactionChannel do
intercept(["pending_transaction", "transaction", "raw_trace"])
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def join("transactions:new_transaction", _params, socket) do
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex
index 9e37382e12a7..c352cb8e783b 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_controller.ex
@@ -15,6 +15,7 @@ defmodule BlockScoutWeb.AddressController do
}
alias Explorer.{Chain, Market}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Chain.Wei
alias Indexer.Fetcher.CoinBalanceOnDemand
alias Phoenix.View
@@ -82,7 +83,7 @@ defmodule BlockScoutWeb.AddressController do
render(conn, "index.html",
current_path: Controller.current_full_path(conn),
- address_count: Chain.address_estimated_count(),
+ address_count: Counters.address_estimated_count(),
total_supply: total_supply
)
end
@@ -146,7 +147,7 @@ defmodule BlockScoutWeb.AddressController do
def address_counters(conn, %{"id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
- {validation_count} = Chain.address_counters(address)
+ {validation_count} = Counters.address_counters(address)
transactions_from_db = address.transactions_count || 0
token_transfers_from_db = address.token_transfers_count || 0
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_token_balance_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_token_balance_controller.ex
index 2013c7bcaad5..5899458fd887 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_token_balance_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_token_balance_controller.ex
@@ -9,12 +9,8 @@ defmodule BlockScoutWeb.AddressTokenBalanceController do
def index(conn, %{"address_id" => address_hash_string} = params) do
with true <- ajax?(conn),
{:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string) do
- token_balances =
- address_hash
- |> Chain.fetch_last_token_balances()
-
Task.start_link(fn ->
- TokenBalanceOnDemand.trigger_fetch(address_hash, token_balances)
+ TokenBalanceOnDemand.trigger_fetch(address_hash)
end)
case AccessHelper.restricted_access?(address_hash_string, params) do
@@ -24,7 +20,7 @@ defmodule BlockScoutWeb.AddressTokenBalanceController do
|> put_layout(false)
|> render("_token_balances.html",
address_hash: Address.checksum(address_hash),
- token_balances: token_balances,
+ token_balances: Chain.fetch_last_token_balances(address_hash),
conn: conn
)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_token_transfer_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_token_transfer_controller.ex
index e8d21d0d2c97..25bec31b7dd4 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_token_transfer_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_token_transfer_controller.ex
@@ -13,6 +13,8 @@ defmodule BlockScoutWeb.AddressTokenTransferController do
import BlockScoutWeb.Chain,
only: [current_filter: 1, next_page_params: 3, paging_options: 1, split_list_by_page: 1]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
@transaction_necessity_by_association [
necessity_by_association: %{
[created_contract_address: :names] => :optional,
@@ -29,7 +31,7 @@ defmodule BlockScoutWeb.AddressTokenTransferController do
}
]
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def index(
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
index 815c8227a6f3..639e5cc39466 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
@@ -6,10 +6,9 @@ defmodule BlockScoutWeb.AddressTransactionController do
use BlockScoutWeb, :controller
import BlockScoutWeb.Account.AuthController, only: [current_user: 1]
-
import BlockScoutWeb.Chain, only: [current_filter: 1, paging_options: 1, next_page_params: 3, split_list_by_page: 1]
-
import BlockScoutWeb.Models.GetAddressTags, only: [get_address_tags: 2]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
alias BlockScoutWeb.{AccessHelper, Controller, TransactionView}
alias Explorer.{Chain, Market}
@@ -40,7 +39,7 @@ defmodule BlockScoutWeb.AddressTransactionController do
}
]
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/rpc_translator.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/rpc_translator.ex
index 53a5ec3add25..b27554eed39b 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/rpc_translator.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/rpc_translator.ex
@@ -29,7 +29,7 @@ defmodule BlockScoutWeb.API.RPC.RPCTranslator do
end
def call(%Conn{params: %{"module" => module, "action" => action}} = conn, translations) do
- with true <- valid_api_request_path(conn),
+ with {:valid_api_request, true} <- {:valid_api_request, valid_api_request_path(conn)},
{:ok, {controller, write_actions}} <- translate_module(translations, module),
{:ok, action} <- translate_action(action),
true <- action_accessed?(action, write_actions),
@@ -58,6 +58,13 @@ defmodule BlockScoutWeb.API.RPC.RPCTranslator do
:rate_limit_reached ->
AccessHelper.handle_rate_limit_deny(conn)
+ {:valid_api_request, false} ->
+ conn
+ |> put_status(404)
+ |> put_view(RPCView)
+ |> Controller.render(:error, error: "Not found")
+ |> halt()
+
_ ->
conn
|> put_status(500)
@@ -119,7 +126,8 @@ defmodule BlockScoutWeb.API.RPC.RPCTranslator do
end
defp valid_api_request_path(conn) do
- if conn.request_path == "/api" || conn.request_path == "/api/v1" do
+ if conn.request_path == "/api" || conn.request_path == "/api/" || conn.request_path == "/api/v1" ||
+ conn.request_path == "/api/v1/" do
true
else
false
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex
index c8062039c870..160fd28cf60d 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/address_controller.ex
@@ -17,6 +17,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
alias BlockScoutWeb.AccessHelper
alias BlockScoutWeb.API.V2.{BlockView, TransactionView, WithdrawalView}
alias Explorer.{Chain, Market}
+ alias Explorer.Chain.Address.Counters
alias Indexer.Fetcher.{CoinBalanceOnDemand, TokenBalanceOnDemand}
@transaction_necessity_by_association [
@@ -57,7 +58,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
action_fallback(BlockScoutWeb.API.V2.FallbackController)
- def address(conn, %{"address_hash" => address_hash_string} = params) do
+ def address(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, address}} <- {:not_found, Chain.hash_to_address(address_hash, @address_options)} do
@@ -69,11 +70,11 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def counters(conn, %{"address_hash" => address_hash_string} = params) do
+ def counters(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
- {validation_count} = Chain.address_counters(address, @api_true)
+ {validation_count} = Counters.address_counters(address, @api_true)
transactions_from_db = address.transactions_count || 0
token_transfers_from_db = address.token_transfers_count || 0
@@ -88,7 +89,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def token_balances(conn, %{"address_hash" => address_hash_string} = params) do
+ def token_balances(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -97,7 +98,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
|> Chain.fetch_last_token_balances(@api_true)
Task.start_link(fn ->
- TokenBalanceOnDemand.trigger_fetch(address_hash, token_balances)
+ TokenBalanceOnDemand.trigger_fetch(address_hash)
end)
conn
@@ -106,7 +107,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def transactions(conn, %{"address_hash" => address_hash_string} = params) do
+ def transactions(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -118,8 +119,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
results_plus_one = Chain.address_to_transactions_without_rewards(address_hash, options, false)
{transactions, next_page} = split_list_by_page(results_plus_one)
- next_page_params =
- next_page |> next_page_params(transactions, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(transactions, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -130,7 +130,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
def token_transfers(
conn,
- %{"address_hash" => address_hash_string, "token" => token_address_hash_string} = params
+ %{"address_hash_param" => address_hash_string, "token" => token_address_hash_string} = params
) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:format, {:ok, token_address_hash}} <- {:format, Chain.string_to_address_hash(token_address_hash_string)},
@@ -166,8 +166,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
next_page_params =
next_page
- |> token_transfers_next_page_params(token_transfers, params)
- |> delete_parameters_from_next_page_params()
+ |> token_transfers_next_page_params(token_transfers, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -176,7 +175,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def token_transfers(conn, %{"address_hash" => address_hash_string} = params) do
+ def token_transfers(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -198,8 +197,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
next_page_params =
next_page
- |> token_transfers_next_page_params(token_transfers, params)
- |> delete_parameters_from_next_page_params()
+ |> token_transfers_next_page_params(token_transfers, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -208,7 +206,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def internal_transactions(conn, %{"address_hash" => address_hash_string} = params) do
+ def internal_transactions(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -231,7 +229,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
{internal_transactions, next_page} = split_list_by_page(results_plus_one)
next_page_params =
- next_page |> next_page_params(internal_transactions, params) |> delete_parameters_from_next_page_params()
+ next_page |> next_page_params(internal_transactions, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -243,7 +241,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def logs(conn, %{"address_hash" => address_hash_string, "topic" => topic} = params) do
+ def logs(conn, %{"address_hash_param" => address_hash_string, "topic" => topic} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -257,7 +255,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
{logs, next_page} = split_list_by_page(results_plus_one)
- next_page_params = next_page |> next_page_params(logs, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(logs, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -266,7 +264,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def logs(conn, %{"address_hash" => address_hash_string} = params) do
+ def logs(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -276,7 +274,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
{logs, next_page} = split_list_by_page(results_plus_one)
- next_page_params = next_page |> next_page_params(logs, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(logs, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -285,7 +283,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def blocks_validated(conn, %{"address_hash" => address_hash_string} = params) do
+ def blocks_validated(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -304,7 +302,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
results_plus_one = Chain.get_blocks_validated_by_address(full_options, address_hash)
{blocks, next_page} = split_list_by_page(results_plus_one)
- next_page_params = next_page |> next_page_params(blocks, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(blocks, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -313,7 +311,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def coin_balance_history(conn, %{"address_hash" => address_hash_string} = params) do
+ def coin_balance_history(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -323,8 +321,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
{coin_balances, next_page} = split_list_by_page(results_plus_one)
- next_page_params =
- next_page |> next_page_params(coin_balances, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(coin_balances, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -332,7 +329,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def coin_balance_history_by_day(conn, %{"address_hash" => address_hash_string} = params) do
+ def coin_balance_history_by_day(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -346,7 +343,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def tokens(conn, %{"address_hash" => address_hash_string} = params) do
+ def tokens(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -354,20 +351,18 @@ defmodule BlockScoutWeb.API.V2.AddressController do
address_hash
|> Chain.fetch_paginated_last_token_balances(
params
- |> delete_parameters_from_next_page_params()
|> paging_options()
|> Keyword.merge(token_transfers_types_options(params))
|> Keyword.merge(@api_true)
)
Task.start_link(fn ->
- TokenBalanceOnDemand.trigger_fetch(address_hash, results_plus_one)
+ TokenBalanceOnDemand.trigger_fetch(address_hash)
end)
{tokens, next_page} = split_list_by_page(results_plus_one)
- next_page_params =
- next_page |> next_page_params(tokens, params, true) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(tokens, delete_parameters_from_next_page_params(params), true)
conn
|> put_status(200)
@@ -375,7 +370,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
end
end
- def withdrawals(conn, %{"address_hash" => address_hash_string} = params) do
+ def withdrawals(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
@@ -383,7 +378,7 @@ defmodule BlockScoutWeb.API.V2.AddressController do
withdrawals_plus_one = address_hash |> Chain.address_hash_to_withdrawals(options)
{withdrawals, next_page} = split_list_by_page(withdrawals_plus_one)
- next_page_params = next_page |> next_page_params(withdrawals, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(withdrawals, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -414,4 +409,26 @@ defmodule BlockScoutWeb.API.V2.AddressController do
total_supply: total_supply
})
end
+
+ def tabs_counters(conn, %{"address_hash_param" => address_hash_string} = params) do
+ with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
+ {:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
+ {:not_found, {:ok, _address}} <- {:not_found, Chain.hash_to_address(address_hash, @api_true, false)} do
+ {validations, transactions, token_transfers, token_balances, logs, withdrawals, internal_txs, coin_balances} =
+ Counters.address_limited_counters(address_hash_string, @api_true)
+
+ conn
+ |> put_status(200)
+ |> json(%{
+ validations_count: validations,
+ transactions_count: transactions,
+ token_transfers_count: token_transfers,
+ token_balances_count: token_balances,
+ logs_count: logs,
+ withdrawals_count: withdrawals,
+ internal_txs_count: internal_txs,
+ coin_balances_count: coin_balances
+ })
+ end
+ end
end
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex
index 865127d756a0..a680d7616d40 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/block_controller.ex
@@ -77,7 +77,7 @@ defmodule BlockScoutWeb.API.V2.BlockController do
{blocks, next_page} = split_list_by_page(blocks_plus_one)
- next_page_params = next_page |> next_page_params(blocks, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(blocks, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -98,8 +98,7 @@ defmodule BlockScoutWeb.API.V2.BlockController do
next_page_params =
next_page
- |> next_page_params(transactions, params)
- |> delete_parameters_from_next_page_params()
+ |> next_page_params(transactions, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -118,7 +117,7 @@ defmodule BlockScoutWeb.API.V2.BlockController do
withdrawals_plus_one = Chain.block_to_withdrawals(block.hash, full_options)
{withdrawals, next_page} = split_list_by_page(withdrawals_plus_one)
- next_page_params = next_page |> next_page_params(withdrawals, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(withdrawals, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/fallback_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/fallback_controller.ex
index 78ef0980d2c5..79cad2ebffed 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/fallback_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/fallback_controller.ex
@@ -1,134 +1,235 @@
defmodule BlockScoutWeb.API.V2.FallbackController do
use Phoenix.Controller
+ require Logger
+
alias BlockScoutWeb.API.V2.ApiView
- def call(conn, {:format, _}) do
+ @verification_failed "API v2 smart-contract verification failed"
+ @invalid_parameters "Invalid parameter(s)"
+ @invalid_address_hash "Invalid address hash"
+ @invalid_hash "Invalid hash"
+ @invalid_number "Invalid number"
+ @invalid_url "Invalid URL"
+ @not_found "Not found"
+ @contract_interaction_disabled "Contract interaction disabled"
+ @restricted_access "Restricted access"
+ @already_verified "Already verified"
+ @json_not_found "JSON files not found"
+ @error_while_reading_json "Error while reading JSON file"
+ @error_in_libraries "Libraries are not valid JSON map"
+ @block_lost_consensus "Block lost consensus"
+ @invalid_captcha_resp "Invalid reCAPTCHA response"
+ @unauthorized "Unauthorized"
+ @not_configured_api_key "API key not configured on the server"
+ @wrong_api_key "Wrong API key"
+
+ def call(conn, {:format, _params}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@invalid_parameters}"]
+ end)
+
conn
|> put_status(:unprocessable_entity)
|> put_view(ApiView)
- |> render(:message, %{message: "Invalid parameter(s)"})
+ |> render(:message, %{message: @invalid_parameters})
end
def call(conn, {:format_address, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@invalid_address_hash}"]
+ end)
+
conn
|> put_status(:unprocessable_entity)
|> put_view(ApiView)
- |> render(:message, %{message: "Invalid address hash"})
+ |> render(:message, %{message: @invalid_address_hash})
end
def call(conn, {:format_url, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@invalid_url}"]
+ end)
+
conn
|> put_status(:unprocessable_entity)
|> put_view(ApiView)
- |> render(:message, %{message: "Invalid URL"})
+ |> render(:message, %{message: @invalid_url})
end
def call(conn, {:not_found, _, :empty_items_with_next_page_params}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: :empty_items_with_next_page_params"]
+ end)
+
conn
|> json(%{"items" => [], "next_page_params" => nil})
end
def call(conn, {:not_found, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@not_found}"]
+ end)
+
conn
|> put_status(:not_found)
|> put_view(ApiView)
- |> render(:message, %{message: "Not found"})
+ |> render(:message, %{message: @not_found})
end
def call(conn, {:contract_interaction_disabled, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@contract_interaction_disabled}"]
+ end)
+
conn
|> put_status(:forbidden)
|> put_view(ApiView)
- |> render(:message, %{message: "Contract interaction disabled"})
+ |> render(:message, %{message: @contract_interaction_disabled})
end
def call(conn, {:error, {:invalid, :hash}}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@invalid_hash}"]
+ end)
+
conn
|> put_status(:unprocessable_entity)
|> put_view(ApiView)
- |> render(:message, %{message: "Invalid hash"})
+ |> render(:message, %{message: @invalid_hash})
end
def call(conn, {:error, {:invalid, :number}}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@invalid_number}"]
+ end)
+
conn
|> put_status(:unprocessable_entity)
|> put_view(ApiView)
- |> render(:message, %{message: "Invalid number"})
+ |> render(:message, %{message: @invalid_number})
end
def call(conn, {:error, :not_found}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: :not_found"]
+ end)
+
conn
|> call({:not_found, nil})
end
def call(conn, {:restricted_access, true}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@restricted_access}"]
+ end)
+
conn
|> put_status(:forbidden)
|> put_view(ApiView)
- |> render(:message, %{message: "Restricted access"})
+ |> render(:message, %{message: @restricted_access})
end
def call(conn, {:already_verified, true}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@already_verified}"]
+ end)
+
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Already verified"})
+ |> render(:message, %{message: @already_verified})
end
def call(conn, {:no_json_file, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@json_not_found}"]
+ end)
+
conn
|> put_view(ApiView)
- |> render(:message, %{message: "JSON files not found"})
+ |> render(:message, %{message: @json_not_found})
end
def call(conn, {:file_error, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@error_while_reading_json}"]
+ end)
+
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Error while reading JSON file"})
+ |> render(:message, %{message: @error_while_reading_json})
end
def call(conn, {:libs_format, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@error_in_libraries}"]
+ end)
+
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Libraries are not valid JSON map"})
+ |> render(:message, %{message: @error_in_libraries})
end
def call(conn, {:lost_consensus, {:ok, block}}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@block_lost_consensus}"]
+ end)
+
conn
|> put_status(:not_found)
- |> json(%{message: "Block lost consensus", hash: to_string(block.hash)})
+ |> json(%{message: @block_lost_consensus, hash: to_string(block.hash)})
end
def call(conn, {:lost_consensus, {:error, :not_found}}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@block_lost_consensus}"]
+ end)
+
conn
|> call({:not_found, nil})
end
def call(conn, {:recaptcha, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@invalid_captcha_resp}"]
+ end)
+
conn
|> put_status(:forbidden)
|> put_view(ApiView)
- |> render(:message, %{message: "Invalid reCAPTCHA response"})
+ |> render(:message, %{message: @invalid_captcha_resp})
end
def call(conn, {:auth, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@unauthorized}"]
+ end)
+
conn
|> put_status(:unauthorized)
|> put_view(ApiView)
- |> render(:message, %{message: "Unauthorized"})
+ |> render(:message, %{message: @unauthorized})
end
def call(conn, {:sensitive_endpoints_api_key, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@not_configured_api_key}"]
+ end)
+
conn
|> put_status(:forbidden)
|> put_view(ApiView)
- |> render(:message, %{message: "API key not configured on the server"})
+ |> render(:message, %{message: @not_configured_api_key})
end
def call(conn, {:api_key, _}) do
+ Logger.error(fn ->
+ ["#{@verification_failed}: #{@wrong_api_key}"]
+ end)
+
conn
|> put_status(:unauthorized)
|> put_view(ApiView)
- |> render(:message, %{message: "Wrong API key"})
+ |> render(:message, %{message: @wrong_api_key})
end
end
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/import_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/import_controller.ex
index 29175a1ad697..a89cbb323e74 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/import_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/import_controller.ex
@@ -18,7 +18,7 @@ defmodule BlockScoutWeb.API.V2.ImportController do
{:format_address, Chain.string_to_address_hash(token_address_hash_string)},
{:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash, @api_true)},
{:format_url, true} <- {:format_url, valid_url?(icon_url)} do
- case token |> Token.changeset(%{icon_url: icon_url}) |> Repo.update() do
+ case token |> Token.changeset(%{icon_url: icon_url, is_verified_via_admin_panel: true}) |> Repo.update() do
{:ok, _} ->
conn
|> put_view(ApiView)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/search_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/search_controller.ex
index e76b4408e2f0..abe0aca31486 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/search_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/search_controller.ex
@@ -3,7 +3,10 @@ defmodule BlockScoutWeb.API.V2.SearchController do
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1, from_param: 1]
- alias Explorer.Chain
+ alias Explorer.Chain.Search
+ alias Explorer.PagingOptions
+
+ @api_true [api?: true]
def search(conn, %{"q" => query} = params) do
[paging_options: paging_options] = paging_options(params)
@@ -11,7 +14,7 @@ defmodule BlockScoutWeb.API.V2.SearchController do
search_results_plus_one =
paging_options
- |> Chain.joint_search(offset, query, api?: true)
+ |> Search.joint_search(offset, query, @api_true)
{search_results, next_page} = split_list_by_page(search_results_plus_one)
@@ -32,4 +35,12 @@ defmodule BlockScoutWeb.API.V2.SearchController do
|> put_status(200)
|> render(:search_results, %{result: result})
end
+
+ def quick_search(conn, %{"q" => query}) do
+ search_results = Search.balanced_unpaginated_search(%PagingOptions{page_size: 50}, query, @api_true)
+
+ conn
+ |> put_status(200)
+ |> render(:search_results, %{search_results: search_results})
+ end
end
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/smart_contract_controller.ex
index 8d016c404714..7002858350ba 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/smart_contract_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/smart_contract_controller.ex
@@ -6,6 +6,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do
import BlockScoutWeb.PagingHelper,
only: [current_filter: 1, delete_parameters_from_next_page_params: 1, search_query: 1]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
import Explorer.SmartContract.Solidity.Verifier, only: [parse_boolean: 1]
alias BlockScoutWeb.{AccessHelper, AddressView}
@@ -26,8 +27,6 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do
@api_true [api?: true]
- @burn_address "0x0000000000000000000000000000000000000000"
-
action_fallback(BlockScoutWeb.API.V2.FallbackController)
def smart_contract(conn, %{"address_hash" => address_hash_string} = params) do
@@ -82,7 +81,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do
{:not_found, true} <- {:not_found, AddressView.check_custom_abi_for_having_write_functions(custom_abi)} do
conn
|> put_status(200)
- |> json(Writer.filter_write_functions(custom_abi.abi))
+ |> json(custom_abi.abi |> Writer.filter_write_functions() |> Reader.get_abi_with_method_id())
end
end
@@ -95,7 +94,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do
{:not_found, false} <- {:not_found, is_nil(smart_contract)} do
conn
|> put_status(200)
- |> json(Writer.write_functions(smart_contract))
+ |> json(smart_contract |> Writer.write_functions() |> Reader.get_abi_with_method_id())
end
end
@@ -109,7 +108,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do
address.smart_contract
|> SmartContract.get_implementation_address_hash(@api_true)
|> Tuple.to_list()
- |> List.first() || @burn_address
+ |> List.first() || burn_address_hash_string()
conn
|> put_status(200)
@@ -131,11 +130,15 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do
address.smart_contract
|> SmartContract.get_implementation_address_hash(@api_true)
|> Tuple.to_list()
- |> List.first() || @burn_address
+ |> List.first() || burn_address_hash_string()
conn
|> put_status(200)
- |> json(Writer.write_functions_proxy(implementation_address_hash_string, @api_true))
+ |> json(
+ implementation_address_hash_string
+ |> Writer.write_functions_proxy(@api_true)
+ |> Reader.get_abi_with_method_id()
+ )
end
end
@@ -200,8 +203,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractController do
next_page_params =
next_page
- |> next_page_params(smart_contracts, params)
- |> delete_parameters_from_next_page_params()
+ |> next_page_params(smart_contracts, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex
index f85e5f54be31..098b05f7e9c8 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/stats_controller.ex
@@ -4,6 +4,7 @@ defmodule BlockScoutWeb.API.V2.StatsController do
alias BlockScoutWeb.API.V2.Helper
alias BlockScoutWeb.Chain.MarketHistoryChartController
alias Explorer.{Chain, Market}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Chain.Cache.Block, as: BlockCache
alias Explorer.Chain.Cache.{GasPriceOracle, GasUsage}
alias Explorer.Chain.Cache.Transaction, as: TransactionCache
@@ -43,7 +44,7 @@ defmodule BlockScoutWeb.API.V2.StatsController do
conn,
%{
"total_blocks" => BlockCache.estimated_count() |> to_string(),
- "total_addresses" => @api_true |> Chain.address_estimated_count() |> to_string(),
+ "total_addresses" => @api_true |> Counters.address_estimated_count() |> to_string(),
"total_transactions" => TransactionCache.estimated_count() |> to_string(),
"average_block_time" => AverageBlockTime.average_block_time() |> Duration.to_milliseconds(),
"coin_price" => exchange_rate.usd_value,
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex
index 647e38ab6283..1ec2a32a3e0b 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/token_controller.ex
@@ -23,7 +23,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
@api_true [api?: true]
- def token(conn, %{"address_hash" => address_hash_string} = params) do
+ def token(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash, @api_true)} do
@@ -35,7 +35,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
end
end
- def counters(conn, %{"address_hash" => address_hash_string} = params) do
+ def counters(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, true} <- {:not_found, Chain.token_from_address_hash_exists?(address_hash, @api_true)} do
@@ -45,7 +45,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
end
end
- def transfers(conn, %{"address_hash" => address_hash_string} = params) do
+ def transfers(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, true} <- {:not_found, Chain.token_from_address_hash_exists?(address_hash, @api_true)} do
@@ -61,8 +61,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
next_page_params =
next_page
- |> token_transfers_next_page_params(token_transfers, params)
- |> delete_parameters_from_next_page_params()
+ |> token_transfers_next_page_params(token_transfers, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -71,7 +70,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
end
end
- def holders(conn, %{"address_hash" => address_hash_string} = params) do
+ def holders(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash, @api_true)} do
@@ -80,8 +79,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
{token_balances, next_page} = split_list_by_page(results_plus_one)
- next_page_params =
- next_page |> next_page_params(token_balances, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(token_balances, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -89,7 +87,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
end
end
- def instances(conn, %{"address_hash" => address_hash_string} = params) do
+ def instances(conn, %{"address_hash_param" => address_hash_string} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash, @api_true)} do
@@ -102,7 +100,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
{token_instances, next_page} = split_list_by_page(results_plus_one)
next_page_params =
- next_page |> unique_tokens_next_page(token_instances, params) |> delete_parameters_from_next_page_params()
+ next_page |> unique_tokens_next_page(token_instances, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -110,7 +108,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
end
end
- def instance(conn, %{"address_hash" => address_hash_string, "token_id" => token_id_str} = params) do
+ def instance(conn, %{"address_hash_param" => address_hash_string, "token_id" => token_id_str} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash, @api_true)},
@@ -131,7 +129,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
end
end
- def transfers_by_instance(conn, %{"address_hash" => address_hash_string, "token_id" => token_id_str} = params) do
+ def transfers_by_instance(conn, %{"address_hash_param" => address_hash_string, "token_id" => token_id_str} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash, @api_true)},
@@ -149,8 +147,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
next_page_params =
next_page
- |> token_transfers_next_page_params(token_transfers, params)
- |> delete_parameters_from_next_page_params()
+ |> token_transfers_next_page_params(token_transfers, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -159,7 +156,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
end
end
- def holders_by_instance(conn, %{"address_hash" => address_hash_string, "token_id" => token_id_str} = params) do
+ def holders_by_instance(conn, %{"address_hash_param" => address_hash_string, "token_id" => token_id_str} = params) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash, @api_true)},
@@ -178,8 +175,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
next_page_params =
next_page
- |> next_page_params(token_holders, params)
- |> delete_parameters_from_next_page_params()
+ |> next_page_params(token_holders, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -187,7 +183,10 @@ defmodule BlockScoutWeb.API.V2.TokenController do
end
end
- def transfers_count_by_instance(conn, %{"address_hash" => address_hash_string, "token_id" => token_id_str} = params) do
+ def transfers_count_by_instance(
+ conn,
+ %{"address_hash_param" => address_hash_string, "token_id" => token_id_str} = params
+ ) do
with {:format, {:ok, address_hash}} <- {:format, Chain.string_to_address_hash(address_hash_string)},
{:ok, false} <- AccessHelper.restricted_access?(address_hash_string, params),
{:not_found, {:ok, token}} <- {:not_found, Chain.token_from_address_hash(address_hash, @api_true)},
@@ -213,7 +212,7 @@ defmodule BlockScoutWeb.API.V2.TokenController do
{tokens, next_page} = filter |> Chain.list_top_tokens(options) |> split_list_by_page()
- next_page_params = next_page |> next_page_params(tokens, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(tokens, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex
index 94d060f918ad..973fdc7094dd 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/transaction_controller.ex
@@ -62,7 +62,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
@api_true [api?: true]
- def transaction(conn, %{"transaction_hash" => transaction_hash_string} = params) do
+ def transaction(conn, %{"transaction_hash_param" => transaction_hash_string} = params) do
with {:format, {:ok, transaction_hash}} <- {:format, Chain.string_to_transaction_hash(transaction_hash_string)},
{:not_found, {:ok, transaction}} <-
{:not_found,
@@ -97,14 +97,14 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
{transactions, next_page} = split_list_by_page(transactions_plus_one)
- next_page_params = next_page |> next_page_params(transactions, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(transactions, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
|> render(:transactions, %{transactions: transactions, next_page_params: next_page_params})
end
- def raw_trace(conn, %{"transaction_hash" => transaction_hash_string} = params) do
+ def raw_trace(conn, %{"transaction_hash_param" => transaction_hash_string} = params) do
with {:format, {:ok, transaction_hash}} <- {:format, Chain.string_to_transaction_hash(transaction_hash_string)},
{:not_found, {:ok, transaction}} <-
{:not_found, Chain.hash_to_transaction(transaction_hash, @api_true)},
@@ -133,7 +133,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
end
end
- def token_transfers(conn, %{"transaction_hash" => transaction_hash_string} = params) do
+ def token_transfers(conn, %{"transaction_hash_param" => transaction_hash_string} = params) do
with {:format, {:ok, transaction_hash}} <- {:format, Chain.string_to_transaction_hash(transaction_hash_string)},
{:not_found, {:ok, transaction}} <-
{:not_found, Chain.hash_to_transaction(transaction_hash, @api_true)},
@@ -157,8 +157,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
next_page_params =
next_page
- |> token_transfers_next_page_params(token_transfers, params)
- |> delete_parameters_from_next_page_params()
+ |> token_transfers_next_page_params(token_transfers, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -166,7 +165,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
end
end
- def internal_transactions(conn, %{"transaction_hash" => transaction_hash_string} = params) do
+ def internal_transactions(conn, %{"transaction_hash_param" => transaction_hash_string} = params) do
with {:format, {:ok, transaction_hash}} <- {:format, Chain.string_to_transaction_hash(transaction_hash_string)},
{:not_found, {:ok, transaction}} <-
{:not_found, Chain.hash_to_transaction(transaction_hash, @api_true)},
@@ -183,8 +182,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
next_page_params =
next_page
- |> next_page_params(internal_transactions, params)
- |> delete_parameters_from_next_page_params()
+ |> next_page_params(internal_transactions, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -195,7 +193,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
end
end
- def logs(conn, %{"transaction_hash" => transaction_hash_string} = params) do
+ def logs(conn, %{"transaction_hash_param" => transaction_hash_string} = params) do
with {:format, {:ok, transaction_hash}} <- {:format, Chain.string_to_transaction_hash(transaction_hash_string)},
{:not_found, {:ok, transaction}} <-
{:not_found, Chain.hash_to_transaction(transaction_hash, @api_true)},
@@ -218,8 +216,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
next_page_params =
next_page
- |> next_page_params(logs, params)
- |> delete_parameters_from_next_page_params()
+ |> next_page_params(logs, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -231,7 +228,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
end
end
- def state_changes(conn, %{"transaction_hash" => transaction_hash_string} = params) do
+ def state_changes(conn, %{"transaction_hash_param" => transaction_hash_string} = params) do
with {:format, {:ok, transaction_hash}} <- {:format, Chain.string_to_transaction_hash(transaction_hash_string)},
{:not_found, {:ok, transaction}} <-
{:not_found,
@@ -249,8 +246,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
next_page_params =
next_page
- |> next_page_params(state_changes, params)
- |> delete_parameters_from_next_page_params()
+ |> next_page_params(state_changes, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
@@ -271,8 +267,7 @@ defmodule BlockScoutWeb.API.V2.TransactionController do
{transactions, next_page} = split_list_by_page(transactions_plus_one)
- next_page_params =
- next_page |> next_page_params(transactions, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(transactions, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/verification_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/verification_controller.ex
index 49c98c5153ee..b2bbb07d3189 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/verification_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/verification_controller.ex
@@ -3,6 +3,8 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
import Explorer.SmartContract.Solidity.Verifier, only: [parse_boolean: 1]
+ require Logger
+
alias BlockScoutWeb.AccessHelper
alias BlockScoutWeb.API.V2.ApiView
alias Explorer.Chain
@@ -14,6 +16,7 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
action_fallback(BlockScoutWeb.API.V2.FallbackController)
@api_true [api?: true]
+ @sc_verification_started "Smart-contract verification started"
def config(conn, _params) do
solidity_compiler_versions = CompilerVersion.fetch_version_list(:solc)
@@ -46,6 +49,8 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
%{"address_hash" => address_hash_string, "compiler_version" => compiler_version, "source_code" => source_code} =
params
) do
+ Logger.info("API v2 smart-contract #{address_hash_string} verification via flattened file")
+
with :validated <- validate_address(params) do
verification_params =
%{
@@ -65,11 +70,12 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
|> Map.put("external_libraries", Map.get(params, "libraries", %{}))
|> Map.put("is_yul", Map.get(params, "is_yul_contract", false))
+ log_sc_verification_started(address_hash_string)
Que.add(SolidityPublisherWorker, {"flattened_api_v2", verification_params})
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Verification started"})
+ |> render(:message, %{message: @sc_verification_started})
end
end
@@ -77,6 +83,8 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
conn,
%{"address_hash" => address_hash_string, "files" => _files, "compiler_version" => compiler_version} = params
) do
+ Logger.info("API v2 smart-contract #{address_hash_string} verification via standard json input")
+
with {:json_input, json_input} <- validate_params_standard_json_input(params) do
verification_params =
%{
@@ -87,15 +95,18 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
|> Map.put("constructor_arguments", Map.get(params, "constructor_args", ""))
|> Map.put("name", Map.get(params, "contract_name", ""))
+ log_sc_verification_started(address_hash_string)
Que.add(SolidityPublisherWorker, {"json_api_v2", verification_params, json_input})
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Verification started"})
+ |> render(:message, %{message: @sc_verification_started})
end
end
def verification_via_sourcify(conn, %{"address_hash" => address_hash_string, "files" => files} = params) do
+ Logger.info("API v2 smart-contract #{address_hash_string} verification via Sourcify")
+
with {:not_found, true} <-
{:not_found, Application.get_env(:explorer, Explorer.ThirdPartyIntegrations.Sourcify)[:enabled]},
:validated <- validate_address(params),
@@ -105,6 +116,8 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
files_content <- PublishHelper.read_files(files_array) do
chosen_contract = params["chosen_contract_index"]
+ log_sc_verification_started(address_hash_string)
+
Que.add(
SolidityPublisherWorker,
{"sourcify_api_v2", String.downcase(address_hash_string), files_content, conn, chosen_contract}
@@ -112,7 +125,7 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Verification started"})
+ |> render(:message, %{message: @sc_verification_started})
end
end
@@ -120,6 +133,8 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
conn,
%{"address_hash" => address_hash_string, "compiler_version" => compiler_version, "files" => files} = params
) do
+ Logger.info("API v2 smart-contract #{address_hash_string} verification via multipart")
+
with :verifier_enabled <- check_microservice(),
:validated <- validate_address(params),
libraries <- Map.get(params, "libraries", "{}"),
@@ -142,11 +157,12 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
|> PublishHelper.prepare_files_array()
|> PublishHelper.read_files()
+ log_sc_verification_started(address_hash_string)
Que.add(SolidityPublisherWorker, {"multipart_api_v2", verification_params, files_array})
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Verification started"})
+ |> render(:message, %{message: @sc_verification_started})
end
end
@@ -166,11 +182,12 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
|> Map.put("name", Map.get(params, "contract_name", "Vyper_contract"))
|> Map.put("evm_version", Map.get(params, "evm_version"))
+ log_sc_verification_started(address_hash_string)
Que.add(VyperPublisherWorker, {"vyper_flattened", verification_params})
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Verification started"})
+ |> render(:message, %{message: @sc_verification_started})
end
end
@@ -178,6 +195,8 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
conn,
%{"address_hash" => address_hash_string, "compiler_version" => compiler_version, "files" => files} = params
) do
+ Logger.info("API v2 vyper smart-contract #{address_hash_string} verification")
+
with :verifier_enabled <- check_microservice(),
:validated <- validate_address(params) do
interfaces = parse_interfaces(params["interfaces"])
@@ -195,11 +214,12 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
|> PublishHelper.prepare_files_array()
|> PublishHelper.read_files()
+ log_sc_verification_started(address_hash_string)
Que.add(VyperPublisherWorker, {"vyper_multipart", verification_params, files_array})
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Verification started"})
+ |> render(:message, %{message: @sc_verification_started})
end
end
@@ -207,6 +227,8 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
conn,
%{"address_hash" => address_hash_string, "files" => _files, "compiler_version" => compiler_version} = params
) do
+ Logger.info("API v2 vyper smart-contract #{address_hash_string} verification via standard json input")
+
with :verifier_enabled <- check_microservice(),
{:json_input, json_input} <- validate_params_standard_json_input(params) do
verification_params = %{
@@ -215,11 +237,12 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
"input" => json_input
}
+ log_sc_verification_started(address_hash_string)
Que.add(VyperPublisherWorker, {"vyper_standard_json", verification_params})
conn
|> put_view(ApiView)
- |> render(:message, %{message: "Verification started"})
+ |> render(:message, %{message: @sc_verification_started})
end
end
@@ -269,4 +292,8 @@ defmodule BlockScoutWeb.API.V2.VerificationController do
:verifier_enabled
end
end
+
+ defp log_sc_verification_started(address_hash_string) do
+ Logger.info("API v2 smart-contract #{address_hash_string} verification request sent to the microservice")
+ end
end
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/withdrawal_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/withdrawal_controller.ex
index 396e66712a54..fc26823e5211 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/withdrawal_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v2/withdrawal_controller.ex
@@ -16,7 +16,7 @@ defmodule BlockScoutWeb.API.V2.WithdrawalController do
withdrawals_plus_one = Chain.list_withdrawals(full_options)
{withdrawals, next_page} = split_list_by_page(withdrawals_plus_one)
- next_page_params = next_page |> next_page_params(withdrawals, params) |> delete_parameters_from_next_page_params()
+ next_page_params = next_page |> next_page_params(withdrawals, delete_parameters_from_next_page_params(params))
conn
|> put_status(200)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex
index 74ef3f6b2f1e..4a92e7c5ca52 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex
@@ -11,12 +11,13 @@ defmodule BlockScoutWeb.BlockTransactionController do
]
import Explorer.Chain, only: [hash_to_block: 2, number_to_block: 2]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
alias BlockScoutWeb.{Controller, TransactionView}
alias Explorer.Chain
alias Phoenix.View
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def index(conn, %{"block_hash_or_number" => formatted_block_hash_or_number, "type" => "JSON"} = params) do
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
index afa8143329b3..eabc844c7d01 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
@@ -6,10 +6,12 @@ defmodule BlockScoutWeb.ChainController do
alias BlockScoutWeb.API.V2.Helper
alias BlockScoutWeb.{ChainView, Controller}
alias Explorer.{Chain, PagingOptions, Repo}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Chain.{Address, Block, Transaction}
alias Explorer.Chain.Cache.Block, as: BlockCache
alias Explorer.Chain.Cache.GasUsage
alias Explorer.Chain.Cache.Transaction, as: TransactionCache
+ alias Explorer.Chain.Search
alias Explorer.Chain.Supply.RSK
alias Explorer.Counters.AverageBlockTime
alias Explorer.Market
@@ -19,7 +21,7 @@ defmodule BlockScoutWeb.ChainController do
transaction_estimated_count = TransactionCache.estimated_count()
total_gas_usage = GasUsage.total()
block_count = BlockCache.estimated_count()
- address_count = Chain.address_estimated_count()
+ address_count = Counters.address_estimated_count()
market_cap_calculation =
case Application.get_env(:explorer, :supply) do
@@ -90,7 +92,7 @@ defmodule BlockScoutWeb.ChainController do
results =
paging_options
- |> Chain.joint_search(offset, term)
+ |> Search.joint_search(offset, term)
encoded_results =
results
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/pending_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/pending_transaction_controller.ex
index 906fbc3194b4..f709855b000a 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/pending_transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/pending_transaction_controller.ex
@@ -2,12 +2,13 @@ defmodule BlockScoutWeb.PendingTransactionController do
use BlockScoutWeb, :controller
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
alias BlockScoutWeb.{Controller, TransactionView}
alias Explorer.Chain
alias Phoenix.View
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def index(conn, %{"type" => "JSON"} = params) do
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/recent_transactions_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/recent_transactions_controller.ex
index d692d6de1471..f3406fc6cab6 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/recent_transactions_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/recent_transactions_controller.ex
@@ -1,11 +1,13 @@
defmodule BlockScoutWeb.RecentTransactionsController do
use BlockScoutWeb, :controller
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
alias Explorer.{Chain, PagingOptions}
alias Explorer.Chain.Hash
alias Phoenix.View
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def index(conn, _params) do
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/robots_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/robots_controller.ex
new file mode 100644
index 000000000000..a482fb1a73c7
--- /dev/null
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/robots_controller.ex
@@ -0,0 +1,13 @@
+defmodule BlockScoutWeb.RobotsController do
+ use BlockScoutWeb, :controller
+
+ def robots(conn, _params) do
+ conn
+ |> render("robots.txt")
+ end
+
+ def sitemap(conn, _params) do
+ conn
+ |> render("sitemap.xml")
+ end
+end
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/search_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/search_controller.ex
index b2f639a6e3a9..937c4b2603a6 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/search_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/search_controller.ex
@@ -4,7 +4,7 @@ defmodule BlockScoutWeb.SearchController do
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
alias BlockScoutWeb.{Controller, SearchView}
- alias Explorer.Chain
+ alias Explorer.Chain.Search
alias Phoenix.View
def search_results(conn, %{"q" => query, "type" => "JSON"} = params) do
@@ -13,7 +13,7 @@ defmodule BlockScoutWeb.SearchController do
search_results_plus_one =
paging_options
- |> Chain.joint_search(offset, query)
+ |> Search.joint_search(offset, query)
{search_results, next_page} = split_list_by_page(search_results_plus_one)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex
index b403e0e7d592..30832eee4aae 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex
@@ -7,8 +7,7 @@ defmodule BlockScoutWeb.SmartContractController do
alias Explorer.SmartContract.{Reader, Writer}
import Explorer.SmartContract.Solidity.Verifier, only: [parse_boolean: 1]
-
- @burn_address "0x0000000000000000000000000000000000000000"
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
def index(conn, %{"hash" => address_hash_string, "type" => contract_type, "action" => action} = params) do
address_options = [
@@ -30,9 +29,9 @@ defmodule BlockScoutWeb.SmartContractController do
address.smart_contract
|> SmartContract.get_implementation_address_hash()
|> Tuple.to_list()
- |> List.first() || @burn_address
+ |> List.first() || burn_address_hash_string()
else
- @burn_address
+ burn_address_hash_string()
end
functions =
@@ -137,7 +136,7 @@ defmodule BlockScoutWeb.SmartContractController do
address: %{hash: address_hash},
custom_abi: true,
contract_abi: contract_abi,
- implementation_address: @burn_address,
+ implementation_address: burn_address_hash_string(),
implementation_abi: [],
contract_type: contract_type,
action: action
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/tokens/instance/transfer_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/instance/transfer_controller.ex
index 7909faf07674..0eaa0115adc8 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/tokens/instance/transfer_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/instance/transfer_controller.ex
@@ -8,8 +8,9 @@ defmodule BlockScoutWeb.Tokens.Instance.TransferController do
alias Phoenix.View
import BlockScoutWeb.Chain, only: [split_list_by_page: 1, paging_options: 1, next_page_params: 3]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def index(conn, %{"token_id" => token_address_hash, "instance_id" => token_id_str, "type" => "JSON"} = params) do
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/tokens/transfer_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/transfer_controller.ex
index a349af147408..b36159b82b66 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/tokens/transfer_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/tokens/transfer_controller.ex
@@ -12,8 +12,9 @@ defmodule BlockScoutWeb.Tokens.TransferController do
alias Phoenix.View
import BlockScoutWeb.Chain, only: [split_list_by_page: 1, paging_options: 1, next_page_params: 3]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def index(conn, %{"token_id" => address_hash_string, "type" => "JSON"} = params) do
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex
index 5983ab8920cd..51a75bf85fcb 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex
@@ -14,6 +14,7 @@ defmodule BlockScoutWeb.TransactionController do
import BlockScoutWeb.Models.GetAddressTags, only: [get_address_tags: 2]
import BlockScoutWeb.Models.GetTransactionTags, only: [get_transaction_with_addresses_tags: 2]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
alias BlockScoutWeb.{
AccessHelper,
@@ -36,7 +37,7 @@ defmodule BlockScoutWeb.TransactionController do
:token_transfers => :optional
}
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
@default_options [
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex
index e2020a47bcca..7ea2d6e74e6c 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_state_controller.ex
@@ -16,8 +16,9 @@ defmodule BlockScoutWeb.TransactionStateController do
import BlockScoutWeb.Models.GetAddressTags, only: [get_address_tags: 2]
import BlockScoutWeb.Models.GetTransactionTags, only: [get_transaction_with_addresses_tags: 2]
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex
index d0f7fed1584f..061fde450ad4 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex
@@ -5,12 +5,13 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do
import BlockScoutWeb.Chain, only: [paging_options: 1, next_page_params: 3, split_list_by_page: 1]
import BlockScoutWeb.Models.GetAddressTags, only: [get_address_tags: 2]
import BlockScoutWeb.Models.GetTransactionTags, only: [get_transaction_with_addresses_tags: 2]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
alias BlockScoutWeb.{AccessHelper, Controller, TransactionController, TransactionTokenTransferView}
alias Explorer.{Chain, Market}
alias Phoenix.View
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def index(conn, %{"transaction_id" => transaction_hash_string, "type" => "JSON"} = params) do
diff --git a/apps/block_scout_web/lib/block_scout_web/endpoint.ex b/apps/block_scout_web/lib/block_scout_web/endpoint.ex
index 9036939eb195..10d8d99f36b6 100644
--- a/apps/block_scout_web/lib/block_scout_web/endpoint.ex
+++ b/apps/block_scout_web/lib/block_scout_web/endpoint.ex
@@ -29,7 +29,6 @@ defmodule BlockScoutWeb.Endpoint do
browserconfig.xml
mstile-150x150.png
safari-pinned-tab.svg
- robots.txt
),
only_matching: ~w(manifest)
)
diff --git a/apps/block_scout_web/lib/block_scout_web/models/transaction_state_helper.ex b/apps/block_scout_web/lib/block_scout_web/models/transaction_state_helper.ex
index e679627e8a74..3971a5463a64 100644
--- a/apps/block_scout_web/lib/block_scout_web/models/transaction_state_helper.ex
+++ b/apps/block_scout_web/lib/block_scout_web/models/transaction_state_helper.ex
@@ -4,13 +4,15 @@ defmodule BlockScoutWeb.Models.TransactionStateHelper do
"""
import BlockScoutWeb.Chain, only: [default_paging_options: 0]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
alias Explorer.Chain.Transaction.StateChange
alias Explorer.{Chain, PagingOptions}
alias Explorer.Chain.{Block, Transaction, Wei}
alias Explorer.Chain.Cache.StateChanges
alias Indexer.Fetcher.{CoinBalanceOnDemand, TokenBalanceOnDemand}
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
def state_changes(transaction, options \\ [])
diff --git a/apps/block_scout_web/lib/block_scout_web/notifier.ex b/apps/block_scout_web/lib/block_scout_web/notifier.ex
index fc69ceb3e27d..a82202c4acdc 100644
--- a/apps/block_scout_web/lib/block_scout_web/notifier.ex
+++ b/apps/block_scout_web/lib/block_scout_web/notifier.ex
@@ -3,6 +3,8 @@ defmodule BlockScoutWeb.Notifier do
Responds to events by sending appropriate channel updates to front-end.
"""
+ require Logger
+
alias Absinthe.Subscription
alias BlockScoutWeb.API.V2, as: API_V2
@@ -17,6 +19,7 @@ defmodule BlockScoutWeb.Notifier do
}
alias Explorer.{Chain, Market, Repo}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Chain.{Address, InternalTransaction, Transaction}
alias Explorer.Chain.Supply.RSK
alias Explorer.Chain.Transaction.History.TransactionStats
@@ -27,7 +30,7 @@ defmodule BlockScoutWeb.Notifier do
@check_broadcast_sequence_period 500
def handle_event({:chain_event, :addresses, type, addresses}) when type in [:realtime, :on_demand] do
- Endpoint.broadcast("addresses:new_address", "count", %{count: Chain.address_estimated_count()})
+ Endpoint.broadcast("addresses:new_address", "count", %{count: Counters.address_estimated_count()})
addresses
|> Stream.reject(fn %Address{fetched_coin_balance: fetched_coin_balance} -> is_nil(fetched_coin_balance) end)
@@ -44,14 +47,11 @@ defmodule BlockScoutWeb.Notifier do
Enum.each(address_token_balances, &broadcast_address_token_balance/1)
end
- def handle_event({:chain_event, :address_current_token_balances, type, address_current_token_balances})
- when type in [:realtime, :on_demand] do
- Enum.each(address_current_token_balances, &broadcast_address_token_balance/1)
- end
-
def handle_event(
{:chain_event, :contract_verification_result, :on_demand, {address_hash, contract_verification_result}}
) do
+ log_broadcast_verification_results_for_address(address_hash)
+
Endpoint.broadcast(
"addresses:#{address_hash}",
"verification_result",
@@ -64,6 +64,7 @@ defmodule BlockScoutWeb.Notifier do
def handle_event(
{:chain_event, :contract_verification_result, :on_demand, {address_hash, contract_verification_result, conn}}
) do
+ log_broadcast_verification_results_for_address(address_hash)
%{view: view, compiler: compiler} = select_contract_type_and_form_view(conn.params)
contract_verification_result =
@@ -222,10 +223,20 @@ defmodule BlockScoutWeb.Notifier do
end
def handle_event({:chain_event, :smart_contract_was_verified, :on_demand, [address_hash]}) do
+ log_broadcast_smart_contract_was_verified(address_hash)
Endpoint.broadcast("addresses:#{to_string(address_hash)}", "smart_contract_was_verified", %{})
end
- def handle_event(_), do: nil
+ def handle_event({:chain_event, :address_current_token_balances, :on_demand, address_current_token_balances}) do
+ Endpoint.broadcast("addresses:#{address_current_token_balances.address_hash}", "address_current_token_balances", %{
+ address_current_token_balances: address_current_token_balances.address_current_token_balances
+ })
+ end
+
+ def handle_event(event) do
+ Logger.warning("Unknown broadcasted event #{inspect(event)}.")
+ nil
+ end
def fetch_compiler_version(compiler) do
case CompilerVersion.fetch_versions(compiler) do
@@ -479,4 +490,12 @@ defmodule BlockScoutWeb.Notifier do
Endpoint.broadcast("addresses:#{address_hash}", event, %{map_key => elements})
end
end
+
+ defp log_broadcast_verification_results_for_address(address_hash) do
+ Logger.info("Broadcast smart-contract #{address_hash} verification results")
+ end
+
+ defp log_broadcast_smart_contract_was_verified(address_hash) do
+ Logger.info("Broadcast smart-contract #{address_hash} was verified")
+ end
end
diff --git a/apps/block_scout_web/lib/block_scout_web/paging_helper.ex b/apps/block_scout_web/lib/block_scout_web/paging_helper.ex
index bcbbc9b0a274..860a8f7d4a15 100644
--- a/apps/block_scout_web/lib/block_scout_web/paging_helper.ex
+++ b/apps/block_scout_web/lib/block_scout_web/paging_helper.ex
@@ -129,12 +129,11 @@ defmodule BlockScoutWeb.PagingHelper do
params
|> Map.drop([
"block_hash_or_number",
- "transaction_hash",
- "address_hash",
+ "transaction_hash_param",
+ "address_hash_param",
"type",
"method",
"filter",
- "token_address_hash",
"q",
"sort",
"order"
diff --git a/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex b/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex
index 7c0a05969912..47c9289f8301 100644
--- a/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex
+++ b/apps/block_scout_web/lib/block_scout_web/realtime_event_handler.ex
@@ -26,6 +26,7 @@ defmodule BlockScoutWeb.RealtimeEventHandler do
Subscriber.to(:transactions, :realtime)
Subscriber.to(:addresses, :on_demand)
Subscriber.to(:address_coin_balances, :on_demand)
+ Subscriber.to(:address_current_token_balances, :on_demand)
Subscriber.to(:address_token_balances, :on_demand)
Subscriber.to(:contract_verification_result, :on_demand)
Subscriber.to(:token_total_supply, :on_demand)
diff --git a/apps/block_scout_web/lib/block_scout_web/router.ex b/apps/block_scout_web/lib/block_scout_web/router.ex
index 8b7421b2773b..b56899ce80f3 100644
--- a/apps/block_scout_web/lib/block_scout_web/router.ex
+++ b/apps/block_scout_web/lib/block_scout_web/router.ex
@@ -28,12 +28,6 @@ defmodule BlockScoutWeb.Router do
# Needs to be 200 to support the schema introspection for graphiql
@max_complexity 200
- forward("/graphql", Absinthe.Plug,
- schema: BlockScoutWeb.Schema,
- analyze_complexity: true,
- max_complexity: @max_complexity
- )
-
forward("/graphiql", Absinthe.Plug.GraphiQL,
schema: BlockScoutWeb.Schema,
interface: :advanced,
@@ -53,6 +47,8 @@ defmodule BlockScoutWeb.Router do
scope "/", BlockScoutWeb do
pipe_through(:browser)
+ get("/robots.txt", RobotsController, :robots)
+ get("/sitemap.xml", RobotsController, :sitemap)
get("/api-docs", APIDocsController, :index)
get("/eth-rpc-api-docs", APIDocsController, :eth_rpc)
end
diff --git a/apps/block_scout_web/lib/block_scout_web/schema/types.ex b/apps/block_scout_web/lib/block_scout_web/schema/types.ex
index 426d9909f59b..99f47a29163b 100644
--- a/apps/block_scout_web/lib/block_scout_web/schema/types.ex
+++ b/apps/block_scout_web/lib/block_scout_web/schema/types.ex
@@ -22,10 +22,14 @@ defmodule BlockScoutWeb.Schema.Types do
A stored representation of a Web3 address.
"""
object :address do
- field(:hash, :address_hash)
field(:fetched_coin_balance, :wei)
field(:fetched_coin_balance_block_number, :integer)
+ field(:hash, :address_hash)
field(:contract_code, :data)
+ field(:nonce, :integer)
+ field(:gas_used, :integer)
+ field(:transactions_count, :integer)
+ field(:token_transfers_count, :integer)
field :smart_contract, :smart_contract do
resolve(dataloader(:db, :smart_contract))
@@ -36,16 +40,7 @@ defmodule BlockScoutWeb.Schema.Types do
arg(:order, type: :sort_order, default_value: :desc)
resolve(&Transaction.get_by/3)
- complexity(fn
- %{first: first}, child_complexity ->
- first * child_complexity
-
- %{last: last}, child_complexity ->
- last * child_complexity
-
- %{}, _child_complexity ->
- 0
- end)
+ complexity(fn params, child_complexity -> process_complexity(params, child_complexity) end)
end
end
@@ -55,18 +50,20 @@ defmodule BlockScoutWeb.Schema.Types do
structure that they form is called a "blockchain".
"""
object :block do
- field(:hash, :full_hash)
field(:consensus, :boolean)
field(:difficulty, :decimal)
field(:gas_limit, :decimal)
field(:gas_used, :decimal)
+ field(:hash, :full_hash)
+ field(:miner_hash, :address_hash)
field(:nonce, :nonce_hash)
field(:number, :integer)
+ field(:parent_hash, :full_hash)
field(:size, :integer)
field(:timestamp, :datetime)
field(:total_difficulty, :decimal)
- field(:miner_hash, :address_hash)
- field(:parent_hash, :full_hash)
+ field(:base_fee_per_gas, :wei)
+ field(:is_empty, :boolean)
end
@desc """
@@ -85,12 +82,14 @@ defmodule BlockScoutWeb.Schema.Types do
field(:trace_address, :json)
field(:type, :type)
field(:value, :wei)
- field(:block_number, :integer)
- field(:transaction_index, :integer)
field(:created_contract_address_hash, :address_hash)
field(:from_address_hash, :address_hash)
field(:to_address_hash, :address_hash)
field(:transaction_hash, :full_hash)
+ field(:block_number, :integer)
+ field(:transaction_index, :integer)
+ field(:block_hash, :full_hash)
+ field(:block_index, :integer)
end
@desc """
@@ -108,6 +107,19 @@ defmodule BlockScoutWeb.Schema.Types do
field(:contract_source_code, :string)
field(:abi, :json)
field(:address_hash, :address_hash)
+ field(:constructor_arguments, :string)
+ field(:optimization_runs, :integer)
+ field(:evm_version, :string)
+ field(:external_libraries, :json)
+ field(:verified_via_sourcify, :boolean)
+ field(:partially_verified, :boolean)
+ field(:file_path, :string)
+ field(:is_vyper_contract, :boolean)
+ field(:is_changed_bytecode, :boolean)
+ field(:implementation_name, :string)
+ field(:implementation_address_hash, :address_hash)
+ field(:compiler_settings, :json)
+ field(:verified_via_eth_bytecode_db, :boolean)
end
@desc """
@@ -130,13 +142,12 @@ defmodule BlockScoutWeb.Schema.Types do
Models a Web3 transaction.
"""
node object(:transaction, id_fetcher: &transaction_id_fetcher/2) do
- field(:hash, :full_hash)
- field(:block_number, :integer)
field(:cumulative_gas_used, :decimal)
field(:error, :string)
field(:gas, :decimal)
field(:gas_price, :wei)
field(:gas_used, :decimal)
+ field(:hash, :full_hash)
field(:index, :integer)
field(:input, :string)
field(:nonce, :nonce_hash)
@@ -145,24 +156,23 @@ defmodule BlockScoutWeb.Schema.Types do
field(:status, :status)
field(:v, :decimal)
field(:value, :wei)
+ field(:block_hash, :full_hash)
+ field(:block_number, :integer)
field(:from_address_hash, :address_hash)
field(:to_address_hash, :address_hash)
field(:created_contract_address_hash, :address_hash)
+ field(:earliest_processing_start, :datetime)
+ field(:revert_reason, :string)
+ field(:max_priority_fee_per_gas, :wei)
+ field(:max_fee_per_gas, :wei)
+ field(:type, :integer)
+ field(:has_error_in_internal_txs, :boolean)
connection field(:internal_transactions, node_type: :internal_transaction) do
arg(:count, :integer)
resolve(&InternalTransaction.get_by/3)
- complexity(fn
- %{first: first}, child_complexity ->
- first * child_complexity
-
- %{last: last}, child_complexity ->
- last * child_complexity
-
- %{}, _child_complexity ->
- 0
- end)
+ complexity(fn params, child_complexity -> process_complexity(params, child_complexity) end)
end
end
@@ -175,4 +185,17 @@ defmodule BlockScoutWeb.Schema.Types do
def internal_transaction_id_fetcher(%{transaction_hash: transaction_hash, index: index}, _) do
Jason.encode!(%{transaction_hash: to_string(transaction_hash), index: index})
end
+
+ defp process_complexity(params, child_complexity) do
+ case params do
+ %{first: first} ->
+ first * child_complexity
+
+ %{last: last} ->
+ last * child_complexity
+
+ %{} ->
+ 0
+ end
+ end
end
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/_tabs.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/_tabs.html.eex
index de29c7e7fd9d..a4060c9485d9 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address/_tabs.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address/_tabs.html.eex
@@ -8,7 +8,7 @@
class: "card-tab #{tab_status("transactions", @conn.request_path)}",
to: AccessHelper.get_path(@conn, :address_transaction_path, :index, @address.hash)
) %>
- <%= if Chain.check_if_token_transfers_at_address(@address.hash) do %>
+ <%= if Counters.check_if_token_transfers_at_address(@address.hash) do %>
<%= link(
gettext("Token Transfers"),
class: "card-tab #{tab_status("token-transfers", @conn.request_path)}",
@@ -16,7 +16,7 @@
to: AccessHelper.get_path(@conn, :address_token_transfers_path, :index, @address.hash)
) %>
<% end %>
- <%= if Chain.check_if_tokens_at_address(@address.hash) do %>
+ <%= if Counters.check_if_tokens_at_address(@address.hash) do %>
<%= link(
gettext("Tokens"),
class: "card-tab #{tab_status("tokens", @conn.request_path)}",
@@ -24,7 +24,7 @@
"data-test": "tokens_tab_link"
) %>
<% end %>
- <%= if Chain.check_if_withdrawals_at_address(@address.hash) do %>
+ <%= if Counters.check_if_withdrawals_at_address(@address.hash) do %>
<%= link(
gettext("Withdrawals"),
class: "card-tab #{tab_status("withdrawals", @conn.request_path)}",
@@ -44,14 +44,14 @@
"data-test": "coin_balance_tab_link",
to: AccessHelper.get_path(@conn, :address_coin_balance_path, :index, @address.hash)
) %>
- <%= if Chain.check_if_logs_at_address(@address.hash) do %>
+ <%= if Counters.check_if_logs_at_address(@address.hash) do %>
<%= link(
gettext("Logs"),
class: "card-tab #{tab_status("logs", @conn.request_path)}",
to: AccessHelper.get_path(@conn, :address_logs_path, :index, @address.hash)
) %>
<% end %>
- <%= if Chain.check_if_validated_blocks_at_address(@address.hash) do %>
+ <%= if Counters.check_if_validated_blocks_at_address(@address.hash) do %>
<%= link(
gettext("Blocks Validated"),
class: "card-tab #{tab_status("validations", @conn.request_path)}",
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
index 658acfd417b4..77c96739cb5d 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
@@ -43,7 +43,7 @@
<% end %>
<%= if smart_contract_verified || (!smart_contract_verified && metadata_for_verification) do %>
<% target_contract = if smart_contract_verified, do: @address.smart_contract, else: metadata_for_verification %>
- <%= if @address.smart_contract.partially_verified && smart_contract_verified do %>
+ <%= if @address.smart_contract.verified_via_sourcify && @address.smart_contract.partially_verified && smart_contract_verified do %>
<%= gettext("This contract has been partially verified via Sourcify.") %>
<% else %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/csv_export/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/csv_export/index.html.eex
index f0484d83d28e..979926300cf6 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/csv_export/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/csv_export/index.html.eex
@@ -27,7 +27,7 @@
id="export-csv-button"
class="button button-primary"
style="padding: 10px 25px;"
- data-link=<%= address_transaction_path(@conn, type_download_path(@type)) %>
+ data-link=<%= BlockScoutWebController.full_path("/api/v1/#{type_download_path(@type)}") %>
data-address-hash=<%= address_checksum(@address_hash_string) %>
data-type=<%= @type %>
><%= gettext("Download") %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/page_not_found/index.json.eex b/apps/block_scout_web/lib/block_scout_web/templates/page_not_found/index.json.eex
new file mode 100644
index 000000000000..98b8502d5f4f
--- /dev/null
+++ b/apps/block_scout_web/lib/block_scout_web/templates/page_not_found/index.json.eex
@@ -0,0 +1 @@
+Page not found
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/static/robots.txt b/apps/block_scout_web/lib/block_scout_web/templates/robots/robots.txt.eex
similarity index 76%
rename from apps/block_scout_web/assets/static/robots.txt
rename to apps/block_scout_web/lib/block_scout_web/templates/robots/robots.txt.eex
index 3c9c7c01f30b..e2f1434e2429 100644
--- a/apps/block_scout_web/assets/static/robots.txt
+++ b/apps/block_scout_web/lib/block_scout_web/templates/robots/robots.txt.eex
@@ -3,3 +3,4 @@
# To ban all spiders from the entire site uncomment the next two lines:
# User-agent: *
# Disallow: /
+Sitemap: <%= APIDocsView.blockscout_url(true) %>/sitemap.xml
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/robots/sitemap.xml.eex b/apps/block_scout_web/lib/block_scout_web/templates/robots/sitemap.xml.eex
new file mode 100644
index 000000000000..0c5334f21aa4
--- /dev/null
+++ b/apps/block_scout_web/lib/block_scout_web/templates/robots/sitemap.xml.eex
@@ -0,0 +1,53 @@
+
+<% host = APIDocsView.blockscout_url(true) %>
+<% date = to_string(Date.utc_today()) %>
+<% non_parameterized_urls = ["/", "/txs", "/blocks", "/accounts", "/verified-contracts", "/tokens", "/apps", "/stats", "/api-docs", "/graphiql", "/search-results", "/withdrawals", "/l2-deposits", "/l2-output-roots", "/l2-txn-batches", "/l2-withdrawals"] %>
+<% params = [paging_options: %PagingOptions{page_size: limit()}] %>
+
+ <%= for url <- non_parameterized_urls do %>
+
+ <%= host %><%= url %>
+ <%= date %>
+
+ <% end %>
+
+ <% addresses = Chain.list_top_addresses(params) %>
+ <%= for {address, _} <- addresses do %>
+
+ <%= host %>/address/<%= to_string(address) %>
+ <%= date %>
+
+ <% end %>
+
+ <% txs = Chain.recent_transactions(params, [:validated]) %>
+ <%= for tx <- txs do %>
+
+ <%= host %>/tx/<%= to_string(tx.hash) %>
+ <%= date %>
+
+ <% end %>
+
+ <% blocks = Chain.list_blocks(params) %>
+ <%= for block <- blocks do %>
+
+ <%= host %>/block/<%= to_string(block.number) %>
+ <%= date %>
+
+ <% end %>
+
+ <% tokens = Chain.list_top_tokens(nil, params) %>
+ <%= for token <- tokens do %>
+
+ <%= host %>/token/<%= to_string(token.contract_address_hash) %>
+ <%= date %>
+
+ <% end %>
+
+ <% smart_contracts_hashes = Chain.verified_contracts_top(limit()) %>
+ <%= for hash <- smart_contracts_hashes do %>
+
+ <%= host %>/address/<%= Address.checksum(hash) %>?tab=contract
+ <%= date %>
+
+ <% end %>
+
\ No newline at end of file
diff --git a/apps/block_scout_web/lib/block_scout_web/views/abi_encoded_value_view.ex b/apps/block_scout_web/lib/block_scout_web/views/abi_encoded_value_view.ex
index a4a7fc66bebb..c25dbbf5392e 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/abi_encoded_value_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/abi_encoded_value_view.ex
@@ -192,23 +192,21 @@ defmodule BlockScoutWeb.ABIEncodedValueView do
end
defp base_value_json(_, {:dynamic, value}) do
- hex(value)
+ hex_for_json(value)
end
defp base_value_json(:address, value) do
- hex(value)
- end
-
- defp base_value_json(:address_text, value) do
- hex(value)
+ hex_for_json(value)
end
defp base_value_json(:bytes, value) do
- hex(value)
+ hex_for_json(value)
end
defp base_value_json(_, value), do: to_string(value)
defp hex("0x" <> value), do: "0x" <> value
defp hex(value), do: "0x" <> Base.encode16(value, case: :lower)
+
+ defp hex_for_json(value), do: "0x" <> Base.encode16(value, case: :lower)
end
diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex
index 3f60d4c7eadc..41ebf80976d6 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/address_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/address_view.ex
@@ -6,6 +6,7 @@ defmodule BlockScoutWeb.AddressView do
alias BlockScoutWeb.{AccessHelper, LayoutView}
alias Explorer.Account.CustomABI
alias Explorer.{Chain, CustomContractsHelper, Repo}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Chain.{Address, Hash, InternalTransaction, Log, SmartContract, Token, TokenTransfer, Transaction, Wei}
alias Explorer.Chain.Block.Reward
alias Explorer.ExchangeRates.Token, as: TokenExchangeRate
diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex
index 4f1601f23481..9cdf88abb2f9 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/address_view.ex
@@ -7,6 +7,7 @@ defmodule BlockScoutWeb.API.V2.AddressView do
alias BlockScoutWeb.API.V2.{ApiView, Helper, TokenView}
alias BlockScoutWeb.API.V2.Helper
alias Explorer.{Chain, Market}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Chain.{Address, SmartContract}
@api_true [api?: true]
@@ -102,12 +103,12 @@ defmodule BlockScoutWeb.API.V2.AddressView do
"has_methods_read_proxy" => is_proxy,
"has_methods_write_proxy" => AddressView.smart_contract_with_write_functions?(address) && is_proxy,
"has_decompiled_code" => AddressView.has_decompiled_code?(address),
- "has_validated_blocks" => Chain.check_if_validated_blocks_at_address(address.hash, @api_true),
- "has_logs" => Chain.check_if_logs_at_address(address.hash, @api_true),
- "has_tokens" => Chain.check_if_tokens_at_address(address.hash, @api_true),
- "has_token_transfers" => Chain.check_if_token_transfers_at_address(address.hash, @api_true),
+ "has_validated_blocks" => Counters.check_if_validated_blocks_at_address(address.hash, @api_true),
+ "has_logs" => Counters.check_if_logs_at_address(address.hash, @api_true),
+ "has_tokens" => Counters.check_if_tokens_at_address(address.hash, @api_true),
+ "has_token_transfers" => Counters.check_if_token_transfers_at_address(address.hash, @api_true),
"watchlist_address_id" => Chain.select_watchlist_address_id(get_watchlist_id(conn), address.hash),
- "has_beacon_chain_withdrawals" => Chain.check_if_withdrawals_at_address(address.hash, @api_true)
+ "has_beacon_chain_withdrawals" => Counters.check_if_withdrawals_at_address(address.hash, @api_true)
})
end
diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/block_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/block_view.ex
index 9c022d364e52..8da05d3b686a 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/block_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/block_view.ex
@@ -50,9 +50,9 @@ defmodule BlockScoutWeb.API.V2.BlockView do
"base_fee_per_gas" => block.base_fee_per_gas,
"burnt_fees" => burned_fee,
"priority_fee" => priority_fee,
- "extra_data" => "TODO",
+ # "extra_data" => "TODO",
"uncles_hashes" => prepare_uncles(block.uncle_relations),
- "state_root" => "TODO",
+ # "state_root" => "TODO",
"rewards" => prepare_rewards(block.rewards, block, single_block?),
"gas_target_percentage" => gas_target(block),
"gas_used_percentage" => gas_used_percentage(block),
diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex
index b0e25f978d02..9b82e01ede77 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/helper.ex
@@ -104,19 +104,15 @@ defmodule BlockScoutWeb.API.V2.Helper do
def is_verified(%Address{smart_contract: %NotLoaded{}}), do: nil
def is_verified(%Address{smart_contract: _}), do: true
- def market_cap(:standard, %{available_supply: available_supply, usd_value: usd_value})
+ def market_cap(:standard, %{available_supply: available_supply, usd_value: usd_value, market_cap_usd: market_cap_usd})
when is_nil(available_supply) or is_nil(usd_value) do
- Decimal.new(0)
+ max(Decimal.new(0), market_cap_usd)
end
def market_cap(:standard, %{available_supply: available_supply, usd_value: usd_value}) do
Decimal.mult(available_supply, usd_value)
end
- def market_cap(:standard, exchange_rate) do
- exchange_rate.market_cap_usd
- end
-
def market_cap(module, exchange_rate) do
module.market_cap(exchange_rate)
end
diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/search_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/search_view.ex
index 7b4f45cbb2da..3663e2f96e80 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/search_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/search_view.ex
@@ -2,12 +2,16 @@ defmodule BlockScoutWeb.API.V2.SearchView do
use BlockScoutWeb, :view
alias BlockScoutWeb.Endpoint
- alias Explorer.Chain.{Address, Block, Transaction}
+ alias Explorer.Chain.{Address, Block, Hash, Transaction}
def render("search_results.json", %{search_results: search_results, next_page_params: next_page_params}) do
%{"items" => Enum.map(search_results, &prepare_search_result/1), "next_page_params" => next_page_params}
end
+ def render("search_results.json", %{search_results: search_results}) do
+ Enum.map(search_results, &prepare_search_result/1)
+ end
+
def render("search_results.json", %{result: {:ok, result}}) do
Map.merge(%{"redirect" => true}, redirect_search_results(result))
end
@@ -30,7 +34,8 @@ defmodule BlockScoutWeb.API.V2.SearchView do
"exchange_rate" => search_result.exchange_rate && to_string(search_result.exchange_rate),
"total_supply" => search_result.total_supply,
"circulating_market_cap" =>
- search_result.circulating_market_cap && to_string(search_result.circulating_market_cap)
+ search_result.circulating_market_cap && to_string(search_result.circulating_market_cap),
+ "is_verified_via_admin_panel" => search_result.is_verified_via_admin_panel
}
end
@@ -68,6 +73,7 @@ defmodule BlockScoutWeb.API.V2.SearchView do
}
end
+ defp hash_to_string(%Hash{bytes: bytes}), do: hash_to_string(bytes)
defp hash_to_string(hash), do: "0x" <> Base.encode16(hash, case: :lower)
defp redirect_search_results(%Address{} = item) do
diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex
index 6a35a0c6fbd3..1c102bf0cc11 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/smart_contract_view.ex
@@ -1,6 +1,8 @@
defmodule BlockScoutWeb.API.V2.SmartContractView do
use BlockScoutWeb, :view
+ import Explorer.SmartContract.Reader, only: [zip_tuple_values_with_types: 2]
+
alias ABI.FunctionSelector
alias BlockScoutWeb.API.V2.{Helper, TransactionView}
alias BlockScoutWeb.SmartContractView
@@ -284,28 +286,31 @@ defmodule BlockScoutWeb.API.V2.SmartContractView do
%{"type" => type, "value" => render_json(value, type)}
end
- def render_json(value, type) when type in [:address, "address", "address payable"] do
- SmartContractView.cast_address(value)
- end
-
- def render_json(value, type) when type in [:string, "string"] do
- to_string(value)
- end
-
def render_json(value, type) when is_tuple(value) do
value
- |> SmartContractView.zip_tuple_values_with_types(type)
+ |> zip_tuple_values_with_types(type)
|> Enum.map(fn {type, value} ->
render_json(value, type)
end)
end
def render_json(value, type) when is_list(value) do
+ type =
+ if String.ends_with?(type, "[]") do
+ String.slice(type, 0..-3)
+ else
+ type
+ end
+
value |> Enum.map(&render_json(&1, type))
end
- def render_json(value, _type) when is_binary(value) do
- SmartContractView.binary_to_utf_string(value)
+ def render_json(value, type) when type in [:address, "address", "address payable"] do
+ SmartContractView.cast_address(value)
+ end
+
+ def render_json(value, type) when type in [:string, "string"] do
+ to_string(value)
end
def render_json(value, _type) do
diff --git a/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex b/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex
index fe60782eb14b..7f983ed84b56 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/api/v2/token_view.ex
@@ -13,7 +13,7 @@ defmodule BlockScoutWeb.API.V2.TokenView do
"name" => token.name,
"decimals" => token.decimals,
"type" => token.type,
- "holders" => token.holder_count && to_string(token.holder_count),
+ "holders" => prepare_holders_count(token.holder_count),
"exchange_rate" => exchange_rate(token),
"total_supply" => token.total_supply,
"icon_url" => token.icon_url,
@@ -80,4 +80,8 @@ defmodule BlockScoutWeb.API.V2.TokenView do
"is_unique" => is_unique
}
end
+
+ defp prepare_holders_count(nil), do: nil
+ defp prepare_holders_count(count) when count < 0, do: prepare_holders_count(0)
+ defp prepare_holders_count(count), do: to_string(count)
end
diff --git a/apps/block_scout_web/lib/block_scout_web/views/csv_export.ex b/apps/block_scout_web/lib/block_scout_web/views/csv_export.ex
index 34596956e45a..a076e1d00afe 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/csv_export.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/csv_export.ex
@@ -1,6 +1,7 @@
defmodule BlockScoutWeb.CsvExportView do
use BlockScoutWeb, :view
+ alias BlockScoutWeb.Controller, as: BlockScoutWebController
alias Explorer.Chain
alias Explorer.Chain.Address
alias Explorer.Chain.CSVExport.Helper
@@ -15,14 +16,10 @@ defmodule BlockScoutWeb.CsvExportView do
end
end
+ defp type_download_path(nil), do: ""
+
defp type_download_path(type) do
- case type do
- "internal-transactions" -> :internal_transactions_csv
- "transactions" -> :transactions_csv
- "token-transfers" -> :token_transfers_csv
- "logs" -> :logs_csv
- _ -> ""
- end
+ type <> "-csv"
end
defp address_checksum(address_hash_string) do
diff --git a/apps/block_scout_web/lib/block_scout_web/views/robots_view.ex b/apps/block_scout_web/lib/block_scout_web/views/robots_view.ex
new file mode 100644
index 000000000000..20e4cca0596f
--- /dev/null
+++ b/apps/block_scout_web/lib/block_scout_web/views/robots_view.ex
@@ -0,0 +1,10 @@
+defmodule BlockScoutWeb.RobotsView do
+ use BlockScoutWeb, :view
+
+ alias BlockScoutWeb.APIDocsView
+ alias Explorer.{Chain, PagingOptions}
+ alias Explorer.Chain.Address
+
+ @limit 200
+ defp limit, do: @limit
+end
diff --git a/apps/block_scout_web/lib/block_scout_web/views/smart_contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/smart_contract_view.ex
index 4a96a93adb6c..f0245adc2dfc 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/smart_contract_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/smart_contract_view.ex
@@ -1,6 +1,8 @@
defmodule BlockScoutWeb.SmartContractView do
use BlockScoutWeb, :view
+ import Explorer.SmartContract.Reader, only: [zip_tuple_values_with_types: 2]
+
alias Explorer.Chain
alias Explorer.Chain.{Address, Transaction}
alias Explorer.Chain.Hash.Address, as: HashAddress
@@ -72,7 +74,7 @@ defmodule BlockScoutWeb.SmartContractView do
String.starts_with?(type, "bytes") ->
values =
value
- |> Enum.map_join(", ", &binary_to_utf_string(&1))
+ |> Enum.join(", ")
render_array_type_value(type, values, fetch_name(names, index))
@@ -107,6 +109,9 @@ defmodule BlockScoutWeb.SmartContractView do
def values_with_type(value, string, names, index, _components) when string in ["string", :string],
do: render_type_value("string", Helper.sanitize_input(value), fetch_name(names, index))
+ def values_with_type(value, "bytes" <> _ = bytes_type, names, index, _components),
+ do: render_type_value(bytes_type, Helper.sanitize_input(value), fetch_name(names, index))
+
def values_with_type(value, bytes, names, index, _components) when bytes in [:bytes],
do: render_type_value("bytes", Helper.sanitize_input(value), fetch_name(names, index))
@@ -114,7 +119,7 @@ defmodule BlockScoutWeb.SmartContractView do
do: render_type_value("bool", Helper.sanitize_input(to_string(value)), fetch_name(names, index))
def values_with_type(value, type, names, index, _components),
- do: render_type_value(type, Helper.sanitize_input(binary_to_utf_string(value)), fetch_name(names, index))
+ do: render_type_value(type, Helper.sanitize_input(value), fetch_name(names, index))
def values_with_type(value, :error, _components),
do: render_type_value("error", Helper.sanitize_input(value), "error")
@@ -158,78 +163,6 @@ defmodule BlockScoutWeb.SmartContractView do
end)
end
- def zip_tuple_values_with_types(value, type) do
- types_string =
- type
- |> String.slice(6..-2)
-
- types =
- if String.trim(types_string) == "" do
- []
- else
- types_string
- |> String.split(",")
- end
-
- {tuple_types, _} =
- types
- |> Enum.reduce({[], nil}, fn val, acc ->
- {arr, to_merge} = acc
-
- if to_merge do
- compose_array_if_to_merge(arr, val, to_merge)
- else
- compose_array_else(arr, val, to_merge)
- end
- end)
-
- values_list =
- value
- |> Tuple.to_list()
-
- Enum.zip(tuple_types, values_list)
- end
-
- def compose_array_if_to_merge(arr, val, to_merge) do
- if count_string_symbols(val)["]"] > count_string_symbols(val)["["] do
- updated_arr = update_last_list_item(arr, val)
- {updated_arr, !to_merge}
- else
- updated_arr = update_last_list_item(arr, val)
- {updated_arr, to_merge}
- end
- end
-
- def compose_array_else(arr, val, to_merge) do
- if count_string_symbols(val)["["] > count_string_symbols(val)["]"] do
- # credo:disable-for-next-line
- {arr ++ [val], !to_merge}
- else
- # credo:disable-for-next-line
- {arr ++ [val], to_merge}
- end
- end
-
- defp update_last_list_item(arr, new_val) do
- arr
- |> Enum.with_index()
- |> Enum.map(fn {item, index} ->
- if index == Enum.count(arr) - 1 do
- item <> "," <> new_val
- else
- item
- end
- end)
- end
-
- defp count_string_symbols(str) do
- str
- |> String.graphemes()
- |> Enum.reduce(%{"[" => 0, "]" => 0}, fn char, acc ->
- Map.update(acc, char, 1, &(&1 + 1))
- end)
- end
-
def binary_to_utf_string(item) do
case Integer.parse(to_string(item)) do
{item_integer, ""} ->
diff --git a/apps/block_scout_web/lib/block_scout_web/web_router.ex b/apps/block_scout_web/lib/block_scout_web/web_router.ex
index 4b3f7a20ae74..3f3dbed7d10e 100644
--- a/apps/block_scout_web/lib/block_scout_web/web_router.ex
+++ b/apps/block_scout_web/lib/block_scout_web/web_router.ex
@@ -493,16 +493,8 @@ defmodule BlockScoutWeb.WebRouter do
get("/csv-export", CsvExportController, :index)
- get("/transactions-csv", AddressTransactionController, :transactions_csv)
-
get("/token-autocomplete", ChainController, :token_autocomplete)
- get("/token-transfers-csv", AddressTransactionController, :token_transfers_csv)
-
- get("/internal-transactions-csv", AddressTransactionController, :internal_transactions_csv)
-
- get("/logs-csv", AddressTransactionController, :logs_csv)
-
get("/chain-blocks", ChainController, :chain_blocks, as: :chain_blocks)
get("/token-counters", Tokens.TokenController, :token_counters)
diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs
index a101102aaa40..01efe54cadbf 100644
--- a/apps/block_scout_web/mix.exs
+++ b/apps/block_scout_web/mix.exs
@@ -23,7 +23,7 @@ defmodule BlockScoutWeb.Mixfile do
dialyzer: :test
],
start_permanent: Mix.env() == :prod,
- version: "5.2.1"
+ version: "5.2.2"
]
end
@@ -83,7 +83,7 @@ defmodule BlockScoutWeb.Mixfile do
# HTML CSS selectors for Phoenix controller tests
{:floki, "~> 0.31"},
{:flow, "~> 1.2"},
- {:gettext, "~> 0.22.0"},
+ {:gettext, "~> 0.23.1"},
{:hammer, "~> 6.0"},
{:httpoison, "~> 2.0"},
{:indexer, in_umbrella: true, runtime: false},
diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot
index 9e448f7f82a7..930e2348eca3 100644
--- a/apps/block_scout_web/priv/gettext/default.pot
+++ b/apps/block_scout_web/priv/gettext/default.pot
@@ -265,7 +265,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:20
#: lib/block_scout_web/templates/transaction_state/index.html.eex:34
#: lib/block_scout_web/templates/verified_contracts/index.html.eex:60
-#: lib/block_scout_web/views/address_view.ex:107
+#: lib/block_scout_web/views/address_view.ex:108
#, elixir-autogen, elixir-format
msgid "Address"
msgstr ""
@@ -556,7 +556,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:56
#: lib/block_scout_web/templates/address/overview.html.eex:275
#: lib/block_scout_web/templates/address_validation/index.html.eex:11
-#: lib/block_scout_web/views/address_view.ex:384
+#: lib/block_scout_web/views/address_view.ex:385
#, elixir-autogen, elixir-format
msgid "Blocks Validated"
msgstr ""
@@ -656,13 +656,13 @@ msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149
-#: lib/block_scout_web/views/address_view.ex:377
+#: lib/block_scout_web/views/address_view.ex:378
#, elixir-autogen, elixir-format
msgid "Code"
msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:42
-#: lib/block_scout_web/views/address_view.ex:383
+#: lib/block_scout_web/views/address_view.ex:384
#, elixir-autogen, elixir-format
msgid "Coin Balance History"
msgstr ""
@@ -771,14 +771,14 @@ msgstr ""
#: lib/block_scout_web/templates/account/custom_abi/form.html.eex:18
#: lib/block_scout_web/templates/account/custom_abi/index.html.eex:29
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_contract_address_field.html.eex:3
-#: lib/block_scout_web/views/address_view.ex:105
+#: lib/block_scout_web/views/address_view.ex:106
#, elixir-autogen, elixir-format
msgid "Contract Address"
msgstr ""
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:16
-#: lib/block_scout_web/views/address_view.ex:45
-#: lib/block_scout_web/views/address_view.ex:79
+#: lib/block_scout_web/views/address_view.ex:46
+#: lib/block_scout_web/views/address_view.ex:80
#, elixir-autogen, elixir-format
msgid "Contract Address Pending"
msgstr ""
@@ -1084,7 +1084,7 @@ msgstr ""
msgid "Decoded"
msgstr ""
-#: lib/block_scout_web/views/address_view.ex:378
+#: lib/block_scout_web/views/address_view.ex:379
#, elixir-autogen, elixir-format
msgid "Decompiled Code"
msgstr ""
@@ -1601,7 +1601,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:17
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
-#: lib/block_scout_web/views/address_view.ex:374
+#: lib/block_scout_web/views/address_view.ex:375
#: lib/block_scout_web/views/transaction_view.ex:533
#, elixir-autogen, elixir-format
msgid "Internal Transactions"
@@ -1718,7 +1718,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_logs/index.html.eex:10
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
-#: lib/block_scout_web/views/address_view.ex:385
+#: lib/block_scout_web/views/address_view.ex:386
#: lib/block_scout_web/views/transaction_view.ex:534
#, elixir-autogen, elixir-format
msgid "Logs"
@@ -1732,7 +1732,7 @@ msgstr ""
#: lib/block_scout_web/templates/chain/show.html.eex:53
#: lib/block_scout_web/templates/layout/app.html.eex:50
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:85
-#: lib/block_scout_web/views/address_view.ex:145
+#: lib/block_scout_web/views/address_view.ex:146
#, elixir-autogen, elixir-format
msgid "Market Cap"
msgstr ""
@@ -2208,7 +2208,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:89
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:27
-#: lib/block_scout_web/views/address_view.ex:379
+#: lib/block_scout_web/views/address_view.ex:380
#: lib/block_scout_web/views/tokens/overview_view.ex:41
#, elixir-autogen, elixir-format
msgid "Read Contract"
@@ -2216,7 +2216,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:96
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:41
-#: lib/block_scout_web/views/address_view.ex:380
+#: lib/block_scout_web/views/address_view.ex:381
#, elixir-autogen, elixir-format
msgid "Read Proxy"
msgstr ""
@@ -2903,7 +2903,7 @@ msgstr ""
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:15
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7
-#: lib/block_scout_web/views/address_view.ex:376
+#: lib/block_scout_web/views/address_view.ex:377
#: lib/block_scout_web/views/tokens/instance/overview_view.ex:114
#: lib/block_scout_web/views/tokens/overview_view.ex:39
#: lib/block_scout_web/views/transaction_view.ex:532
@@ -2927,7 +2927,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:13
#: lib/block_scout_web/templates/layout/_topnav.html.eex:84
#: lib/block_scout_web/templates/tokens/index.html.eex:10
-#: lib/block_scout_web/views/address_view.ex:373
+#: lib/block_scout_web/views/address_view.ex:374
#, elixir-autogen, elixir-format
msgid "Tokens"
msgstr ""
@@ -3099,7 +3099,7 @@ msgstr ""
#: lib/block_scout_web/templates/block/overview.html.eex:80
#: lib/block_scout_web/templates/chain/show.html.eex:214
#: lib/block_scout_web/templates/layout/_topnav.html.eex:49
-#: lib/block_scout_web/views/address_view.ex:375
+#: lib/block_scout_web/views/address_view.ex:376
#, elixir-autogen, elixir-format
msgid "Transactions"
msgstr ""
@@ -3469,14 +3469,14 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:103
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:34
-#: lib/block_scout_web/views/address_view.ex:381
+#: lib/block_scout_web/views/address_view.ex:382
#, elixir-autogen, elixir-format
msgid "Write Contract"
msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:110
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:48
-#: lib/block_scout_web/views/address_view.ex:382
+#: lib/block_scout_web/views/address_view.ex:383
#, elixir-autogen, elixir-format
msgid "Write Proxy"
msgstr ""
diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
index d84b5aca859a..dd08664c4b1f 100644
--- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
+++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
@@ -265,7 +265,7 @@ msgstr ""
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:20
#: lib/block_scout_web/templates/transaction_state/index.html.eex:34
#: lib/block_scout_web/templates/verified_contracts/index.html.eex:60
-#: lib/block_scout_web/views/address_view.ex:107
+#: lib/block_scout_web/views/address_view.ex:108
#, elixir-autogen, elixir-format
msgid "Address"
msgstr ""
@@ -556,7 +556,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:56
#: lib/block_scout_web/templates/address/overview.html.eex:275
#: lib/block_scout_web/templates/address_validation/index.html.eex:11
-#: lib/block_scout_web/views/address_view.ex:384
+#: lib/block_scout_web/views/address_view.ex:385
#, elixir-autogen, elixir-format
msgid "Blocks Validated"
msgstr ""
@@ -656,13 +656,13 @@ msgstr ""
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:187
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:126
#: lib/block_scout_web/templates/api_docs/_eth_rpc_item.html.eex:149
-#: lib/block_scout_web/views/address_view.ex:377
+#: lib/block_scout_web/views/address_view.ex:378
#, elixir-autogen, elixir-format
msgid "Code"
msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:42
-#: lib/block_scout_web/views/address_view.ex:383
+#: lib/block_scout_web/views/address_view.ex:384
#, elixir-autogen, elixir-format
msgid "Coin Balance History"
msgstr ""
@@ -771,14 +771,14 @@ msgstr ""
#: lib/block_scout_web/templates/account/custom_abi/form.html.eex:18
#: lib/block_scout_web/templates/account/custom_abi/index.html.eex:29
#: lib/block_scout_web/templates/address_contract_verification_common_fields/_contract_address_field.html.eex:3
-#: lib/block_scout_web/views/address_view.ex:105
+#: lib/block_scout_web/views/address_view.ex:106
#, elixir-autogen, elixir-format
msgid "Contract Address"
msgstr ""
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:16
-#: lib/block_scout_web/views/address_view.ex:45
-#: lib/block_scout_web/views/address_view.ex:79
+#: lib/block_scout_web/views/address_view.ex:46
+#: lib/block_scout_web/views/address_view.ex:80
#, elixir-autogen, elixir-format
msgid "Contract Address Pending"
msgstr ""
@@ -1084,7 +1084,7 @@ msgstr ""
msgid "Decoded"
msgstr ""
-#: lib/block_scout_web/views/address_view.ex:378
+#: lib/block_scout_web/views/address_view.ex:379
#, elixir-autogen, elixir-format
msgid "Decompiled Code"
msgstr ""
@@ -1601,7 +1601,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:17
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:11
#: lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex:6
-#: lib/block_scout_web/views/address_view.ex:374
+#: lib/block_scout_web/views/address_view.ex:375
#: lib/block_scout_web/views/transaction_view.ex:533
#, elixir-autogen, elixir-format
msgid "Internal Transactions"
@@ -1718,7 +1718,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_logs/index.html.eex:10
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:17
#: lib/block_scout_web/templates/transaction_log/index.html.eex:8
-#: lib/block_scout_web/views/address_view.ex:385
+#: lib/block_scout_web/views/address_view.ex:386
#: lib/block_scout_web/views/transaction_view.ex:534
#, elixir-autogen, elixir-format
msgid "Logs"
@@ -1732,7 +1732,7 @@ msgstr ""
#: lib/block_scout_web/templates/chain/show.html.eex:53
#: lib/block_scout_web/templates/layout/app.html.eex:50
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:85
-#: lib/block_scout_web/views/address_view.ex:145
+#: lib/block_scout_web/views/address_view.ex:146
#, elixir-autogen, elixir-format
msgid "Market Cap"
msgstr ""
@@ -2208,7 +2208,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:89
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:27
-#: lib/block_scout_web/views/address_view.ex:379
+#: lib/block_scout_web/views/address_view.ex:380
#: lib/block_scout_web/views/tokens/overview_view.ex:41
#, elixir-autogen, elixir-format
msgid "Read Contract"
@@ -2216,7 +2216,7 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:96
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:41
-#: lib/block_scout_web/views/address_view.ex:380
+#: lib/block_scout_web/views/address_view.ex:381
#, elixir-autogen, elixir-format
msgid "Read Proxy"
msgstr ""
@@ -2903,7 +2903,7 @@ msgstr ""
#: lib/block_scout_web/templates/tokens/transfer/index.html.eex:15
#: lib/block_scout_web/templates/transaction/_tabs.html.eex:4
#: lib/block_scout_web/templates/transaction_token_transfer/index.html.eex:7
-#: lib/block_scout_web/views/address_view.ex:376
+#: lib/block_scout_web/views/address_view.ex:377
#: lib/block_scout_web/views/tokens/instance/overview_view.ex:114
#: lib/block_scout_web/views/tokens/overview_view.ex:39
#: lib/block_scout_web/views/transaction_view.ex:532
@@ -2927,7 +2927,7 @@ msgstr ""
#: lib/block_scout_web/templates/address_token_transfer/index.html.eex:13
#: lib/block_scout_web/templates/layout/_topnav.html.eex:84
#: lib/block_scout_web/templates/tokens/index.html.eex:10
-#: lib/block_scout_web/views/address_view.ex:373
+#: lib/block_scout_web/views/address_view.ex:374
#, elixir-autogen, elixir-format
msgid "Tokens"
msgstr ""
@@ -3099,7 +3099,7 @@ msgstr ""
#: lib/block_scout_web/templates/block/overview.html.eex:80
#: lib/block_scout_web/templates/chain/show.html.eex:214
#: lib/block_scout_web/templates/layout/_topnav.html.eex:49
-#: lib/block_scout_web/views/address_view.ex:375
+#: lib/block_scout_web/views/address_view.ex:376
#, elixir-autogen, elixir-format
msgid "Transactions"
msgstr ""
@@ -3469,14 +3469,14 @@ msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:103
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:34
-#: lib/block_scout_web/views/address_view.ex:381
+#: lib/block_scout_web/views/address_view.ex:382
#, elixir-autogen, elixir-format
msgid "Write Contract"
msgstr ""
#: lib/block_scout_web/templates/address/_tabs.html.eex:110
#: lib/block_scout_web/templates/tokens/overview/_tabs.html.eex:48
-#: lib/block_scout_web/views/address_view.ex:382
+#: lib/block_scout_web/views/address_view.ex:383
#, elixir-autogen, elixir-format
msgid "Write Proxy"
msgstr ""
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs
index 3e1434750870..ad86587530fc 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs
@@ -176,7 +176,7 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
to_period = Timex.format!(Timex.now(), "%Y-%m-%d", :strftime)
conn =
- get(conn, "/token-transfers-csv", %{
+ get(conn, "/api/v1/token-transfers-csv", %{
"address_id" => Address.checksum(address.hash),
"from_period" => from_period,
"to_period" => to_period
@@ -203,7 +203,7 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
to_period = Timex.format!(Timex.now(), "%Y-%m-%d", :strftime)
conn =
- get(conn, "/token-transfers-csv", %{
+ get(conn, "/api/v1/token-transfers-csv", %{
"address_id" => Address.checksum(address.hash),
"from_period" => from_period,
"to_period" => to_period,
@@ -231,7 +231,7 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
to_period = Timex.format!(Timex.now(), "%Y-%m-%d", :strftime)
conn =
- get(conn, "/token-transfers-csv", %{
+ get(conn, "/api/v1/token-transfers-csv", %{
"address_id" => Address.checksum(address.hash),
"from_period" => from_period,
"to_period" => to_period
@@ -260,7 +260,7 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
to_period = Timex.format!(Timex.now(), "%Y-%m-%d", :strftime)
conn =
- get(conn, "/token-transfers-csv", %{
+ get(conn, "/api/v1/token-transfers-csv", %{
"address_id" => Address.checksum(address.hash),
"from_period" => from_period,
"to_period" => to_period,
@@ -290,7 +290,7 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
to_period = Timex.format!(Timex.now(), "%Y-%m-%d", :strftime)
conn =
- get(conn, "/transactions-csv", %{
+ get(conn, "/api/v1/transactions-csv", %{
"address_id" => Address.checksum(address.hash),
"from_period" => from_period,
"to_period" => to_period,
@@ -357,7 +357,7 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
to_period = Timex.format!(Timex.now(), "%Y-%m-%d", :strftime)
conn =
- get(conn, "/internal-transactions-csv", %{
+ get(conn, "/api/v1/internal-transactions-csv", %{
"address_id" => Address.checksum(address.hash),
"from_period" => from_period,
"to_period" => to_period,
@@ -418,7 +418,7 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
to_period = Timex.format!(Timex.now(), "%Y-%m-%d", :strftime)
conn =
- get(conn, "/logs-csv", %{
+ get(conn, "/api/v1/logs-csv", %{
"address_id" => Address.checksum(address.hash),
"from_period" => from_period,
"to_period" => to_period,
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs
index 0cd2b50bd390..752c393c4710 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/rpc/contract_controller_test.exs
@@ -712,7 +712,7 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
params = %{
"module" => "contract",
"action" => "verify_via_sourcify",
- "addressHash" => "0x18d89C12e9463Be6343c35C9990361bA4C42AfC2"
+ "addressHash" => "0xf26594F585De4EB0Ae9De865d9053FEe02ac6eF1"
}
response =
@@ -732,14 +732,14 @@ defmodule BlockScoutWeb.API.RPC.ContractControllerTest do
_created_contract_address =
insert(
:address,
- hash: "0x18d89C12e9463Be6343c35C9990361bA4C42AfC2",
+ hash: "0xf26594F585De4EB0Ae9De865d9053FEe02ac6eF1",
contract_code: smart_contract_bytecode
)
params = %{
"module" => "contract",
"action" => "verify_via_sourcify",
- "addressHash" => "0x18d89C12e9463Be6343c35C9990361bA4C42AfC2"
+ "addressHash" => "0xf26594F585De4EB0Ae9De865d9053FEe02ac6eF1"
}
get_implementation()
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs
index 7073f491550a..ee6f156fa525 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/address_controller_test.exs
@@ -3,6 +3,7 @@ defmodule BlockScoutWeb.API.V2.AddressControllerTest do
alias BlockScoutWeb.Models.UserFromAuth
alias Explorer.{Chain, Repo}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Chain.{
Address,
@@ -159,9 +160,9 @@ defmodule BlockScoutWeb.API.V2.AddressControllerTest do
insert(:block, miner: address)
- Chain.transaction_count(address)
- Chain.token_transfers_count(address)
- Chain.gas_usage_count(address)
+ Counters.transaction_count(address)
+ Counters.token_transfers_count(address)
+ Counters.gas_usage_count(address)
request = get(conn, "/api/v2/addresses/#{address.hash}/counters")
@@ -1534,21 +1535,29 @@ defmodule BlockScoutWeb.API.V2.AddressControllerTest do
ctbs_erc_20 =
for _ <- 0..50 do
- insert(:address_current_token_balance_with_token_id, address: address, token_type: "ERC-20", token_id: nil)
+ insert(:address_current_token_balance_with_token_id_and_fixed_token_type,
+ address: address,
+ token_type: "ERC-20",
+ token_id: nil
+ )
|> Repo.preload([:token])
end
- |> Enum.sort_by(fn x -> x.value end, :asc)
+ |> Enum.sort_by(fn x -> Decimal.to_float(Decimal.mult(x.value, x.token.fiat_value)) end, :asc)
ctbs_erc_721 =
for _ <- 0..50 do
- insert(:address_current_token_balance_with_token_id, address: address, token_type: "ERC-721", token_id: nil)
+ insert(:address_current_token_balance_with_token_id_and_fixed_token_type,
+ address: address,
+ token_type: "ERC-721",
+ token_id: nil
+ )
|> Repo.preload([:token])
end
|> Enum.sort_by(fn x -> x.value end, :asc)
ctbs_erc_1155 =
for _ <- 0..50 do
- insert(:address_current_token_balance_with_token_id,
+ insert(:address_current_token_balance_with_token_id_and_fixed_token_type,
address: address,
token_type: "ERC-1155",
token_id: Enum.random(1..100_000)
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/search_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/search_controller_test.exs
index e9dda32b848e..145963c99d32 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/search_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/search_controller_test.exs
@@ -135,6 +135,7 @@ defmodule BlockScoutWeb.API.V2.SearchControllerTest do
assert item["exchange_rate"] == (token.fiat_value && to_string(token.fiat_value))
assert item["total_supply"] == to_string(token.total_supply)
assert item["icon_url"] == token.icon_url
+ assert item["is_verified_via_admin_panel"] == token.is_verified_via_admin_panel
end
test "search transaction", %{conn: conn} do
@@ -287,4 +288,49 @@ defmodule BlockScoutWeb.API.V2.SearchControllerTest do
%{"redirect" => false, "type" => nil, "parameter" => nil} = json_response(request, 200)
end
end
+
+ describe "/search/quick" do
+ test "check that all categories are in response list", %{conn: conn} do
+ name = "156000"
+
+ tags =
+ for _ <- 0..50 do
+ insert(:address_to_tag, tag: build(:address_tag, display_name: name))
+ end
+
+ contracts = insert_list(50, :smart_contract, name: name)
+ tokens = insert_list(50, :token, name: name)
+ blocks = [insert(:block, number: name, consensus: false), insert(:block, number: name)]
+
+ request = get(conn, "/api/v2/search/quick?q=#{name}")
+ assert response = json_response(request, 200)
+ assert Enum.count(response) == 50
+
+ assert response |> Enum.filter(fn x -> x["type"] == "label" end) |> Enum.map(fn x -> x["address"] end) ==
+ tags |> Enum.reverse() |> Enum.take(16) |> Enum.map(fn tag -> Address.checksum(tag.address.hash) end)
+
+ assert response |> Enum.filter(fn x -> x["type"] == "contract" end) |> Enum.map(fn x -> x["address"] end) ==
+ contracts
+ |> Enum.reverse()
+ |> Enum.take(16)
+ |> Enum.map(fn contract -> Address.checksum(contract.address_hash) end)
+
+ assert response |> Enum.filter(fn x -> x["type"] == "token" end) |> Enum.map(fn x -> x["address"] end) ==
+ tokens
+ |> Enum.reverse()
+ |> Enum.sort_by(fn x -> x.is_verified_via_admin_panel end, :desc)
+ |> Enum.take(16)
+ |> Enum.map(fn token -> Address.checksum(token.contract_address_hash) end)
+
+ block_hashes = response |> Enum.filter(fn x -> x["type"] == "block" end) |> Enum.map(fn x -> x["block_hash"] end)
+
+ assert block_hashes == blocks |> Enum.reverse() |> Enum.map(fn block -> to_string(block.hash) end) ||
+ block_hashes == blocks |> Enum.map(fn block -> to_string(block.hash) end)
+ end
+
+ test "returns empty list and don't crash", %{conn: conn} do
+ request = get(conn, "/api/v2/search/quick?q=qwertyuioiuytrewertyuioiuytrertyuio")
+ assert [] = json_response(request, 200)
+ end
+ end
end
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs
index 12dd8c8c5f4b..6799c10396db 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/smart_contract_controller_test.exs
@@ -702,6 +702,148 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"method_id" => Base.encode16(id, case: :lower)
} in response
end
+
+ test "get correct bytes value 1", %{conn: conn} do
+ abi = [
+ %{
+ "inputs" => [],
+ "name" => "all_messages_hash",
+ "outputs" => [
+ %{
+ "internalType" => "bytes32",
+ "name" => "",
+ "type" => "bytes32"
+ }
+ ],
+ "stateMutability" => "view",
+ "type" => "function"
+ }
+ ]
+
+ id_1 =
+ abi
+ |> ABI.parse_specification()
+ |> Enum.at(0)
+ |> Map.fetch!(:method_id)
+
+ target_contract = insert(:smart_contract, abi: abi)
+ address_hash_string = to_string(target_contract.address_hash)
+
+ EthereumJSONRPC.Mox
+ |> expect(
+ :json_rpc,
+ fn [
+ %{
+ id: id,
+ method: "eth_call",
+ params: [
+ %{data: "0x1dd69d06", to: ^address_hash_string},
+ "latest"
+ ]
+ }
+ ],
+ _opts ->
+ {:ok,
+ [
+ %{
+ id: id,
+ jsonrpc: "2.0",
+ result: "0x0000000000000000000000000000000000000000000000000000000000000000"
+ }
+ ]}
+ end
+ )
+
+ request = get(conn, "/api/v2/smart-contracts/#{target_contract.address_hash}/methods-read")
+ assert response = json_response(request, 200)
+
+ assert %{
+ "inputs" => [],
+ "name" => "all_messages_hash",
+ "outputs" => [
+ %{
+ "value" => "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "type" => "bytes32"
+ }
+ ],
+ "stateMutability" => "view",
+ "type" => "function",
+ "method_id" => Base.encode16(id_1, case: :lower),
+ "names" => ["bytes32"]
+ } in response
+ end
+
+ test "get correct bytes value 2", %{conn: conn} do
+ abi = [
+ %{
+ "inputs" => [],
+ "name" => "FRAUD_STRING",
+ "outputs" => [
+ %{
+ "internalType" => "bytes",
+ "name" => "",
+ "type" => "bytes"
+ }
+ ],
+ "stateMutability" => "view",
+ "type" => "function"
+ }
+ ]
+
+ id_2 =
+ abi
+ |> ABI.parse_specification()
+ |> Enum.at(0)
+ |> Map.fetch!(:method_id)
+
+ target_contract = insert(:smart_contract, abi: abi)
+ address_hash_string = to_string(target_contract.address_hash)
+
+ EthereumJSONRPC.Mox
+ |> expect(
+ :json_rpc,
+ fn [
+ %{
+ id: id,
+ method: "eth_call",
+ params: [
+ %{data: "0x46b2eb9b", to: ^address_hash_string},
+ "latest"
+ ]
+ }
+ ],
+ _opts ->
+ {:ok,
+ [
+ %{
+ id: id,
+ jsonrpc: "2.0",
+ result:
+ "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000322d2d5468697320697320612062616420737472696e672e204e6f626f64792073617973207468697320737472696e672e2d2d0000000000000000000000000000"
+ }
+ ]}
+ end
+ )
+
+ request = get(conn, "/api/v2/smart-contracts/#{target_contract.address_hash}/methods-read")
+ assert response = json_response(request, 200)
+
+ assert %{
+ "inputs" => [],
+ "name" => "FRAUD_STRING",
+ "outputs" => [
+ %{
+ "value" =>
+ "0x2d2d5468697320697320612062616420737472696e672e204e6f626f64792073617973207468697320737472696e672e2d2d",
+ "type" => "bytes"
+ }
+ ],
+ "stateMutability" => "view",
+ "type" => "function",
+ "method_id" => Base.encode16(id_2, case: :lower),
+ "names" => ["bytes"]
+ } in response
+ end
end
describe "/smart-contracts/{address_hash}/query-read-method" do
@@ -1205,6 +1347,7 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
assert [
%{
+ "method_id" => "49ba1b49",
"type" => "function",
"stateMutability" => "nonpayable",
"outputs" => [],
@@ -1271,7 +1414,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"stateMutability" => "nonpayable",
"outputs" => [],
"name" => "disableWhitelist",
- "inputs" => [%{"type" => "bool", "name" => "disable", "internalType" => "bool"}]
+ "inputs" => [%{"type" => "bool", "name" => "disable", "internalType" => "bool"}],
+ "method_id" => "49ba1b49"
}
] == response
end
@@ -1912,7 +2056,8 @@ defmodule BlockScoutWeb.API.V2.SmartContractControllerTest do
"stateMutability" => "nonpayable",
"outputs" => [],
"name" => "disableWhitelist",
- "inputs" => [%{"type" => "bool", "name" => "disable", "internalType" => "bool"}]
+ "inputs" => [%{"type" => "bool", "name" => "disable", "internalType" => "bool"}],
+ "method_id" => "49ba1b49"
}
] == response
end
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs
index fbed9880a6ec..05b7009487c4 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/token_controller_test.exs
@@ -390,6 +390,30 @@ defmodule BlockScoutWeb.API.V2.TokenControllerTest do
check_paginated_response(response, response_2nd_page, token_balances)
end
+
+ test "check pagination with the same values", %{conn: conn} do
+ token = insert(:token)
+
+ token_balances =
+ for _ <- 0..50 do
+ insert(
+ :address_current_token_balance,
+ token_contract_address_hash: token.contract_address_hash,
+ value: 1000
+ )
+ end
+ |> Enum.sort_by(fn x -> x.address_hash end, :asc)
+
+ request = get(conn, "/api/v2/tokens/#{token.contract_address.hash}/holders")
+ assert response = json_response(request, 200)
+
+ request_2nd_page =
+ get(conn, "/api/v2/tokens/#{token.contract_address.hash}/holders", response["next_page_params"])
+
+ assert response_2nd_page = json_response(request_2nd_page, 200)
+
+ check_paginated_response(response, response_2nd_page, token_balances)
+ end
end
describe "/tokens" do
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/verification_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/verification_controller_test.exs
index 4ff1545377bd..bd471e8d771f 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/v2/verification_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v2/verification_controller_test.exs
@@ -75,7 +75,7 @@ defmodule BlockScoutWeb.API.V2.VerificationControllerTest do
request = post(conn, "/api/v2/smart-contracts/#{contract_address.hash}/verification/via/flattened-code", params)
- assert %{"message" => "Verification started"} = json_response(request, 200)
+ assert %{"message" => "Smart-contract verification started"} = json_response(request, 200)
assert_receive %Phoenix.Socket.Message{
payload: %{status: "success"},
@@ -118,7 +118,7 @@ defmodule BlockScoutWeb.API.V2.VerificationControllerTest do
request = post(conn, "/api/v2/smart-contracts/#{contract_address.hash}/verification/via/flattened-code", params)
- assert %{"message" => "Verification started"} = json_response(request, 200)
+ assert %{"message" => "Smart-contract verification started"} = json_response(request, 200)
assert_receive %Phoenix.Socket.Message{
payload: %{status: "error", errors: %{name: ["Wrong contract name, please try again."]}},
@@ -198,7 +198,7 @@ defmodule BlockScoutWeb.API.V2.VerificationControllerTest do
body
)
- assert %{"message" => "Verification started"} = json_response(request, 200)
+ assert %{"message" => "Smart-contract verification started"} = json_response(request, 200)
assert_receive %Phoenix.Socket.Message{
payload: %{status: "success"},
@@ -222,7 +222,7 @@ defmodule BlockScoutWeb.API.V2.VerificationControllerTest do
end
test "verify contract from sourcify repo", %{conn: conn} do
- address = "0x18d89C12e9463Be6343c35C9990361bA4C42AfC2"
+ address = "0xf26594F585De4EB0Ae9De865d9053FEe02ac6eF1"
_contract = insert(:address, hash: address, contract_code: "0x01")
@@ -259,7 +259,7 @@ defmodule BlockScoutWeb.API.V2.VerificationControllerTest do
body
)
- assert %{"message" => "Verification started"} = json_response(request, 200)
+ assert %{"message" => "Smart-contract verification started"} = json_response(request, 200)
assert_receive %Phoenix.Socket.Message{
payload: %{status: "success"},
@@ -329,7 +329,7 @@ defmodule BlockScoutWeb.API.V2.VerificationControllerTest do
request = post(conn, "/api/v2/smart-contracts/#{contract_address.hash}/verification/via/vyper-code", params)
- assert %{"message" => "Verification started"} = json_response(request, 200)
+ assert %{"message" => "Smart-contract verification started"} = json_response(request, 200)
assert_receive %Phoenix.Socket.Message{
payload: %{status: "success"},
diff --git a/apps/block_scout_web/test/block_scout_web/schema/query/address_test.exs b/apps/block_scout_web/test/block_scout_web/schema/query/address_test.exs
index ea1f5579f01c..f4526bc31454 100644
--- a/apps/block_scout_web/test/block_scout_web/schema/query/address_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/schema/query/address_test.exs
@@ -18,7 +18,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
variables = %{"hash" => to_string(address.hash)}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -45,7 +45,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
variables = %{"hash" => to_string(address.hash)}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -78,7 +78,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
variables = %{"hash" => to_string(address.hash)}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -110,7 +110,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
variables = %{"hash" => to_string(address.hash)}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] =~ ~s(Address not found.)
@@ -127,7 +127,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
variables = %{}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] == ~s(In argument "hash": Expected type "AddressHash!", found null.)
@@ -144,7 +144,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
variables = %{"hash" => "someInvalidHash"}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] =~ ~s(Argument "hash" has invalid value)
@@ -193,7 +193,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
"first" => 1
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -251,7 +251,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
"first" => 1
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -304,7 +304,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
"first" => 3
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
%{
"data" => %{
@@ -366,7 +366,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
"first" => 3
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
%{
"data" => %{
@@ -410,7 +410,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
"first" => 67
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error1, error2, error3]} = json_response(conn, 200)
assert error1["message"] =~ ~s(Field transactions is too complex)
@@ -465,7 +465,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
"count" => 9
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
%{
"data" => %{
@@ -525,7 +525,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
"first" => 3
}
- conn = post(conn, "/graphql", query: query1, variables: variables1)
+ conn = post(conn, "/api/v1/graphql", query: query1, variables: variables1)
%{"data" => %{"address" => %{"transactions" => page1}}} = json_response(conn, 200)
@@ -564,7 +564,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
"after" => last_cursor_page1
}
- conn = post(conn, "/graphql", query: query2, variables: variables2)
+ conn = post(conn, "/api/v1/graphql", query: query2, variables: variables2)
%{"data" => %{"address" => %{"transactions" => page2}}} = json_response(conn, 200)
@@ -583,7 +583,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
"after" => last_cursor_page2
}
- conn = post(conn, "/graphql", query: query2, variables: variables3)
+ conn = post(conn, "/api/v1/graphql", query: query2, variables: variables3)
%{"data" => %{"address" => %{"transactions" => page3}}} = json_response(conn, 200)
diff --git a/apps/block_scout_web/test/block_scout_web/schema/query/addresses_test.exs b/apps/block_scout_web/test/block_scout_web/schema/query/addresses_test.exs
index f6145a4afc1d..e3ca744f4937 100644
--- a/apps/block_scout_web/test/block_scout_web/schema/query/addresses_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/schema/query/addresses_test.exs
@@ -18,7 +18,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressesTest do
variables = %{"hashes" => to_string(address.hash)}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -47,7 +47,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressesTest do
variables = %{"hashes" => to_string(address.hash)}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -82,7 +82,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressesTest do
variables = %{"hashes" => to_string(address.hash)}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -116,7 +116,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressesTest do
variables = %{"hashes" => [to_string(address.hash)]}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] =~ ~s(Addresses not found.)
@@ -133,7 +133,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressesTest do
variables = %{}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] == ~s(In argument "hashes": Expected type "[AddressHash!]!", found null.)
@@ -150,7 +150,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressesTest do
variables = %{"hashes" => ["someInvalidHash"]}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] =~ ~s(Argument "hashes" has invalid value)
@@ -175,7 +175,7 @@ defmodule BlockScoutWeb.Schema.Query.AddressesTest do
variables = %{"hashes" => hashes}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error1, error2]} = json_response(conn, 200)
assert error1["message"] =~ ~s(Field addresses is too complex)
diff --git a/apps/block_scout_web/test/block_scout_web/schema/query/block_test.exs b/apps/block_scout_web/test/block_scout_web/schema/query/block_test.exs
index d601e3dd1005..26c612b344ce 100644
--- a/apps/block_scout_web/test/block_scout_web/schema/query/block_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/schema/query/block_test.exs
@@ -27,7 +27,7 @@ defmodule BlockScoutWeb.Schema.Query.BlockTest do
variables = %{"number" => block.number}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -63,7 +63,7 @@ defmodule BlockScoutWeb.Schema.Query.BlockTest do
variables = %{"number" => non_existent_block_number}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] =~ ~s(Block number #{non_existent_block_number} was not found)
@@ -80,7 +80,7 @@ defmodule BlockScoutWeb.Schema.Query.BlockTest do
}
"""
- conn = get(conn, "/graphql", query: query)
+ conn = get(conn, "/api/v1/graphql", query: query)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] == ~s(In argument "number": Expected type "Int!", found null.)
@@ -99,7 +99,7 @@ defmodule BlockScoutWeb.Schema.Query.BlockTest do
variables = %{"number" => "invalid"}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] =~ ~s(Argument "number" has invalid value)
diff --git a/apps/block_scout_web/test/block_scout_web/schema/query/node_test.exs b/apps/block_scout_web/test/block_scout_web/schema/query/node_test.exs
index 4638e2f1c379..75e6aacd1ac6 100644
--- a/apps/block_scout_web/test/block_scout_web/schema/query/node_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/schema/query/node_test.exs
@@ -20,7 +20,7 @@ defmodule BlockScoutWeb.Schema.Query.NodeTest do
variables = %{"id" => id}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -50,7 +50,7 @@ defmodule BlockScoutWeb.Schema.Query.NodeTest do
variables = %{"id" => id}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
%{"errors" => [error]} = json_response(conn, 200)
@@ -88,7 +88,7 @@ defmodule BlockScoutWeb.Schema.Query.NodeTest do
variables = %{"id" => id}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -132,7 +132,7 @@ defmodule BlockScoutWeb.Schema.Query.NodeTest do
variables = %{"id" => id}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
%{"errors" => [error]} = json_response(conn, 200)
@@ -163,7 +163,7 @@ defmodule BlockScoutWeb.Schema.Query.NodeTest do
variables = %{"id" => id}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -199,7 +199,7 @@ defmodule BlockScoutWeb.Schema.Query.NodeTest do
variables = %{"id" => id}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
%{"errors" => [error]} = json_response(conn, 200)
diff --git a/apps/block_scout_web/test/block_scout_web/schema/query/token_transfers_test.exs b/apps/block_scout_web/test/block_scout_web/schema/query/token_transfers_test.exs
index aef875fe3e16..ea20aa4f4ede 100644
--- a/apps/block_scout_web/test/block_scout_web/schema/query/token_transfers_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/schema/query/token_transfers_test.exs
@@ -33,7 +33,7 @@ defmodule BlockScoutWeb.Schema.Query.TokenTransfersTest do
"first" => 1
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -86,7 +86,7 @@ defmodule BlockScoutWeb.Schema.Query.TokenTransfersTest do
"first" => 10
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -121,7 +121,7 @@ defmodule BlockScoutWeb.Schema.Query.TokenTransfersTest do
response1 =
conn
- |> post("/graphql", query: query1, variables: variables1)
+ |> post("/api/v1/graphql", query: query1, variables: variables1)
|> json_response(200)
%{"errors" => [response1_error1, response1_error2]} = response1
@@ -150,7 +150,7 @@ defmodule BlockScoutWeb.Schema.Query.TokenTransfersTest do
response2 =
conn
- |> post("/graphql", query: query2, variables: variables2)
+ |> post("/api/v1/graphql", query: query2, variables: variables2)
|> json_response(200)
%{"errors" => [response2_error1, response2_error2]} = response2
@@ -212,7 +212,7 @@ defmodule BlockScoutWeb.Schema.Query.TokenTransfersTest do
[token_transfer] =
conn
- |> post("/graphql", query: query, variables: variables)
+ |> post("/api/v1/graphql", query: query, variables: variables)
|> json_response(200)
|> get_in(["data", "token_transfers", "edges"])
@@ -264,7 +264,7 @@ defmodule BlockScoutWeb.Schema.Query.TokenTransfersTest do
"first" => 1
}
- conn = post(conn, "/graphql", query: query1, variables: variables1)
+ conn = post(conn, "/api/v1/graphql", query: query1, variables: variables1)
%{"data" => %{"token_transfers" => page1}} = json_response(conn, 200)
@@ -300,7 +300,7 @@ defmodule BlockScoutWeb.Schema.Query.TokenTransfersTest do
"after" => last_cursor_page1
}
- conn = post(conn, "/graphql", query: query2, variables: variables2)
+ conn = post(conn, "/api/v1/graphql", query: query2, variables: variables2)
%{"data" => %{"token_transfers" => page2}} = json_response(conn, 200)
@@ -319,7 +319,7 @@ defmodule BlockScoutWeb.Schema.Query.TokenTransfersTest do
"after" => last_cursor_page2
}
- conn = post(conn, "/graphql", query: query2, variables: variables3)
+ conn = post(conn, "/api/v1/graphql", query: query2, variables: variables3)
%{"data" => %{"token_transfers" => page3}} = json_response(conn, 200)
diff --git a/apps/block_scout_web/test/block_scout_web/schema/query/transaction_test.exs b/apps/block_scout_web/test/block_scout_web/schema/query/transaction_test.exs
index 66b31d676c72..6212ca89a788 100644
--- a/apps/block_scout_web/test/block_scout_web/schema/query/transaction_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/schema/query/transaction_test.exs
@@ -37,7 +37,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
variables = %{"hash" => to_string(transaction.hash)}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -78,7 +78,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
variables = %{"hash" => to_string(transaction.hash)}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] == "Transaction not found."
@@ -93,7 +93,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
}
"""
- conn = get(conn, "/graphql", query: query)
+ conn = get(conn, "/api/v1/graphql", query: query)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] == ~s(In argument "hash": Expected type "FullHash!", found null.)
@@ -110,7 +110,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
variables = %{"hash" => "0x000"}
- conn = get(conn, "/graphql", query: query, variables: variables)
+ conn = get(conn, "/api/v1/graphql", query: query, variables: variables)
assert %{"errors" => [error]} = json_response(conn, 200)
assert error["message"] =~ ~s(Argument "hash" has invalid value)
@@ -180,7 +180,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
"first" => 1
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -247,7 +247,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
"first" => 1
}
- conn = post(conn, "/graphql", query: query, variables: variables)
+ conn = post(conn, "/api/v1/graphql", query: query, variables: variables)
assert json_response(conn, 200) == %{
"data" => %{
@@ -306,7 +306,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
response =
conn
- |> post("/graphql", query: query, variables: variables)
+ |> post("/api/v1/graphql", query: query, variables: variables)
|> json_response(200)
internal_transactions = get_in(response, ["data", "transaction", "internal_transactions", "edges"])
@@ -341,7 +341,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
response1 =
conn
- |> post("/graphql", query: query1, variables: variables1)
+ |> post("/api/v1/graphql", query: query1, variables: variables1)
|> json_response(200)
assert %{"errors" => [error1, error2, error3]} = response1
@@ -372,7 +372,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
response2 =
conn
- |> post("/graphql", query: query2, variables: variables2)
+ |> post("/api/v1/graphql", query: query2, variables: variables2)
|> json_response(200)
assert %{"errors" => [error1, error2, error3]} = response2
@@ -435,7 +435,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
[internal_transaction] =
conn
- |> post("/graphql", query: query, variables: variables)
+ |> post("/api/v1/graphql", query: query, variables: variables)
|> json_response(200)
|> get_in(["data", "transaction", "internal_transactions", "edges"])
@@ -479,7 +479,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
"first" => 2
}
- conn = post(conn, "/graphql", query: query1, variables: variables1)
+ conn = post(conn, "/api/v1/graphql", query: query1, variables: variables1)
%{"data" => %{"transaction" => %{"internal_transactions" => page1}}} = json_response(conn, 200)
@@ -520,7 +520,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
page2 =
conn
- |> post("/graphql", query: query2, variables: variables2)
+ |> post("/api/v1/graphql", query: query2, variables: variables2)
|> json_response(200)
|> get_in(["data", "transaction", "internal_transactions"])
@@ -541,7 +541,7 @@ defmodule BlockScoutWeb.Schema.Query.TransactionTest do
page3 =
conn
- |> post("/graphql", query: query2, variables: variables3)
+ |> post("/api/v1/graphql", query: query2, variables: variables3)
|> json_response(200)
|> get_in(["data", "transaction", "internal_transactions"])
diff --git a/apps/block_scout_web/test/block_scout_web/views/smart_contract_view_test.exs b/apps/block_scout_web/test/block_scout_web/views/smart_contract_view_test.exs
index 7ba53f18ced2..cb63435730b2 100644
--- a/apps/block_scout_web/test/block_scout_web/views/smart_contract_view_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/views/smart_contract_view_test.exs
@@ -8,47 +8,32 @@ defmodule BlockScoutWeb.SmartContractViewTest do
describe "values_with_type/1" do
test "complex data type case" do
value =
- {<<156, 209, 70, 119, 249, 170, 85, 105, 179, 187, 179, 81, 252, 214, 125, 17, 21, 170, 86, 58, 225, 98, 66,
- 118, 211, 212, 230, 127, 179, 214, 249, 38>>, 23_183_417, true,
+ {"0x9cd14677f9aa5569b3bbb351fcd67d1115aa563ae1624276d3d4e67fb3d6f926", 23_183_417, true,
[
{<<164, 118, 64, 69, 133, 31, 23, 170, 96, 182, 200, 232, 182, 32, 114, 190, 169, 83, 133, 33>>,
[
- <<15, 103, 152, 165, 96, 121, 58, 84, 195, 188, 254, 134, 169, 60, 222, 30, 115, 8, 125, 148, 76, 14, 162,
- 5, 68, 19, 125, 65, 33, 57, 104, 133>>,
- <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 61, 111, 131, 12, 226, 99, 202, 233, 135, 25, 57, 130, 25, 44,
- 217, 144, 68, 43, 83>>
- ],
- <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 178, 96, 212, 241, 78, 0, 0>>},
+ "0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885",
+ "0x000000000000000000000000bf3d6f830ce263cae987193982192cd990442b53"
+ ], "0x000000000000000000000000000000000000000000000000aab260d4f14e0000"},
{<<164, 118, 64, 69, 133, 31, 23, 170, 96, 182, 200, 232, 182, 32, 114, 190, 169, 83, 133, 33>>,
[
- <<221, 242, 82, 173, 27, 226, 200, 155, 105, 194, 176, 104, 252, 55, 141, 170, 149, 43, 167, 241, 99, 196,
- 161, 22, 40, 245, 90, 77, 245, 35, 179, 239>>,
- <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>,
- <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 61, 111, 131, 12, 226, 99, 202, 233, 135, 25, 57, 130, 25, 44,
- 217, 144, 68, 43, 83>>
- ],
- <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 178, 96, 212, 241, 78, 0, 0>>},
+ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
+ "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "0x000000000000000000000000bf3d6f830ce263cae987193982192cd990442b53"
+ ], "0x000000000000000000000000000000000000000000000000aab260d4f14e0000"},
{<<166, 139, 214, 89, 169, 22, 127, 61, 60, 1, 186, 151, 118, 161, 32, 141, 174, 143, 0, 59>>,
[
- <<47, 154, 96, 152, 212, 80, 58, 18, 119, 121, 186, 151, 95, 95, 107, 4, 248, 66, 54, 43, 24, 9, 243, 70,
- 152, 158, 154, 188, 11, 77, 237, 182>>,
- <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 61, 111, 131, 12, 226, 99, 202, 233, 135, 25, 57, 130, 25, 44,
- 217, 144, 68, 43, 83>>,
- <<0, 5, 0, 0, 36, 155, 252, 47, 60, 200, 214, 143, 107, 107, 247, 35, 14, 160, 168, 237, 133, 61, 231, 49,
- 0, 0, 0, 0, 0, 0, 2, 79>>
- ],
- <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 178, 96, 212, 241, 78, 0, 0>>},
+ "0x2f9a6098d4503a127779ba975f5f6b04f842362b1809f346989e9abc0b4dedb6",
+ "0x000000000000000000000000bf3d6f830ce263cae987193982192cd990442b53",
+ "0x00050000249bfc2f3cc8d68f6b6bf7230ea0a8ed853de731000000000000024f"
+ ], "0x000000000000000000000000000000000000000000000000aab260d4f14e0000"},
{<<254, 68, 107, 239, 29, 191, 122, 254, 36, 232, 30, 5, 188, 139, 39, 28, 27, 169, 165, 96>>,
[
- <<39, 51, 62, 219, 139, 220, 212, 10, 10, 233, 68, 251, 18, 27, 94, 45, 98, 234, 120, 38, 131, 148, 102,
- 84, 160, 245, 230, 7, 169, 8, 213, 120>>,
- <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 95, 197, 45, 138, 86, 59, 47, 24, 28, 106, 82, 125, 66, 46, 21,
- 146, 201, 236, 250>>,
- <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 139, 214, 89, 169, 22, 127, 61, 60, 1, 186, 151, 118, 161, 32,
- 141, 174, 143, 0, 59>>,
- <<0, 5, 0, 0, 36, 155, 252, 47, 60, 200, 214, 143, 107, 107, 247, 35, 14, 160, 168, 237, 133, 61, 231, 49,
- 0, 0, 0, 0, 0, 0, 2, 79>>
- ], <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1>>}
+ "0x27333edb8bdcd40a0ae944fb121b5e2d62ea782683946654a0f5e607a908d578",
+ "0x0000000000000000000000002a5fc52d8a563b2f181c6a527d422e1592c9ecfa",
+ "0x000000000000000000000000a68bd659a9167f3d3c01ba9776a1208dae8f003b",
+ "0x00050000249bfc2f3cc8d68f6b6bf7230ea0a8ed853de731000000000000024f"
+ ], "0x0000000000000000000000000000000000000000000000000000000000000001"}
]}
type = "tuple[bytes32,uint256,bool,tuple[address,bytes32[],bytes][]]"
diff --git a/apps/ethereum_jsonrpc/config/config.exs b/apps/ethereum_jsonrpc/config/config.exs
index e578ffbea78a..503b7a3828ed 100644
--- a/apps/ethereum_jsonrpc/config/config.exs
+++ b/apps/ethereum_jsonrpc/config/config.exs
@@ -6,7 +6,6 @@ config :ethereum_jsonrpc, EthereumJSONRPC.RequestCoordinator,
duration: :timer.minutes(1),
table: EthereumJSONRPC.RequestCoordinator.TimeoutCounter
],
- wait_per_timeout: :timer.seconds(20),
max_jitter: :timer.seconds(2)
# Add this configuration to add global RPC request throttling.
diff --git a/apps/ethereum_jsonrpc/config/runtime/test.exs b/apps/ethereum_jsonrpc/config/runtime/test.exs
index e2043f6c1435..081c952dfc9d 100644
--- a/apps/ethereum_jsonrpc/config/runtime/test.exs
+++ b/apps/ethereum_jsonrpc/config/runtime/test.exs
@@ -2,6 +2,8 @@ import Config
alias EthereumJSONRPC.Variant
+config :ethereum_jsonrpc, EthereumJSONRPC.RequestCoordinator, wait_per_timeout: 2
+
variant = Variant.get()
Code.require_file("#{variant}.exs", "#{__DIR__}/../../../explorer/config/test")
diff --git a/apps/ethereum_jsonrpc/config/test.exs b/apps/ethereum_jsonrpc/config/test.exs
index 0ed3de28b282..61e5f67398a0 100644
--- a/apps/ethereum_jsonrpc/config/test.exs
+++ b/apps/ethereum_jsonrpc/config/test.exs
@@ -6,7 +6,6 @@ config :ethereum_jsonrpc, EthereumJSONRPC.RequestCoordinator,
duration: :timer.seconds(6),
table: EthereumJSONRPC.RequestCoordinator.TimeoutCounter
],
- wait_per_timeout: 2,
max_jitter: 1,
# This should not actually limit anything in tests, but it is here to enable the relevant code for testing
throttle_rate_limit: 10_000,
diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex
index 221c082b0218..37573679aa51 100644
--- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex
+++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/encoder.ex
@@ -69,7 +69,7 @@ defmodule EthereumJSONRPC.Encoder do
end
end
- def decode_result(result, selectors, _leave_error_as_map) when is_list(selectors) do
+ def decode_result(%{id: id, result: _result} = result, selectors, _leave_error_as_map) when is_list(selectors) do
selectors
|> Enum.map(fn selector ->
try do
@@ -78,7 +78,7 @@ defmodule EthereumJSONRPC.Encoder do
_ -> :error
end
end)
- |> Enum.find(fn decode ->
+ |> Enum.find({id, {:error, :unable_to_decode}}, fn decode ->
case decode do
{_id, {:ok, _}} -> true
_ -> false
diff --git a/apps/ethereum_jsonrpc/mix.exs b/apps/ethereum_jsonrpc/mix.exs
index b6caba1eda1a..83c294152620 100644
--- a/apps/ethereum_jsonrpc/mix.exs
+++ b/apps/ethereum_jsonrpc/mix.exs
@@ -23,7 +23,7 @@ defmodule EthereumJsonrpc.MixProject do
dialyzer: :test
],
start_permanent: Mix.env() == :prod,
- version: "5.2.1"
+ version: "5.2.2"
]
end
diff --git a/apps/explorer/lib/explorer/account/notifier/forbidden_address.ex b/apps/explorer/lib/explorer/account/notifier/forbidden_address.ex
index 26d5e3836cbe..6022c87fcc7d 100644
--- a/apps/explorer/lib/explorer/account/notifier/forbidden_address.ex
+++ b/apps/explorer/lib/explorer/account/notifier/forbidden_address.ex
@@ -3,8 +3,10 @@ defmodule Explorer.Account.Notifier.ForbiddenAddress do
Check if address is forbidden to notify
"""
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
@blacklist [
- "0x0000000000000000000000000000000000000000",
+ burn_address_hash_string(),
"0x000000000000000000000000000000000000dEaD"
]
diff --git a/apps/explorer/lib/explorer/account/notifier/summary.ex b/apps/explorer/lib/explorer/account/notifier/summary.ex
index 6e7833c904ad..db39423bb48c 100644
--- a/apps/explorer/lib/explorer/account/notifier/summary.ex
+++ b/apps/explorer/lib/explorer/account/notifier/summary.ex
@@ -3,6 +3,8 @@ defmodule Explorer.Account.Notifier.Summary do
Compose a summary from transactions
"""
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
alias Explorer
alias Explorer.Account.Notifier.Summary
alias Explorer.{Chain, Repo}
@@ -154,10 +156,8 @@ defmodule Explorer.Account.Notifier.Summary do
def fetch_summary(_, _), do: :nothing
- @burn_address "0x0000000000000000000000000000000000000000"
-
def method(%{from_address_hash: from, to_address_hash: to}) do
- {:ok, burn_address} = format_address(@burn_address)
+ {:ok, burn_address} = format_address(burn_address_hash_string())
cond do
burn_address == from -> "mint"
diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex
index dd4200d0f0c0..5b4d96d9b940 100644
--- a/apps/explorer/lib/explorer/chain.ex
+++ b/apps/explorer/lib/explorer/chain.ex
@@ -26,6 +26,7 @@ defmodule Explorer.Chain do
]
import EthereumJSONRPC, only: [integer_to_quantity: 1, fetch_block_internal_transactions: 2]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
require Logger
@@ -55,6 +56,7 @@ defmodule Explorer.Chain do
InternalTransaction,
Log,
PendingBlockOperation,
+ Search,
SmartContract,
SmartContractAdditionalSource,
Token,
@@ -81,24 +83,15 @@ defmodule Explorer.Chain do
}
alias Explorer.Chain.Cache.Block, as: BlockCache
- alias Explorer.Chain.Cache.Helper, as: CacheHelper
alias Explorer.Chain.Cache.PendingBlockOperation, as: PendingBlockOperationCache
alias Explorer.Chain.Fetcher.{CheckBytecodeMatchingOnDemand, LookUpSmartContractSourcesOnDemand}
alias Explorer.Chain.Import.Runner
alias Explorer.Chain.InternalTransaction.{CallType, Type}
- alias Explorer.Counters.{
- AddressesCounter,
- AddressesWithBalanceCounter,
- AddressTokenTransfersCounter,
- AddressTransactionsCounter,
- AddressTransactionsGasUsageCounter
- }
-
alias Explorer.Market.MarketHistoryCache
alias Explorer.{PagingOptions, Repo}
alias Explorer.SmartContract.Helper
- alias Explorer.Tags.{AddressTag, AddressToTag}
+ alias Explorer.SmartContract.Solidity.Verifier
alias Dataloader.Ecto, as: DataloaderEcto
@@ -121,8 +114,6 @@ defmodule Explorer.Chain do
"commit" => "f14fcbc8"
}
- @max_incoming_transactions_count 10_000
-
@revert_msg_prefix_1 "Revert: "
@revert_msg_prefix_2 "revert: "
@revert_msg_prefix_3 "reverted "
@@ -132,8 +123,6 @@ defmodule Explorer.Chain do
# keccak256("Error(string)")
@revert_error_method_id "08c379a0"
- @burn_address_hash_str "0x0000000000000000000000000000000000000000"
-
@limit_showing_transactions 10_000
@default_page_size 50
@@ -178,56 +167,7 @@ defmodule Explorer.Chain do
@typep necessity_by_association_option :: {:necessity_by_association, necessity_by_association}
@typep paging_options :: {:paging_options, PagingOptions.t()}
@typep balance_by_day :: %{date: String.t(), value: Wei.t()}
- @typep api? :: {:api?, true | false}
-
- @doc """
- Gets from the cache the count of `t:Explorer.Chain.Address.t/0`'s where the `fetched_coin_balance` is > 0
- """
- @spec count_addresses_with_balance_from_cache :: non_neg_integer()
- def count_addresses_with_balance_from_cache do
- AddressesWithBalanceCounter.fetch()
- end
-
- @doc """
- Estimated count of `t:Explorer.Chain.Address.t/0`.
-
- Estimated count of addresses.
- """
- @spec address_estimated_count() :: non_neg_integer()
- def address_estimated_count(options \\ []) do
- cached_value = AddressesCounter.fetch()
-
- if is_nil(cached_value) || cached_value == 0 do
- count = CacheHelper.estimated_count_from("addresses", options)
-
- max(count, 0)
- else
- cached_value
- end
- end
-
- @doc """
- Counts the number of addresses with fetched coin balance > 0.
-
- This function should be used with caution. In larger databases, it may take a
- while to have the return back.
- """
- def count_addresses_with_balance do
- Repo.one(
- Address.count_with_fetched_coin_balance(),
- timeout: :infinity
- )
- end
-
- @doc """
- Counts the number of all addresses.
-
- This function should be used with caution. In larger databases, it may take a
- while to have the return back.
- """
- def count_addresses do
- Repo.aggregate(Address, :count, timeout: :infinity)
- end
+ @type api? :: {:api?, true | false}
@doc """
`t:Explorer.Chain.InternalTransaction/0`s from the address with the given `hash`.
@@ -326,25 +266,6 @@ defmodule Explorer.Chain do
)
end
- @doc """
- Get the total number of transactions sent by the address with the given hash according to the last block indexed.
-
- We have to increment +1 in the last nonce result because it works like an array position, the first
- nonce has the value 0. When last nonce is nil, it considers that the given address has 0 transactions.
- """
- @spec total_transactions_sent_by_address(Hash.Address.t()) :: non_neg_integer()
- def total_transactions_sent_by_address(address_hash) do
- last_nonce =
- address_hash
- |> Transaction.last_nonce_by_address_query()
- |> Repo.one(timeout: :infinity)
-
- case last_nonce do
- nil -> 0
- value -> value + 1
- end
- end
-
@doc """
Fetches the transactions related to the address with the given hash, including
transactions that only have the address in the `token_transfers` related table
@@ -1027,53 +948,6 @@ defmodule Explorer.Chain do
|> select_repo(options).exists?()
end
- @spec address_to_incoming_transaction_count(Hash.Address.t()) :: non_neg_integer()
- def address_to_incoming_transaction_count(address_hash) do
- to_address_query =
- from(
- transaction in Transaction,
- where: transaction.to_address_hash == ^address_hash
- )
-
- Repo.aggregate(to_address_query, :count, :hash, timeout: :infinity)
- end
-
- @spec address_hash_to_transaction_count(Hash.Address.t()) :: non_neg_integer()
- def address_hash_to_transaction_count(address_hash) do
- query =
- from(
- transaction in Transaction,
- where: transaction.to_address_hash == ^address_hash or transaction.from_address_hash == ^address_hash
- )
-
- Repo.aggregate(query, :count, :hash, timeout: :infinity)
- end
-
- @spec address_to_incoming_transaction_gas_usage(Hash.Address.t()) :: Decimal.t() | nil
- def address_to_incoming_transaction_gas_usage(address_hash) do
- to_address_query =
- from(
- transaction in Transaction,
- where: transaction.to_address_hash == ^address_hash
- )
-
- Repo.aggregate(to_address_query, :sum, :gas_used, timeout: :infinity)
- end
-
- @spec address_to_outcoming_transaction_gas_usage(Hash.Address.t()) :: Decimal.t() | nil
- def address_to_outcoming_transaction_gas_usage(address_hash) do
- to_address_query =
- from(
- transaction in Transaction,
- where: transaction.from_address_hash == ^address_hash
- )
-
- Repo.aggregate(to_address_query, :sum, :gas_used, timeout: :infinity)
- end
-
- @spec max_incoming_transactions_count() :: non_neg_integer()
- def max_incoming_transactions_count, do: @max_incoming_transactions_count
-
@doc """
How many blocks have confirmed `block` based on the current `max_block_number`
@@ -1472,328 +1346,6 @@ defmodule Explorer.Chain do
end
end
- defp prepare_search_term(string) do
- case Regex.scan(~r/[a-zA-Z0-9]+/, string) do
- [_ | _] = words ->
- term_final =
- words
- |> Enum.map_join(" & ", fn [word] -> word <> ":*" end)
-
- {:some, term_final}
-
- _ ->
- :none
- end
- end
-
- def search_label_query(term) do
- inner_query =
- from(tag in AddressTag,
- where: fragment("to_tsvector('english', ?) @@ to_tsquery(?)", tag.display_name, ^term),
- select: tag
- )
-
- from(att in AddressToTag,
- inner_join: at in subquery(inner_query),
- on: att.tag_id == at.id,
- left_join: smart_contract in SmartContract,
- on: att.address_hash == smart_contract.address_hash,
- select: %{
- address_hash: att.address_hash,
- tx_hash: fragment("CAST(NULL AS bytea)"),
- block_hash: fragment("CAST(NULL AS bytea)"),
- type: "label",
- name: at.display_name,
- symbol: ^nil,
- holder_count: ^nil,
- inserted_at: att.inserted_at,
- block_number: 0,
- icon_url: nil,
- token_type: nil,
- timestamp: fragment("NULL::timestamp without time zone"),
- verified: not is_nil(smart_contract),
- exchange_rate: nil,
- total_supply: nil,
- circulating_market_cap: nil,
- priority: 1
- }
- )
- end
-
- defp search_token_query(term) do
- from(token in Token,
- left_join: smart_contract in SmartContract,
- on: token.contract_address_hash == smart_contract.address_hash,
- where: fragment("to_tsvector('english', ? || ' ' || ?) @@ to_tsquery(?)", token.symbol, token.name, ^term),
- select: %{
- address_hash: token.contract_address_hash,
- tx_hash: fragment("CAST(NULL AS bytea)"),
- block_hash: fragment("CAST(NULL AS bytea)"),
- type: "token",
- name: token.name,
- symbol: token.symbol,
- holder_count: token.holder_count,
- inserted_at: token.inserted_at,
- block_number: 0,
- icon_url: token.icon_url,
- token_type: token.type,
- timestamp: fragment("NULL::timestamp without time zone"),
- verified: not is_nil(smart_contract),
- exchange_rate: token.fiat_value,
- total_supply: token.total_supply,
- circulating_market_cap: token.circulating_market_cap,
- priority: 0
- }
- )
- end
-
- defp search_contract_query(term) do
- from(smart_contract in SmartContract,
- left_join: address in Address,
- on: smart_contract.address_hash == address.hash,
- where: fragment("to_tsvector('english', ?) @@ to_tsquery(?)", smart_contract.name, ^term),
- select: %{
- address_hash: smart_contract.address_hash,
- tx_hash: fragment("CAST(NULL AS bytea)"),
- block_hash: fragment("CAST(NULL AS bytea)"),
- type: "contract",
- name: smart_contract.name,
- symbol: ^nil,
- holder_count: ^nil,
- inserted_at: address.inserted_at,
- block_number: 0,
- icon_url: nil,
- token_type: nil,
- timestamp: fragment("NULL::timestamp without time zone"),
- verified: true,
- exchange_rate: nil,
- total_supply: nil,
- circulating_market_cap: nil,
- priority: 0
- }
- )
- end
-
- defp search_address_query(term) do
- case Chain.string_to_address_hash(term) do
- {:ok, address_hash} ->
- from(address in Address,
- left_join:
- address_name in subquery(
- from(name in Address.Name,
- where: name.address_hash == ^address_hash,
- order_by: [desc: name.primary],
- limit: 1
- )
- ),
- on: address.hash == address_name.address_hash,
- where: address.hash == ^address_hash,
- select: %{
- address_hash: address.hash,
- tx_hash: fragment("CAST(NULL AS bytea)"),
- block_hash: fragment("CAST(NULL AS bytea)"),
- type: "address",
- name: address_name.name,
- symbol: ^nil,
- holder_count: ^nil,
- inserted_at: address.inserted_at,
- block_number: 0,
- icon_url: nil,
- token_type: nil,
- timestamp: fragment("NULL::timestamp without time zone"),
- verified: address.verified,
- exchange_rate: nil,
- total_supply: nil,
- circulating_market_cap: nil,
- priority: 0
- }
- )
-
- _ ->
- nil
- end
- end
-
- defp search_tx_query(term) do
- case Chain.string_to_transaction_hash(term) do
- {:ok, tx_hash} ->
- from(transaction in Transaction,
- left_join: block in Block,
- on: transaction.block_hash == block.hash,
- where: transaction.hash == ^tx_hash,
- select: %{
- address_hash: fragment("CAST(NULL AS bytea)"),
- tx_hash: transaction.hash,
- block_hash: fragment("CAST(NULL AS bytea)"),
- type: "transaction",
- name: ^nil,
- symbol: ^nil,
- holder_count: ^nil,
- inserted_at: transaction.inserted_at,
- block_number: 0,
- icon_url: nil,
- token_type: nil,
- timestamp: block.timestamp,
- verified: nil,
- exchange_rate: nil,
- total_supply: nil,
- circulating_market_cap: nil,
- priority: 0
- }
- )
-
- _ ->
- nil
- end
- end
-
- defp search_block_query(term) do
- case Chain.string_to_block_hash(term) do
- {:ok, block_hash} ->
- from(block in Block,
- where: block.hash == ^block_hash,
- select: %{
- address_hash: fragment("CAST(NULL AS bytea)"),
- tx_hash: fragment("CAST(NULL AS bytea)"),
- block_hash: block.hash,
- type: "block",
- name: ^nil,
- symbol: ^nil,
- holder_count: ^nil,
- inserted_at: block.inserted_at,
- block_number: block.number,
- icon_url: nil,
- token_type: nil,
- timestamp: block.timestamp,
- verified: nil,
- exchange_rate: nil,
- total_supply: nil,
- circulating_market_cap: nil,
- priority: 0
- }
- )
-
- _ ->
- case Integer.parse(term) do
- {block_number, ""} ->
- from(block in Block,
- where: block.number == ^block_number,
- select: %{
- address_hash: fragment("CAST(NULL AS bytea)"),
- tx_hash: fragment("CAST(NULL AS bytea)"),
- block_hash: block.hash,
- type: "block",
- name: ^nil,
- symbol: ^nil,
- holder_count: ^nil,
- inserted_at: block.inserted_at,
- block_number: block.number,
- icon_url: nil,
- token_type: nil,
- timestamp: block.timestamp,
- verified: nil,
- exchange_rate: nil,
- total_supply: nil,
- circulating_market_cap: nil,
- priority: 0
- }
- )
-
- _ ->
- nil
- end
- end
- end
-
- def joint_search(paging_options, offset, raw_string, options \\ []) do
- string = String.trim(raw_string)
-
- case prepare_search_term(string) do
- {:some, term} ->
- tokens_query = search_token_query(term)
- contracts_query = search_contract_query(term)
- labels_query = search_label_query(term)
- tx_query = search_tx_query(string)
- address_query = search_address_query(string)
- block_query = search_block_query(string)
-
- basic_query =
- from(
- tokens in subquery(tokens_query),
- union: ^contracts_query,
- union: ^labels_query
- )
-
- query =
- cond do
- address_query ->
- basic_query
- |> union(^address_query)
-
- tx_query ->
- basic_query
- |> union(^tx_query)
- |> union(^block_query)
-
- block_query ->
- basic_query
- |> union(^block_query)
-
- true ->
- basic_query
- end
-
- ordered_query =
- from(items in subquery(query),
- order_by: [
- desc: items.priority,
- desc_nulls_last: items.circulating_market_cap,
- desc_nulls_last: items.exchange_rate,
- desc_nulls_last: items.holder_count,
- asc: items.name,
- desc: items.inserted_at
- ],
- limit: ^paging_options.page_size,
- offset: ^offset
- )
-
- paginated_ordered_query =
- ordered_query
- |> page_search_results(paging_options)
-
- search_results = select_repo(options).all(paginated_ordered_query)
-
- search_results
- |> Enum.map(fn result ->
- result
- |> compose_result_checksummed_address_hash()
- |> format_timestamp()
- end)
-
- _ ->
- []
- end
- end
-
- defp compose_result_checksummed_address_hash(result) do
- if result.address_hash do
- result
- |> Map.put(:address_hash, Address.checksum(result.address_hash))
- else
- result
- end
- end
-
- # For some reasons timestamp for blocks and txs returns as ~N[2023-06-25 19:39:47.339493]
- defp format_timestamp(result) do
- if result.timestamp do
- result
- |> Map.put(:timestamp, DateTime.from_naive!(result.timestamp, "Etc/UTC"))
- else
- result
- end
- end
-
@doc """
Converts `t:Explorer.Chain.Address.t/0` `hash` to the `t:Explorer.Chain.Address.t/0` with that `hash`.
@@ -1913,7 +1465,7 @@ defmodule Explorer.Chain do
if smart_contract do
CheckBytecodeMatchingOnDemand.trigger_check(address_result, smart_contract)
LookUpSmartContractSourcesOnDemand.trigger_fetch(address_result, smart_contract)
- address_result
+ check_and_update_constructor_args(address_result)
else
LookUpSmartContractSourcesOnDemand.trigger_fetch(address_result, nil)
@@ -1936,6 +1488,36 @@ defmodule Explorer.Chain do
end
end
+ defp check_and_update_constructor_args(
+ %SmartContract{address_hash: address_hash, constructor_arguments: nil, verified_via_sourcify: true} =
+ smart_contract
+ ) do
+ if args = Verifier.parse_constructor_arguments_for_sourcify_contract(address_hash, smart_contract.abi) do
+ smart_contract |> SmartContract.changeset(%{constructor_arguments: args}) |> Repo.update()
+ %SmartContract{smart_contract | constructor_arguments: args}
+ else
+ smart_contract
+ end
+ end
+
+ defp check_and_update_constructor_args(
+ %Address{
+ hash: address_hash,
+ contract_code: deployed_bytecode,
+ smart_contract: %SmartContract{constructor_arguments: nil, verified_via_sourcify: true} = smart_contract
+ } = address
+ ) do
+ if args =
+ Verifier.parse_constructor_arguments_for_sourcify_contract(address_hash, smart_contract.abi, deployed_bytecode) do
+ smart_contract |> SmartContract.changeset(%{constructor_arguments: args}) |> Repo.update()
+ %Address{address | smart_contract: %SmartContract{smart_contract | constructor_arguments: args}}
+ else
+ address
+ end
+ end
+
+ defp check_and_update_constructor_args(other), do: other
+
defp add_twin_info_to_contract(address_result, address_verified_twin_contract, _hash)
when is_nil(address_verified_twin_contract),
do: address_result
@@ -2510,7 +2092,7 @@ defmodule Explorer.Chain do
query =
if filter && filter !== "" do
- case prepare_search_term(filter) do
+ case Search.prepare_search_term(filter) do
{:some, filter_term} ->
base_query_with_paging
|> where(fragment("to_tsvector('english', symbol || ' ' || name) @@ to_tsquery(?)", ^filter_term))
@@ -2574,56 +2156,6 @@ defmodule Explorer.Chain do
|> select_repo(options).all()
end
- def check_if_validated_blocks_at_address(address_hash, options \\ []) do
- select_repo(options).exists?(from(b in Block, where: b.miner_hash == ^address_hash))
- end
-
- def check_if_logs_at_address(address_hash, options \\ []) do
- select_repo(options).exists?(from(l in Log, where: l.address_hash == ^address_hash))
- end
-
- def check_if_internal_transactions_at_address(address_hash) do
- internal_transactions_exists_by_created_contract_address_hash =
- Repo.exists?(from(it in InternalTransaction, where: it.created_contract_address_hash == ^address_hash))
-
- internal_transactions_exists_by_from_address_hash =
- Repo.exists?(from(it in InternalTransaction, where: it.from_address_hash == ^address_hash))
-
- internal_transactions_exists_by_to_address_hash =
- Repo.exists?(from(it in InternalTransaction, where: it.to_address_hash == ^address_hash))
-
- internal_transactions_exists_by_created_contract_address_hash || internal_transactions_exists_by_from_address_hash ||
- internal_transactions_exists_by_to_address_hash
- end
-
- def check_if_token_transfers_at_address(address_hash, options \\ []) do
- token_transfers_exists_by_from_address_hash =
- select_repo(options).exists?(from(tt in TokenTransfer, where: tt.from_address_hash == ^address_hash))
-
- token_transfers_exists_by_to_address_hash =
- select_repo(options).exists?(from(tt in TokenTransfer, where: tt.to_address_hash == ^address_hash))
-
- token_transfers_exists_by_from_address_hash ||
- token_transfers_exists_by_to_address_hash
- end
-
- def check_if_tokens_at_address(address_hash, options \\ []) do
- select_repo(options).exists?(
- from(
- tb in CurrentTokenBalance,
- where: tb.address_hash == ^address_hash,
- where: tb.value > 0
- )
- )
- end
-
- @spec check_if_withdrawals_at_address(Hash.Address.t()) :: boolean()
- def check_if_withdrawals_at_address(address_hash, options \\ []) do
- address_hash
- |> Withdrawal.address_hash_to_withdrawals_unordered_query()
- |> select_repo(options).exists?()
- end
-
@doc """
Counts all of the block validations and groups by the `miner_hash`.
"""
@@ -2640,53 +2172,6 @@ defmodule Explorer.Chain do
Repo.stream_each(query, fun)
end
- @doc """
- Counts the number of `t:Explorer.Chain.Block.t/0` validated by the address with the given `hash`.
- """
- @spec address_to_validation_count(Hash.Address.t(), [api?]) :: non_neg_integer()
- def address_to_validation_count(hash, options) do
- query = from(block in Block, where: block.miner_hash == ^hash, select: fragment("COUNT(*)"))
-
- select_repo(options).one(query)
- end
-
- @spec address_to_transaction_count(Address.t()) :: non_neg_integer()
- def address_to_transaction_count(address) do
- address_hash_to_transaction_count(address.hash)
- end
-
- @spec address_to_token_transfer_count(Address.t()) :: non_neg_integer()
- def address_to_token_transfer_count(address) do
- query =
- from(
- token_transfer in TokenTransfer,
- where: token_transfer.to_address_hash == ^address.hash,
- or_where: token_transfer.from_address_hash == ^address.hash
- )
-
- Repo.aggregate(query, :count, timeout: :infinity)
- end
-
- @spec address_to_gas_usage_count(Address.t()) :: Decimal.t() | nil
- def address_to_gas_usage_count(address) do
- if contract?(address) do
- incoming_transaction_gas_usage = address_to_incoming_transaction_gas_usage(address.hash)
-
- cond do
- !incoming_transaction_gas_usage ->
- address_to_outcoming_transaction_gas_usage(address.hash)
-
- Decimal.compare(incoming_transaction_gas_usage, 0) == :eq ->
- address_to_outcoming_transaction_gas_usage(address.hash)
-
- true ->
- incoming_transaction_gas_usage
- end
- else
- address_to_outcoming_transaction_gas_usage(address.hash)
- end
- end
-
@doc """
Return the balance in usd corresponding to this token. Return nil if the fiat_value of the token is not present.
"""
@@ -2703,9 +2188,9 @@ defmodule Explorer.Chain do
Decimal.mult(tokens, fiat_value)
end
- defp contract?(%{contract_code: nil}), do: false
+ def contract?(%{contract_code: nil}), do: false
- defp contract?(%{contract_code: _}), do: true
+ def contract?(%{contract_code: _}), do: true
@doc """
Returns a stream of unfetched `t:Explorer.Chain.Address.CoinBalance.t/0`.
@@ -4310,7 +3795,7 @@ defmodule Explorer.Chain do
verified_contract_twin_additional_sources = get_contract_additional_sources(verified_contract_twin, options)
%{
- :verified_contract => verified_contract_twin,
+ :verified_contract => check_and_update_constructor_args(verified_contract_twin),
:additional_sources => verified_contract_twin_additional_sources
}
else
@@ -4772,37 +4257,6 @@ defmodule Explorer.Chain do
where(query, [transaction], transaction.index < ^index)
end
- defp page_search_results(query, %PagingOptions{key: nil}), do: query
-
- defp page_search_results(query, %PagingOptions{
- key: {_address_hash, _tx_hash, _block_hash, holder_count, name, inserted_at, item_type}
- })
- when holder_count in [nil, ""] do
- where(
- query,
- [item],
- (item.name > ^name and item.type == ^item_type) or
- (item.name == ^name and item.inserted_at < ^inserted_at and
- item.type == ^item_type) or
- item.type != ^item_type
- )
- end
-
- # credo:disable-for-next-line
- defp page_search_results(query, %PagingOptions{
- key: {_address_hash, _tx_hash, _block_hash, holder_count, name, inserted_at, item_type}
- }) do
- where(
- query,
- [item],
- (item.holder_count < ^holder_count and item.type == ^item_type) or
- (item.holder_count == ^holder_count and item.name > ^name and item.type == ^item_type) or
- (item.holder_count == ^holder_count and item.name == ^name and item.inserted_at < ^inserted_at and
- item.type == ^item_type) or
- item.type != ^item_type
- )
- end
-
def page_token_balances(query, %PagingOptions{key: nil}), do: query
def page_token_balances(query, %PagingOptions{key: {value, address_hash}}) do
@@ -4991,6 +4445,11 @@ defmodule Explorer.Chain do
) :: {:ok, accumulator}
when accumulator: term()
def stream_token_instances_with_error(initial, reducer, limited? \\ false) when is_function(reducer, 2) do
+ # likely to get valid metadata
+ high_priority = ["request error: 429", ":checkout_timeout", ":econnrefused", ":timeout"]
+ # almost impossible to get valid metadata
+ negative_priority = ["VM execution error", "no uri", "invalid json"]
+
Instance
|> where([instance], not is_nil(instance.error))
|> select([instance], %{
@@ -4998,6 +4457,7 @@ defmodule Explorer.Chain do
token_id: instance.token_id,
updated_at: instance.updated_at
})
+ |> order_by([instance], desc: instance.error in ^high_priority, asc: instance.error in ^negative_priority)
|> add_fetcher_limit(limited?)
|> Repo.stream_reduce(initial, reducer)
end
@@ -5235,6 +4695,9 @@ defmodule Explorer.Chain do
end
end
+ @doc """
+ Expects map of change params. Inserts using on_conflict: :replace_all
+ """
@spec upsert_token_instance(map()) :: {:ok, Instance.t()} | {:error, Ecto.Changeset.t()}
def upsert_token_instance(params) do
changeset = Instance.changeset(%Instance{}, params)
@@ -5245,6 +4708,14 @@ defmodule Explorer.Chain do
)
end
+ @doc """
+ Inserts list of token instances via upsert_token_instance/1.
+ """
+ @spec upsert_token_instances_list([map()]) :: list()
+ def upsert_token_instances_list(instances) do
+ Enum.map(instances, &upsert_token_instance/1)
+ end
+
@doc """
Update a new `t:Token.t/0` record.
@@ -5295,6 +4766,13 @@ defmodule Explorer.Chain do
end
end
+ @spec fetch_last_token_balances_include_unfetched(Hash.Address.t(), [api?]) :: []
+ def fetch_last_token_balances_include_unfetched(address_hash, options \\ []) do
+ address_hash
+ |> CurrentTokenBalance.last_token_balances_include_unfetched()
+ |> select_repo(options).all()
+ end
+
@spec fetch_last_token_balances(Hash.Address.t(), [api?]) :: []
def fetch_last_token_balances(address_hash, options \\ []) do
address_hash
@@ -5578,7 +5056,7 @@ defmodule Explorer.Chain do
def count_token_holders_from_token_hash(contract_address_hash) do
query =
from(ctb in CurrentTokenBalance.token_holders_query_for_count(contract_address_hash),
- select: fragment("COUNT(DISTINCT(address_hash))")
+ select: fragment("COUNT(DISTINCT(?))", ctb.address_hash)
)
Repo.one!(query, timeout: :infinity)
@@ -6326,7 +5804,7 @@ defmodule Explorer.Chain do
@spec get_token_transfer_type(TokenTransfer.t()) ::
:token_burning | :token_minting | :token_spawning | :token_transfer
def get_token_transfer_type(transfer) do
- {:ok, burn_address_hash} = Chain.string_to_address_hash(@burn_address_hash_str)
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
cond do
transfer.to_address_hash == burn_address_hash && transfer.from_address_hash !== burn_address_hash ->
@@ -6650,55 +6128,6 @@ defmodule Explorer.Chain do
NewContractsCounter.fetch(options)
end
- def address_counters(address, options \\ []) do
- validation_count_task =
- Task.async(fn ->
- address_to_validation_count(address.hash, options)
- end)
-
- Task.start_link(fn ->
- transaction_count(address)
- end)
-
- Task.start_link(fn ->
- token_transfers_count(address)
- end)
-
- Task.start_link(fn ->
- gas_usage_count(address)
- end)
-
- [
- validation_count_task
- ]
- |> Task.yield_many(:infinity)
- |> Enum.map(fn {_task, res} ->
- case res do
- {:ok, result} ->
- result
-
- {:exit, reason} ->
- raise "Query fetching address counters terminated: #{inspect(reason)}"
-
- nil ->
- raise "Query fetching address counters timed out."
- end
- end)
- |> List.to_tuple()
- end
-
- def transaction_count(address) do
- AddressTransactionsCounter.fetch(address)
- end
-
- def token_transfers_count(address) do
- AddressTokenTransfersCounter.fetch(address)
- end
-
- def gas_usage_count(address) do
- AddressTransactionsGasUsageCounter.fetch(address)
- end
-
def fetch_token_counters(address_hash, timeout) do
total_token_transfers_task =
Task.async(fn ->
@@ -6891,4 +6320,18 @@ defmodule Explorer.Chain do
}
)
end
+
+ @spec verified_contracts_top(non_neg_integer()) :: [Hash.Address.t()]
+ def verified_contracts_top(limit) do
+ query =
+ from(contract in SmartContract,
+ inner_join: address in Address,
+ on: contract.address_hash == address.hash,
+ order_by: [desc: address.transactions_count],
+ limit: ^limit,
+ select: contract.address_hash
+ )
+
+ Repo.all(query)
+ end
end
diff --git a/apps/explorer/lib/explorer/chain/address/coin_balance.ex b/apps/explorer/lib/explorer/chain/address/coin_balance.ex
index bab4a62b6291..b2e5a46f263e 100644
--- a/apps/explorer/lib/explorer/chain/address/coin_balance.ex
+++ b/apps/explorer/lib/explorer/chain/address/coin_balance.ex
@@ -155,7 +155,6 @@ defmodule Explorer.Chain.Address.CoinBalance do
balance
|> cast(params, @allowed_fields)
|> validate_required(@required_fields)
- |> foreign_key_constraint(:address_hash)
|> unique_constraint(:block_number, name: :address_coin_balances_address_hash_block_number_index)
end
end
diff --git a/apps/explorer/lib/explorer/chain/address/coin_balance_daily.ex b/apps/explorer/lib/explorer/chain/address/coin_balance_daily.ex
index 0aab03e3619a..cc881d9c471d 100644
--- a/apps/explorer/lib/explorer/chain/address/coin_balance_daily.ex
+++ b/apps/explorer/lib/explorer/chain/address/coin_balance_daily.ex
@@ -69,7 +69,6 @@ defmodule Explorer.Chain.Address.CoinBalanceDaily do
balance
|> cast(params, @allowed_fields)
|> validate_required(@required_fields)
- |> foreign_key_constraint(:address_hash)
|> unique_constraint(:day, name: :address_coin_balances_daily_address_hash_day_index)
end
end
diff --git a/apps/explorer/lib/explorer/chain/address/counters.ex b/apps/explorer/lib/explorer/chain/address/counters.ex
new file mode 100644
index 000000000000..a8d2b78b6d69
--- /dev/null
+++ b/apps/explorer/lib/explorer/chain/address/counters.ex
@@ -0,0 +1,543 @@
+defmodule Explorer.Chain.Address.Counters do
+ @moduledoc """
+ Functions related to Explorer.Chain.Address counters
+ """
+ import Ecto.Query, only: [from: 2, limit: 2, select: 3, subquery: 1, union: 2, where: 3]
+
+ import Explorer.Chain,
+ only: [select_repo: 1, wrapped_union_subquery: 1]
+
+ alias Explorer.{Chain, Repo}
+
+ alias Explorer.Counters.{
+ AddressesCounter,
+ AddressesWithBalanceCounter,
+ AddressTokenTransfersCounter,
+ AddressTransactionsCounter,
+ AddressTransactionsGasUsageCounter
+ }
+
+ alias Explorer.Chain.{
+ Address,
+ Address.CoinBalance,
+ Address.CurrentTokenBalance,
+ Block,
+ Hash,
+ InternalTransaction,
+ Log,
+ TokenTransfer,
+ Transaction,
+ Withdrawal
+ }
+
+ alias Explorer.Chain.Cache.Helper, as: CacheHelper
+
+ require Logger
+
+ defp address_hash_to_logs_query(address_hash) do
+ from(l in Log, where: l.address_hash == ^address_hash)
+ end
+
+ defp address_hash_to_validated_blocks_query(address_hash) do
+ from(b in Block, where: b.miner_hash == ^address_hash)
+ end
+
+ def check_if_validated_blocks_at_address(address_hash, options \\ []) do
+ select_repo(options).exists?(address_hash_to_validated_blocks_query(address_hash))
+ end
+
+ def check_if_logs_at_address(address_hash, options \\ []) do
+ select_repo(options).exists?(address_hash_to_logs_query(address_hash))
+ end
+
+ defp address_hash_to_coin_balances(address_hash) do
+ query =
+ from(
+ cb in CoinBalance,
+ where: cb.address_hash == ^address_hash,
+ where: not is_nil(cb.value),
+ select_merge: %{
+ delta: fragment("? - coalesce(lead(?, 1) over (order by ? desc), 0)", cb.value, cb.value, cb.block_number)
+ }
+ )
+
+ from(balance in subquery(query),
+ where: balance.delta != 0
+ )
+ end
+
+ def check_if_token_transfers_at_address(address_hash, options \\ []) do
+ select_repo(options).exists?(from(tt in TokenTransfer, where: tt.from_address_hash == ^address_hash)) ||
+ select_repo(options).exists?(from(tt in TokenTransfer, where: tt.to_address_hash == ^address_hash))
+ end
+
+ def check_if_tokens_at_address(address_hash, options \\ []) do
+ select_repo(options).exists?(address_hash_to_token_balances_query(address_hash))
+ end
+
+ @spec check_if_withdrawals_at_address(Hash.Address.t()) :: boolean()
+ def check_if_withdrawals_at_address(address_hash, options \\ []) do
+ address_hash
+ |> Withdrawal.address_hash_to_withdrawals_unordered_query()
+ |> select_repo(options).exists?()
+ end
+
+ @doc """
+ Gets from the cache the count of `t:Explorer.Chain.Address.t/0`'s where the `fetched_coin_balance` is > 0
+ """
+ @spec count_addresses_with_balance_from_cache :: non_neg_integer()
+ def count_addresses_with_balance_from_cache do
+ AddressesWithBalanceCounter.fetch()
+ end
+
+ @doc """
+ Estimated count of `t:Explorer.Chain.Address.t/0`.
+
+ Estimated count of addresses.
+ """
+ @spec address_estimated_count() :: non_neg_integer()
+ def address_estimated_count(options \\ []) do
+ cached_value = AddressesCounter.fetch()
+
+ if is_nil(cached_value) || cached_value == 0 do
+ count = CacheHelper.estimated_count_from("addresses", options)
+
+ max(count, 0)
+ else
+ cached_value
+ end
+ end
+
+ @doc """
+ Counts the number of all addresses.
+
+ This function should be used with caution. In larger databases, it may take a
+ while to have the return back.
+ """
+ def count_addresses do
+ Repo.aggregate(Address, :count, timeout: :infinity)
+ end
+
+ @doc """
+ Get the total number of transactions sent by the address with the given hash according to the last block indexed.
+
+ We have to increment +1 in the last nonce result because it works like an array position, the first
+ nonce has the value 0. When last nonce is nil, it considers that the given address has 0 transactions.
+ """
+ @spec total_transactions_sent_by_address(Hash.Address.t()) :: non_neg_integer()
+ def total_transactions_sent_by_address(address_hash) do
+ last_nonce =
+ address_hash
+ |> Transaction.last_nonce_by_address_query()
+ |> Repo.one(timeout: :infinity)
+
+ case last_nonce do
+ nil -> 0
+ value -> value + 1
+ end
+ end
+
+ def address_hash_to_transaction_count_query(address_hash) do
+ from(
+ transaction in Transaction,
+ where: transaction.to_address_hash == ^address_hash or transaction.from_address_hash == ^address_hash
+ )
+ end
+
+ @spec address_hash_to_transaction_count(Hash.Address.t()) :: non_neg_integer()
+ def address_hash_to_transaction_count(address_hash) do
+ query = address_hash_to_transaction_count_query(address_hash)
+
+ Repo.aggregate(query, :count, :hash, timeout: :infinity)
+ end
+
+ @spec address_to_transaction_count(Address.t()) :: non_neg_integer()
+ def address_to_transaction_count(address) do
+ address_hash_to_transaction_count(address.hash)
+ end
+
+ @doc """
+ Counts the number of `t:Explorer.Chain.Block.t/0` validated by the address with the given `hash`.
+ """
+ @spec address_to_validation_count(Hash.Address.t(), [Chain.api?()]) :: non_neg_integer()
+ def address_to_validation_count(hash, options) do
+ query = from(block in Block, where: block.miner_hash == ^hash, select: fragment("COUNT(*)"))
+
+ select_repo(options).one(query)
+ end
+
+ @doc """
+ Counts the number of addresses with fetched coin balance > 0.
+
+ This function should be used with caution. In larger databases, it may take a
+ while to have the return back.
+ """
+ def count_addresses_with_balance do
+ Repo.one(
+ Address.count_with_fetched_coin_balance(),
+ timeout: :infinity
+ )
+ end
+
+ @spec address_to_incoming_transaction_count(Hash.Address.t()) :: non_neg_integer()
+ def address_to_incoming_transaction_count(address_hash) do
+ to_address_query =
+ from(
+ transaction in Transaction,
+ where: transaction.to_address_hash == ^address_hash
+ )
+
+ Repo.aggregate(to_address_query, :count, :hash, timeout: :infinity)
+ end
+
+ @spec address_to_incoming_transaction_gas_usage(Hash.Address.t()) :: Decimal.t() | nil
+ def address_to_incoming_transaction_gas_usage(address_hash) do
+ to_address_query =
+ from(
+ transaction in Transaction,
+ where: transaction.to_address_hash == ^address_hash
+ )
+
+ Repo.aggregate(to_address_query, :sum, :gas_used, timeout: :infinity)
+ end
+
+ @spec address_to_outcoming_transaction_gas_usage(Hash.Address.t()) :: Decimal.t() | nil
+ def address_to_outcoming_transaction_gas_usage(address_hash) do
+ to_address_query =
+ from(
+ transaction in Transaction,
+ where: transaction.from_address_hash == ^address_hash
+ )
+
+ Repo.aggregate(to_address_query, :sum, :gas_used, timeout: :infinity)
+ end
+
+ def address_to_token_transfer_count_query(address_hash) do
+ from(
+ token_transfer in TokenTransfer,
+ where: token_transfer.to_address_hash == ^address_hash,
+ or_where: token_transfer.from_address_hash == ^address_hash
+ )
+ end
+
+ @spec address_to_token_transfer_count(Address.t()) :: non_neg_integer()
+ def address_to_token_transfer_count(address) do
+ query = address_to_token_transfer_count_query(address.hash)
+
+ Repo.aggregate(query, :count, timeout: :infinity)
+ end
+
+ def address_hash_to_token_balances_query(address_hash) do
+ from(
+ tb in CurrentTokenBalance,
+ where: tb.address_hash == ^address_hash,
+ where: tb.value > 0
+ )
+ end
+
+ @spec address_to_gas_usage_count(Address.t()) :: Decimal.t() | nil
+ def address_to_gas_usage_count(address) do
+ if Chain.contract?(address) do
+ incoming_transaction_gas_usage = address_to_incoming_transaction_gas_usage(address.hash)
+
+ cond do
+ !incoming_transaction_gas_usage ->
+ address_to_outcoming_transaction_gas_usage(address.hash)
+
+ Decimal.compare(incoming_transaction_gas_usage, 0) == :eq ->
+ address_to_outcoming_transaction_gas_usage(address.hash)
+
+ true ->
+ incoming_transaction_gas_usage
+ end
+ else
+ address_to_outcoming_transaction_gas_usage(address.hash)
+ end
+ end
+
+ def address_counters(address, options \\ []) do
+ validation_count_task =
+ Task.async(fn ->
+ address_to_validation_count(address.hash, options)
+ end)
+
+ Task.start_link(fn ->
+ transaction_count(address)
+ end)
+
+ Task.start_link(fn ->
+ token_transfers_count(address)
+ end)
+
+ Task.start_link(fn ->
+ gas_usage_count(address)
+ end)
+
+ [
+ validation_count_task
+ ]
+ |> Task.yield_many(:infinity)
+ |> Enum.map(fn {_task, res} ->
+ case res do
+ {:ok, result} ->
+ result
+
+ {:exit, reason} ->
+ raise "Query fetching address counters terminated: #{inspect(reason)}"
+
+ nil ->
+ raise "Query fetching address counters timed out."
+ end
+ end)
+ |> List.to_tuple()
+ end
+
+ def transaction_count(address) do
+ AddressTransactionsCounter.fetch(address)
+ end
+
+ def token_transfers_count(address) do
+ AddressTokenTransfersCounter.fetch(address)
+ end
+
+ def gas_usage_count(address) do
+ AddressTransactionsGasUsageCounter.fetch(address)
+ end
+
+ @counters_limit 51
+
+ def address_limited_counters(address_hash, options) do
+ start = Time.utc_now()
+
+ validations_count_task =
+ Task.async(fn ->
+ result =
+ address_hash
+ |> address_hash_to_validated_blocks_query()
+ |> limit(@counters_limit)
+ |> select_repo(options).aggregate(:count)
+
+ Logger.info(
+ "Time consumed for validations_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ transactions_from_count_task =
+ Task.async(fn ->
+ result =
+ Transaction
+ |> where([t], t.from_address_hash == ^address_hash)
+ |> Transaction.not_dropped_or_replaced_transactions()
+ |> select([t], t.hash)
+ |> limit(@counters_limit)
+ |> select_repo(options).all()
+
+ Logger.info(
+ "Time consumed for transactions_from_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ transactions_to_count_task =
+ Task.async(fn ->
+ result =
+ Transaction
+ |> where([t], t.to_address_hash == ^address_hash)
+ |> Transaction.not_dropped_or_replaced_transactions()
+ |> select([t], t.hash)
+ |> limit(@counters_limit)
+ |> select_repo(options).all()
+
+ Logger.info(
+ "Time consumed for transactions_to_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ transactions_created_contract_count_task =
+ Task.async(fn ->
+ result =
+ Transaction
+ |> where([t], t.created_contract_address_hash == ^address_hash)
+ |> Transaction.not_dropped_or_replaced_transactions()
+ |> select([t], t.hash)
+ |> limit(@counters_limit)
+ |> select_repo(options).all()
+
+ Logger.info(
+ "Time consumed for transactions_created_contract_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ token_transfer_count_task =
+ Task.async(fn ->
+ result =
+ address_hash
+ |> address_to_token_transfer_count_query()
+ |> limit(@counters_limit)
+ |> select_repo(options).aggregate(:count)
+
+ Logger.info(
+ "Time consumed for token_transfer_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ token_balances_count_task =
+ Task.async(fn ->
+ result =
+ address_hash
+ |> address_hash_to_token_balances_query()
+ |> limit(@counters_limit)
+ |> select_repo(options).aggregate(:count)
+
+ Logger.info(
+ "Time consumed for token_balances_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ logs_count_task =
+ Task.async(fn ->
+ result =
+ address_hash
+ |> address_hash_to_logs_query()
+ |> limit(@counters_limit)
+ |> select_repo(options).aggregate(:count)
+
+ Logger.info(
+ "Time consumed for logs_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ withdrawals_count_task =
+ Task.async(fn ->
+ result =
+ address_hash
+ |> Withdrawal.address_hash_to_withdrawals_unordered_query()
+ |> limit(@counters_limit)
+ |> select_repo(options).aggregate(:count)
+
+ Logger.info(
+ "Time consumed for withdrawals_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ internal_txs_count_task =
+ Task.async(fn ->
+ query_to_address_hash_wrapped =
+ InternalTransaction
+ |> InternalTransaction.where_nonpending_block()
+ |> InternalTransaction.where_address_fields_match(address_hash, :to_address_hash)
+ |> InternalTransaction.where_is_different_from_parent_transaction()
+ |> limit(@counters_limit)
+ |> wrapped_union_subquery()
+
+ query_from_address_hash_wrapped =
+ InternalTransaction
+ |> InternalTransaction.where_nonpending_block()
+ |> InternalTransaction.where_address_fields_match(address_hash, :from_address_hash)
+ |> InternalTransaction.where_is_different_from_parent_transaction()
+ |> limit(@counters_limit)
+ |> wrapped_union_subquery()
+
+ query_created_contract_address_hash_wrapped =
+ InternalTransaction
+ |> InternalTransaction.where_nonpending_block()
+ |> InternalTransaction.where_address_fields_match(address_hash, :created_contract_address_hash)
+ |> InternalTransaction.where_is_different_from_parent_transaction()
+ |> limit(@counters_limit)
+ |> wrapped_union_subquery()
+
+ result =
+ query_to_address_hash_wrapped
+ |> union(^query_from_address_hash_wrapped)
+ |> union(^query_created_contract_address_hash_wrapped)
+ |> wrapped_union_subquery()
+ |> InternalTransaction.where_is_different_from_parent_transaction()
+ |> limit(@counters_limit)
+ |> select_repo(options).aggregate(:count)
+
+ Logger.info(
+ "Time consumed for internal_txs_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ coin_balances_count_task =
+ Task.async(fn ->
+ result =
+ address_hash
+ |> address_hash_to_coin_balances()
+ |> limit(@counters_limit)
+ |> select_repo(options).aggregate(:count)
+
+ Logger.info(
+ "Time consumed for coin_balances_count_task for #{address_hash} is #{Time.diff(Time.utc_now(), start, :millisecond)}ms"
+ )
+
+ result
+ end)
+
+ {validations, txs_from, txs_to, txs_contract, token_transfers, token_balances, logs, withdrawals, internal_txs,
+ coin_balances} =
+ [
+ validations_count_task,
+ transactions_from_count_task,
+ transactions_to_count_task,
+ transactions_created_contract_count_task,
+ token_transfer_count_task,
+ token_balances_count_task,
+ logs_count_task,
+ withdrawals_count_task,
+ internal_txs_count_task,
+ coin_balances_count_task
+ ]
+ |> Task.yield_many(:timer.seconds(30))
+ |> Enum.map(fn {_task, res} ->
+ case res do
+ {:ok, result} ->
+ result
+
+ {:exit, reason} ->
+ Logger.warn(fn ->
+ [
+ "Query fetching address counters terminated: #{inspect(reason)}"
+ ]
+ end)
+
+ nil
+
+ nil ->
+ Logger.warn(fn ->
+ [
+ "Query fetching address counters timed out."
+ ]
+ end)
+
+ nil
+ end
+ end)
+ |> List.to_tuple()
+
+ {validations,
+ (sanitize_list(txs_from) ++ sanitize_list(txs_to) ++ sanitize_list(txs_contract)) |> Enum.dedup() |> Enum.count(),
+ token_transfers, token_balances, logs, withdrawals, internal_txs, coin_balances}
+ end
+
+ defp sanitize_list(nil), do: []
+ defp sanitize_list(other), do: other
+end
diff --git a/apps/explorer/lib/explorer/chain/address/current_token_balance.ex b/apps/explorer/lib/explorer/chain/address/current_token_balance.ex
index 4b4574598a72..50af3af4dd5d 100644
--- a/apps/explorer/lib/explorer/chain/address/current_token_balance.ex
+++ b/apps/explorer/lib/explorer/chain/address/current_token_balance.ex
@@ -10,6 +10,7 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do
import Ecto.Changeset
import Ecto.Query, only: [from: 2, limit: 2, offset: 2, order_by: 3, preload: 2, dynamic: 2]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
alias Explorer.{Chain, PagingOptions, Repo}
alias Explorer.Chain.{Address, Block, Hash, Token}
@@ -74,11 +75,9 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do
token_balance
|> cast(attrs, @allowed_fields)
|> validate_required(@required_fields)
- |> foreign_key_constraint(:address_hash)
- |> foreign_key_constraint(:token_contract_address_hash)
end
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
@doc """
@@ -158,6 +157,25 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do
dynamic([ctb, t], ctb.value * t.fiat_value / fragment("10 ^ ?", t.decimals))
end
+ @doc """
+ Builds an `t:Ecto.Query.t/0` to fetch the current token balances of the given address (include unfetched).
+ """
+ def last_token_balances_include_unfetched(address_hash) do
+ fiat_balance = fiat_value_query()
+
+ from(
+ ctb in __MODULE__,
+ where: ctb.address_hash == ^address_hash,
+ left_join: t in assoc(ctb, :token),
+ on: ctb.token_contract_address_hash == t.contract_address_hash,
+ preload: [token: t],
+ select: ctb,
+ select_merge: ^%{fiat_value: fiat_balance},
+ order_by: ^[desc_nulls_last: fiat_balance],
+ order_by: [desc: ctb.value, desc: ctb.id]
+ )
+ end
+
@doc """
Builds an `t:Ecto.Query.t/0` to fetch the current token balances of the given address.
"""
@@ -170,10 +188,10 @@ defmodule Explorer.Chain.Address.CurrentTokenBalance do
ctb in __MODULE__,
where: ctb.address_hash == ^address_hash,
where: ctb.value > 0,
- where: ctb.token_type == ^type,
left_join: t in assoc(ctb, :token),
on: ctb.token_contract_address_hash == t.contract_address_hash,
preload: [token: t],
+ where: t.type == ^type,
select: ctb,
select_merge: ^%{fiat_value: fiat_balance},
order_by: ^[desc_nulls_last: fiat_balance],
diff --git a/apps/explorer/lib/explorer/chain/address/token_balance.ex b/apps/explorer/lib/explorer/chain/address/token_balance.ex
index bdf7d42293b9..ab7a75b62486 100644
--- a/apps/explorer/lib/explorer/chain/address/token_balance.ex
+++ b/apps/explorer/lib/explorer/chain/address/token_balance.ex
@@ -9,6 +9,8 @@ defmodule Explorer.Chain.Address.TokenBalance do
use Explorer.Schema
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
alias Explorer.Chain
alias Explorer.Chain.Address.TokenBalance
alias Explorer.Chain.{Address, Block, Hash, Token}
@@ -65,12 +67,10 @@ defmodule Explorer.Chain.Address.TokenBalance do
token_balance
|> cast(attrs, @allowed_fields)
|> validate_required(@required_fields)
- |> foreign_key_constraint(:address_hash)
- |> foreign_key_constraint(:token_contract_address_hash)
|> unique_constraint(:block_number, name: :token_balances_address_hash_block_number_index)
end
- {:ok, burn_address_hash} = Chain.string_to_address_hash("0x0000000000000000000000000000000000000000")
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
@burn_address_hash burn_address_hash
@doc """
diff --git a/apps/explorer/lib/explorer/chain/block/reward.ex b/apps/explorer/lib/explorer/chain/block/reward.ex
index b57af7a8cfa1..fd6296a550ea 100644
--- a/apps/explorer/lib/explorer/chain/block/reward.ex
+++ b/apps/explorer/lib/explorer/chain/block/reward.ex
@@ -5,6 +5,8 @@ defmodule Explorer.Chain.Block.Reward do
use Explorer.Schema
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
alias Explorer.Application.Constants
alias Explorer.{Chain, PagingOptions}
alias Explorer.Chain.Block.Reward.AddressType
@@ -34,8 +36,6 @@ defmodule Explorer.Chain.Block.Reward do
"constant" => true
}
- @empty_address "0x0000000000000000000000000000000000000000"
-
@typedoc """
The validation reward given related to a block.
@@ -218,7 +218,7 @@ defmodule Explorer.Chain.Block.Reward do
payout_key_hash =
call_contract(keys_manager_contract_address, @get_payout_by_mining_abi, get_payout_by_mining_params)
- if payout_key_hash == @empty_address do
+ if payout_key_hash == burn_address_hash_string() do
mining_key
else
choose_key(payout_key_hash, mining_key)
@@ -248,7 +248,7 @@ defmodule Explorer.Chain.Block.Reward do
case Reader.query_contract(address, abi, params, false) do
%{^method_id => {:ok, [result]}} -> result
- _ -> @empty_address
+ _ -> burn_address_hash_string()
end
end
diff --git a/apps/explorer/lib/explorer/chain/events/publisher.ex b/apps/explorer/lib/explorer/chain/events/publisher.ex
index 92f01bfc844d..8d47f337ec64 100644
--- a/apps/explorer/lib/explorer/chain/events/publisher.ex
+++ b/apps/explorer/lib/explorer/chain/events/publisher.ex
@@ -3,7 +3,7 @@ defmodule Explorer.Chain.Events.Publisher do
Publishes events related to the Chain context.
"""
- @allowed_events ~w(addresses address_coin_balances address_token_balances blocks block_rewards internal_transactions last_block_number token_transfers transactions contract_verification_result token_total_supply changed_bytecode smart_contract_was_verified)a
+ @allowed_events ~w(addresses address_coin_balances address_token_balances address_current_token_balances blocks block_rewards internal_transactions last_block_number token_transfers transactions contract_verification_result token_total_supply changed_bytecode smart_contract_was_verified)a
def broadcast(_data, false), do: :ok
diff --git a/apps/explorer/lib/explorer/chain/events/subscriber.ex b/apps/explorer/lib/explorer/chain/events/subscriber.ex
index 9862e2e6c043..fa0203cbaf90 100644
--- a/apps/explorer/lib/explorer/chain/events/subscriber.ex
+++ b/apps/explorer/lib/explorer/chain/events/subscriber.ex
@@ -3,7 +3,7 @@ defmodule Explorer.Chain.Events.Subscriber do
Subscribes to events related to the Chain context.
"""
- @allowed_broadcast_events ~w(addresses address_coin_balances address_token_balances blocks block_rewards internal_transactions last_block_number token_transfers transactions contract_verification_result token_total_supply changed_bytecode smart_contract_was_verified)a
+ @allowed_broadcast_events ~w(addresses address_coin_balances address_token_balances address_current_token_balances blocks block_rewards internal_transactions last_block_number token_transfers transactions contract_verification_result token_total_supply changed_bytecode smart_contract_was_verified)a
@allowed_broadcast_types ~w(catchup realtime on_demand contract_verification_result)a
diff --git a/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex b/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex
index 0903c70cb876..cc51fb87376c 100644
--- a/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex
+++ b/apps/explorer/lib/explorer/chain/import/runner/address/current_token_balances.ex
@@ -273,11 +273,12 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalances do
]
],
where:
- fragment("? < EXCLUDED.block_number", current_token_balance.block_number) or
- (fragment("? = EXCLUDED.block_number", current_token_balance.block_number) and
- fragment("EXCLUDED.value IS NOT NULL") and
- (is_nil(current_token_balance.value_fetched_at) or
- fragment("? < EXCLUDED.value_fetched_at", current_token_balance.value_fetched_at)))
+ fragment("EXCLUDED.value_fetched_at IS NOT NULL") and
+ (fragment("? < EXCLUDED.block_number", current_token_balance.block_number) or
+ (fragment("? = EXCLUDED.block_number", current_token_balance.block_number) and
+ fragment("EXCLUDED.value IS NOT NULL") and
+ (is_nil(current_token_balance.value_fetched_at) or
+ fragment("? < EXCLUDED.value_fetched_at", current_token_balance.value_fetched_at))))
)
end
diff --git a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex
index a3d99c65d6a5..adc1106be2c3 100644
--- a/apps/explorer/lib/explorer/chain/import/runner/blocks.ex
+++ b/apps/explorer/lib/explorer/chain/import/runner/blocks.ex
@@ -374,6 +374,7 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
removed_consensus_block_hashes
|> Enum.map(fn {number, _hash} -> number end)
+ |> Enum.reject(&Enum.member?(consensus_block_numbers, &1))
|> MissingRangesManipulator.add_ranges_by_block_numbers()
{:ok, removed_consensus_block_hashes}
@@ -540,8 +541,10 @@ defmodule Explorer.Chain.Import.Runner.Blocks do
address_hash: new_current_token_balance.address_hash,
token_contract_address_hash: new_current_token_balance.token_contract_address_hash,
token_id: new_current_token_balance.token_id,
+ token_type: tb.token_type,
block_number: new_current_token_balance.block_number,
value: tb.value,
+ value_fetched_at: tb.value_fetched_at,
inserted_at: over(min(tb.inserted_at), :w),
updated_at: over(max(tb.updated_at), :w)
},
diff --git a/apps/explorer/lib/explorer/chain/internal_transaction.ex b/apps/explorer/lib/explorer/chain/internal_transaction.ex
index b91509a3dcf9..2d0c6ae2da02 100644
--- a/apps/explorer/lib/explorer/chain/internal_transaction.ex
+++ b/apps/explorer/lib/explorer/chain/internal_transaction.ex
@@ -444,8 +444,6 @@ defmodule Explorer.Chain.InternalTransaction do
|> validate_call_error_or_result()
|> check_constraint(:call_type, message: ~S|can't be blank when type is 'call'|, name: :call_has_call_type)
|> check_constraint(:input, message: ~S|can't be blank when type is 'call'|, name: :call_has_call_type)
- |> foreign_key_constraint(:from_address_hash)
- |> foreign_key_constraint(:to_address_hash)
|> foreign_key_constraint(:transaction_hash)
|> unique_constraint(:index)
end
@@ -460,8 +458,6 @@ defmodule Explorer.Chain.InternalTransaction do
|> validate_required(@create_required_fields)
|> validate_create_error_or_result()
|> check_constraint(:init, message: ~S|can't be blank when type is 'create'|, name: :create_has_init)
- |> foreign_key_constraint(:created_contract_address_hash)
- |> foreign_key_constraint(:from_address_hash)
|> foreign_key_constraint(:transaction_hash)
|> unique_constraint(:index)
end
@@ -474,8 +470,6 @@ defmodule Explorer.Chain.InternalTransaction do
changeset
|> cast(attrs, @selfdestruct_allowed_fields)
|> validate_required(@selfdestruct_required_fields)
- |> foreign_key_constraint(:from_address_hash)
- |> foreign_key_constraint(:to_address_hash)
|> unique_constraint(:index)
end
diff --git a/apps/explorer/lib/explorer/chain/search.ex b/apps/explorer/lib/explorer/chain/search.ex
new file mode 100644
index 000000000000..b2439545a424
--- /dev/null
+++ b/apps/explorer/lib/explorer/chain/search.ex
@@ -0,0 +1,523 @@
+defmodule Explorer.Chain.Search do
+ @moduledoc """
+ Search related functions
+ """
+ import Ecto.Query,
+ only: [
+ from: 2,
+ limit: 2,
+ order_by: 3,
+ subquery: 1,
+ union: 2,
+ where: 3
+ ]
+
+ import Explorer.Chain, only: [select_repo: 1]
+
+ alias Explorer.{Chain, PagingOptions}
+ alias Explorer.Tags.{AddressTag, AddressToTag}
+
+ alias Explorer.Chain.{
+ Address,
+ Block,
+ SmartContract,
+ Token,
+ Transaction
+ }
+
+ @doc """
+ Search function used in web interface. Returns paginated search results
+ """
+ @spec joint_search(PagingOptions.t(), integer(), binary(), [Chain.api?()] | []) :: list
+ def joint_search(paging_options, offset, raw_string, options \\ []) do
+ string = String.trim(raw_string)
+
+ case prepare_search_term(string) do
+ {:some, term} ->
+ tokens_query = search_token_query(term)
+ contracts_query = search_contract_query(term)
+ labels_query = search_label_query(term)
+ tx_query = search_tx_query(string)
+ address_query = search_address_query(string)
+ block_query = search_block_query(string)
+
+ basic_query =
+ from(
+ tokens in subquery(tokens_query),
+ union: ^contracts_query,
+ union: ^labels_query
+ )
+
+ query =
+ cond do
+ address_query ->
+ basic_query
+ |> union(^address_query)
+
+ tx_query ->
+ basic_query
+ |> union(^tx_query)
+ |> union(^block_query)
+
+ block_query ->
+ basic_query
+ |> union(^block_query)
+
+ true ->
+ basic_query
+ end
+
+ ordered_query =
+ from(items in subquery(query),
+ order_by: [
+ desc: items.priority,
+ desc_nulls_last: items.circulating_market_cap,
+ desc_nulls_last: items.exchange_rate,
+ desc_nulls_last: items.is_verified_via_admin_panel,
+ desc_nulls_last: items.holder_count,
+ asc: items.name,
+ desc: items.inserted_at
+ ],
+ limit: ^paging_options.page_size,
+ offset: ^offset
+ )
+
+ paginated_ordered_query =
+ ordered_query
+ |> page_search_results(paging_options)
+
+ search_results = select_repo(options).all(paginated_ordered_query)
+
+ search_results
+ |> Enum.map(fn result ->
+ result
+ |> compose_result_checksummed_address_hash()
+ |> format_timestamp()
+ end)
+
+ _ ->
+ []
+ end
+ end
+
+ @doc """
+ Search function. Differences from joint_search/4:
+ 1. Returns all the found categories (amount of results up to `paging_options.page_size`).
+ For example if was found 50 tokens, 50 smart-contracts, 50 labels, 1 address, 1 transaction and 2 blocks (impossible, just example) and page_size=50. Then function will return:
+ [1 address, 1 transaction, 2 blocks, 16 tokens, 15 smart-contracts, 15 labels]
+ 2. Results couldn't be paginated
+ """
+ @spec balanced_unpaginated_search(PagingOptions.t(), binary(), [Chain.api?()] | []) :: list
+ def balanced_unpaginated_search(paging_options, raw_search_query, options \\ []) do
+ search_query = String.trim(raw_search_query)
+
+ case prepare_search_term(search_query) do
+ {:some, term} ->
+ tokens_result =
+ term
+ |> search_token_query()
+ |> order_by([token],
+ desc_nulls_last: token.circulating_market_cap,
+ desc_nulls_last: token.fiat_value,
+ desc_nulls_last: token.is_verified_via_admin_panel,
+ desc_nulls_last: token.holder_count,
+ asc: token.name,
+ desc: token.inserted_at
+ )
+ |> limit(^paging_options.page_size)
+ |> select_repo(options).all()
+
+ contracts_result =
+ term
+ |> search_contract_query()
+ |> order_by([items], asc: items.name, desc: items.inserted_at)
+ |> limit(^paging_options.page_size)
+ |> select_repo(options).all()
+
+ labels_result =
+ term
+ |> search_label_query()
+ |> order_by([att, at], asc: at.display_name, desc: att.inserted_at)
+ |> limit(^paging_options.page_size)
+ |> select_repo(options).all()
+
+ tx_result =
+ if query = search_tx_query(search_query) do
+ query
+ |> select_repo(options).all()
+ else
+ []
+ end
+
+ address_result =
+ if query = search_address_query(search_query) do
+ query
+ |> select_repo(options).all()
+ else
+ []
+ end
+
+ blocks_result =
+ if query = search_block_query(search_query) do
+ query
+ |> limit(^paging_options.page_size)
+ |> select_repo(options).all()
+ else
+ []
+ end
+
+ non_empty_lists =
+ [tokens_result, contracts_result, labels_result, tx_result, address_result, blocks_result]
+ |> Enum.filter(fn list -> Enum.count(list) > 0 end)
+ |> Enum.sort_by(fn list -> Enum.count(list) end, :asc)
+
+ to_take =
+ non_empty_lists
+ |> Enum.map(fn list -> Enum.count(list) end)
+ |> take_all_categories(List.duplicate(0, Enum.count(non_empty_lists)), paging_options.page_size)
+
+ non_empty_lists
+ |> Enum.zip_reduce(to_take, [], fn x, y, acc -> acc ++ Enum.take(x, y) end)
+ |> Enum.map(fn result ->
+ result
+ |> compose_result_checksummed_address_hash()
+ |> format_timestamp()
+ end)
+
+ _ ->
+ []
+ end
+ end
+
+ def prepare_search_term(string) do
+ case Regex.scan(~r/[a-zA-Z0-9]+/, string) do
+ [_ | _] = words ->
+ term_final =
+ words
+ |> Enum.map_join(" & ", fn [word] -> word <> ":*" end)
+
+ {:some, term_final}
+
+ _ ->
+ :none
+ end
+ end
+
+ defp search_label_query(term) do
+ inner_query =
+ from(tag in AddressTag,
+ where: fragment("to_tsvector('english', ?) @@ to_tsquery(?)", tag.display_name, ^term),
+ select: tag
+ )
+
+ from(att in AddressToTag,
+ inner_join: at in subquery(inner_query),
+ on: att.tag_id == at.id,
+ left_join: smart_contract in SmartContract,
+ on: att.address_hash == smart_contract.address_hash,
+ select: %{
+ address_hash: att.address_hash,
+ tx_hash: fragment("CAST(NULL AS bytea)"),
+ block_hash: fragment("CAST(NULL AS bytea)"),
+ type: "label",
+ name: at.display_name,
+ symbol: ^nil,
+ holder_count: ^nil,
+ inserted_at: att.inserted_at,
+ block_number: 0,
+ icon_url: nil,
+ token_type: nil,
+ timestamp: fragment("NULL::timestamp without time zone"),
+ verified: not is_nil(smart_contract),
+ exchange_rate: nil,
+ total_supply: nil,
+ circulating_market_cap: nil,
+ priority: 1,
+ is_verified_via_admin_panel: nil
+ }
+ )
+ end
+
+ defp search_token_query(term) do
+ from(token in Token,
+ left_join: smart_contract in SmartContract,
+ on: token.contract_address_hash == smart_contract.address_hash,
+ where: fragment("to_tsvector('english', ? || ' ' || ?) @@ to_tsquery(?)", token.symbol, token.name, ^term),
+ select: %{
+ address_hash: token.contract_address_hash,
+ tx_hash: fragment("CAST(NULL AS bytea)"),
+ block_hash: fragment("CAST(NULL AS bytea)"),
+ type: "token",
+ name: token.name,
+ symbol: token.symbol,
+ holder_count: token.holder_count,
+ inserted_at: token.inserted_at,
+ block_number: 0,
+ icon_url: token.icon_url,
+ token_type: token.type,
+ timestamp: fragment("NULL::timestamp without time zone"),
+ verified: not is_nil(smart_contract),
+ exchange_rate: token.fiat_value,
+ total_supply: token.total_supply,
+ circulating_market_cap: token.circulating_market_cap,
+ priority: 0,
+ is_verified_via_admin_panel: token.is_verified_via_admin_panel
+ }
+ )
+ end
+
+ defp search_contract_query(term) do
+ from(smart_contract in SmartContract,
+ left_join: address in Address,
+ on: smart_contract.address_hash == address.hash,
+ where: fragment("to_tsvector('english', ?) @@ to_tsquery(?)", smart_contract.name, ^term),
+ select: %{
+ address_hash: smart_contract.address_hash,
+ tx_hash: fragment("CAST(NULL AS bytea)"),
+ block_hash: fragment("CAST(NULL AS bytea)"),
+ type: "contract",
+ name: smart_contract.name,
+ symbol: ^nil,
+ holder_count: ^nil,
+ inserted_at: address.inserted_at,
+ block_number: 0,
+ icon_url: nil,
+ token_type: nil,
+ timestamp: fragment("NULL::timestamp without time zone"),
+ verified: true,
+ exchange_rate: nil,
+ total_supply: nil,
+ circulating_market_cap: nil,
+ priority: 0,
+ is_verified_via_admin_panel: nil
+ }
+ )
+ end
+
+ defp search_address_query(term) do
+ case Chain.string_to_address_hash(term) do
+ {:ok, address_hash} ->
+ from(address in Address,
+ left_join:
+ address_name in subquery(
+ from(name in Address.Name,
+ where: name.address_hash == ^address_hash,
+ order_by: [desc: name.primary],
+ limit: 1
+ )
+ ),
+ on: address.hash == address_name.address_hash,
+ where: address.hash == ^address_hash,
+ select: %{
+ address_hash: address.hash,
+ tx_hash: fragment("CAST(NULL AS bytea)"),
+ block_hash: fragment("CAST(NULL AS bytea)"),
+ type: "address",
+ name: address_name.name,
+ symbol: ^nil,
+ holder_count: ^nil,
+ inserted_at: address.inserted_at,
+ block_number: 0,
+ icon_url: nil,
+ token_type: nil,
+ timestamp: fragment("NULL::timestamp without time zone"),
+ verified: address.verified,
+ exchange_rate: nil,
+ total_supply: nil,
+ circulating_market_cap: nil,
+ priority: 0,
+ is_verified_via_admin_panel: nil
+ }
+ )
+
+ _ ->
+ nil
+ end
+ end
+
+ defp search_tx_query(term) do
+ case Chain.string_to_transaction_hash(term) do
+ {:ok, tx_hash} ->
+ from(transaction in Transaction,
+ left_join: block in Block,
+ on: transaction.block_hash == block.hash,
+ where: transaction.hash == ^tx_hash,
+ select: %{
+ address_hash: fragment("CAST(NULL AS bytea)"),
+ tx_hash: transaction.hash,
+ block_hash: fragment("CAST(NULL AS bytea)"),
+ type: "transaction",
+ name: ^nil,
+ symbol: ^nil,
+ holder_count: ^nil,
+ inserted_at: transaction.inserted_at,
+ block_number: 0,
+ icon_url: nil,
+ token_type: nil,
+ timestamp: block.timestamp,
+ verified: nil,
+ exchange_rate: nil,
+ total_supply: nil,
+ circulating_market_cap: nil,
+ priority: 0,
+ is_verified_via_admin_panel: nil
+ }
+ )
+
+ _ ->
+ nil
+ end
+ end
+
+ defp search_block_query(term) do
+ case Chain.string_to_block_hash(term) do
+ {:ok, block_hash} ->
+ from(block in Block,
+ where: block.hash == ^block_hash,
+ select: %{
+ address_hash: fragment("CAST(NULL AS bytea)"),
+ tx_hash: fragment("CAST(NULL AS bytea)"),
+ block_hash: block.hash,
+ type: "block",
+ name: ^nil,
+ symbol: ^nil,
+ holder_count: ^nil,
+ inserted_at: block.inserted_at,
+ block_number: block.number,
+ icon_url: nil,
+ token_type: nil,
+ timestamp: block.timestamp,
+ verified: nil,
+ exchange_rate: nil,
+ total_supply: nil,
+ circulating_market_cap: nil,
+ priority: 0,
+ is_verified_via_admin_panel: nil
+ }
+ )
+
+ _ ->
+ case Integer.parse(term) do
+ {block_number, ""} ->
+ from(block in Block,
+ where: block.number == ^block_number,
+ select: %{
+ address_hash: fragment("CAST(NULL AS bytea)"),
+ tx_hash: fragment("CAST(NULL AS bytea)"),
+ block_hash: block.hash,
+ type: "block",
+ name: ^nil,
+ symbol: ^nil,
+ holder_count: ^nil,
+ inserted_at: block.inserted_at,
+ block_number: block.number,
+ icon_url: nil,
+ token_type: nil,
+ timestamp: block.timestamp,
+ verified: nil,
+ exchange_rate: nil,
+ total_supply: nil,
+ circulating_market_cap: nil,
+ priority: 0,
+ is_verified_via_admin_panel: nil
+ }
+ )
+
+ _ ->
+ nil
+ end
+ end
+ end
+
+ defp page_search_results(query, %PagingOptions{key: nil}), do: query
+
+ defp page_search_results(query, %PagingOptions{
+ key: {_address_hash, _tx_hash, _block_hash, holder_count, name, inserted_at, item_type}
+ })
+ when holder_count in [nil, ""] do
+ where(
+ query,
+ [item],
+ (item.name > ^name and item.type == ^item_type) or
+ (item.name == ^name and item.inserted_at < ^inserted_at and
+ item.type == ^item_type) or
+ item.type != ^item_type
+ )
+ end
+
+ # credo:disable-for-next-line
+ defp page_search_results(query, %PagingOptions{
+ key: {_address_hash, _tx_hash, _block_hash, holder_count, name, inserted_at, item_type}
+ }) do
+ where(
+ query,
+ [item],
+ (item.holder_count < ^holder_count and item.type == ^item_type) or
+ (item.holder_count == ^holder_count and item.name > ^name and item.type == ^item_type) or
+ (item.holder_count == ^holder_count and item.name == ^name and item.inserted_at < ^inserted_at and
+ item.type == ^item_type) or
+ item.type != ^item_type
+ )
+ end
+
+ defp take_all_categories([], taken_lengths, _remained), do: taken_lengths
+
+ defp take_all_categories(lengths, taken_lengths, remained) do
+ non_zero_count = count_non_zero(lengths)
+
+ target = if(remained < non_zero_count, do: 1, else: div(remained, non_zero_count))
+
+ {lengths_updated, %{result: taken_lengths_reversed}} =
+ Enum.map_reduce(lengths, %{result: [], sum: 0}, fn el, acc ->
+ taken =
+ cond do
+ acc[:sum] >= remained ->
+ 0
+
+ el < target ->
+ el
+
+ true ->
+ target
+ end
+
+ {el - taken, %{result: [taken | acc[:result]], sum: acc[:sum] + taken}}
+ end)
+
+ taken_lengths =
+ taken_lengths
+ |> Enum.zip_reduce(Enum.reverse(taken_lengths_reversed), [], fn x, y, acc -> [x + y | acc] end)
+ |> Enum.reverse()
+
+ remained = remained - Enum.sum(taken_lengths_reversed)
+
+ if remained > 0 and count_non_zero(lengths_updated) > 0 do
+ take_all_categories(lengths_updated, taken_lengths, remained)
+ else
+ taken_lengths
+ end
+ end
+
+ defp count_non_zero(list) do
+ Enum.reduce(list, 0, fn el, acc -> acc + if el > 0, do: 1, else: 0 end)
+ end
+
+ defp compose_result_checksummed_address_hash(result) do
+ if result.address_hash do
+ result
+ |> Map.put(:address_hash, Address.checksum(result.address_hash))
+ else
+ result
+ end
+ end
+
+ # For some reasons timestamp for blocks and txs returns as ~N[2023-06-25 19:39:47.339493]
+ defp format_timestamp(result) do
+ if result.timestamp do
+ result
+ |> Map.put(:timestamp, DateTime.from_naive!(result.timestamp, "Etc/UTC"))
+ else
+ result
+ end
+ end
+end
diff --git a/apps/explorer/lib/explorer/chain/smart_contract.ex b/apps/explorer/lib/explorer/chain/smart_contract.ex
index c1cb17f1022e..adb743d34773 100644
--- a/apps/explorer/lib/explorer/chain/smart_contract.ex
+++ b/apps/explorer/lib/explorer/chain/smart_contract.ex
@@ -21,8 +21,26 @@ defmodule Explorer.Chain.SmartContract do
alias Explorer.SmartContract.Reader
alias Timex.Duration
- @burn_address_hash_str "0x0000000000000000000000000000000000000000"
- @burn_address_hash_str_32 "0x0000000000000000000000000000000000000000000000000000000000000000"
+ # supported signatures:
+ # 5c60da1b = keccak256(implementation())
+ @implementation_signature "5c60da1b"
+ # aaf10f42 = keccak256(getImplementation())
+ @get_implementation_signature "aaf10f42"
+
+ @burn_address_hash_string "0x0000000000000000000000000000000000000000"
+ @burn_address_hash_string_32 "0x0000000000000000000000000000000000000000000000000000000000000000"
+
+ defguard is_burn_signature(term) when term in ["0x", "0x0", @burn_address_hash_string_32]
+ defguard is_burn_signature_or_nil(term) when is_burn_signature(term) or term == nil
+ defguard is_burn_signature_extended(term) when is_burn_signature(term) or term == @burn_address_hash_string
+
+ @doc """
+ Returns burn address hash
+ """
+ @spec burn_address_hash_string() :: String.t()
+ def burn_address_hash_string do
+ @burn_address_hash_string
+ end
@typep api? :: {:api?, true | false}
@@ -424,30 +442,53 @@ defmodule Explorer.Chain.SmartContract do
defp upsert_contract_methods(changeset), do: changeset
- defp error_message(:compilation), do: "There was an error compiling your contract."
- defp error_message(:compiler_version), do: "Compiler version does not match, please try again."
- defp error_message(:generated_bytecode), do: "Bytecode does not match, please try again."
- defp error_message(:constructor_arguments), do: "Constructor arguments do not match, please try again."
- defp error_message(:name), do: "Wrong contract name, please try again."
- defp error_message(:json), do: "Invalid JSON file."
+ defp error_message(:compilation), do: error_message_with_log("There was an error compiling your contract.")
+
+ defp error_message(:compiler_version),
+ do: error_message_with_log("Compiler version does not match, please try again.")
+
+ defp error_message(:generated_bytecode), do: error_message_with_log("Bytecode does not match, please try again.")
+
+ defp error_message(:constructor_arguments),
+ do: error_message_with_log("Constructor arguments do not match, please try again.")
+
+ defp error_message(:name), do: error_message_with_log("Wrong contract name, please try again.")
+ defp error_message(:json), do: error_message_with_log("Invalid JSON file.")
defp error_message(:autodetect_constructor_arguments_failed),
- do: "Autodetection of constructor arguments failed. Please try to input constructor arguments manually."
+ do:
+ error_message_with_log(
+ "Autodetection of constructor arguments failed. Please try to input constructor arguments manually."
+ )
defp error_message(:no_creation_data),
- do: "The contract creation transaction has not been indexed yet. Please wait a few minutes and try again."
+ do:
+ error_message_with_log(
+ "The contract creation transaction has not been indexed yet. Please wait a few minutes and try again."
+ )
+
+ defp error_message(:unknown_error), do: error_message_with_log("Unable to verify: unknown error.")
- defp error_message(:unknown_error), do: "Unable to verify: unknown error."
- defp error_message(:deployed_bytecode), do: "Deployed bytecode does not correspond to contract creation code."
+ defp error_message(:deployed_bytecode),
+ do: error_message_with_log("Deployed bytecode does not correspond to contract creation code.")
- defp error_message(string) when is_binary(string), do: string
+ defp error_message(:contract_source_code), do: error_message_with_log("Empty contract source code.")
+
+ defp error_message(string) when is_binary(string), do: error_message_with_log(string)
+ defp error_message(%{"message" => string} = error) when is_map(error), do: error_message_with_log(string)
defp error_message(error) do
Logger.warn(fn -> ["Unknown verifier error: ", inspect(error)] end)
"There was an error validating your contract, please try again."
end
- defp error_message(:compilation, error_message), do: "There was an error compiling your contract: #{error_message}"
+ defp error_message(:compilation, error_message),
+ do: error_message_with_log("There was an error compiling your contract: #{error_message}")
+
+ defp error_message_with_log(error_string) do
+ Logger.error("Smart-contract verification error: #{error_string}")
+ error_string
+ end
defp select_error_field(:no_creation_data), do: :address_hash
defp select_error_field(:compiler_version), do: :compiler_version
@@ -676,10 +717,10 @@ defmodule Explorer.Chain.SmartContract do
implementation_address =
cond do
implementation_method_abi ->
- get_implementation_address_hash_basic("5c60da1b", proxy_address_hash, abi)
+ get_implementation_address_hash_basic(@implementation_signature, proxy_address_hash, abi)
get_implementation_method_abi ->
- get_implementation_address_hash_basic("aaf10f42", proxy_address_hash, abi)
+ get_implementation_address_hash_basic(@get_implementation_signature, proxy_address_hash, abi)
master_copy_method_abi ->
get_implementation_address_hash_from_master_copy_pattern(proxy_address_hash)
@@ -709,7 +750,7 @@ defmodule Explorer.Chain.SmartContract do
json_rpc_named_arguments
) do
{:ok, empty_address}
- when empty_address in ["0x", "0x0", @burn_address_hash_str_32, nil] ->
+ when is_burn_signature_or_nil(empty_address) ->
fetch_beacon_proxy_implementation(proxy_address_hash, json_rpc_named_arguments)
{:ok, implementation_logic_address} ->
@@ -745,13 +786,13 @@ defmodule Explorer.Chain.SmartContract do
json_rpc_named_arguments
) do
{:ok, empty_address}
- when empty_address in ["0x", "0x0", @burn_address_hash_str_32, nil] ->
+ when is_burn_signature_or_nil(empty_address) ->
fetch_openzeppelin_proxy_implementation(proxy_address_hash, json_rpc_named_arguments)
{:ok, beacon_contract_address} ->
case beacon_contract_address
|> abi_decode_address_output()
- |> get_implementation_address_hash_basic("5c60da1b", implementation_method_abi) do
+ |> get_implementation_address_hash_basic(@implementation_signature, implementation_method_abi) do
<> ->
{:ok, implementation_address}
@@ -776,7 +817,7 @@ defmodule Explorer.Chain.SmartContract do
json_rpc_named_arguments
) do
{:ok, empty_address}
- when empty_address in ["0x", "0x0", @burn_address_hash_str_32] ->
+ when is_burn_signature(empty_address) ->
{:ok, "0x"}
{:ok, logic_contract_address} ->
@@ -788,9 +829,6 @@ defmodule Explorer.Chain.SmartContract do
end
defp get_implementation_address_hash_basic(signature, proxy_address_hash, abi) do
- # supported signatures:
- # 5c60da1b = keccak256(implementation())
- # aaf10f42 = keccak256(getImplementation())
implementation_address =
case Reader.query_contract(
proxy_address_hash,
@@ -820,7 +858,7 @@ defmodule Explorer.Chain.SmartContract do
json_rpc_named_arguments
) do
{:ok, empty_address}
- when empty_address in ["0x", "0x0", @burn_address_hash_str_32] ->
+ when is_burn_signature(empty_address) ->
{:ok, "0x"}
{:ok, logic_contract_address} ->
@@ -836,12 +874,7 @@ defmodule Explorer.Chain.SmartContract do
defp save_implementation_data(nil, _, _, _), do: {nil, nil}
defp save_implementation_data(empty_address_hash_string, proxy_address_hash, metadata_from_verified_twin, options)
- when empty_address_hash_string in [
- "0x",
- "0x0",
- @burn_address_hash_str_32,
- @burn_address_hash_str
- ] do
+ when is_burn_signature_extended(empty_address_hash_string) do
if is_nil(metadata_from_verified_twin) or !metadata_from_verified_twin do
proxy_address_hash
|> Chain.address_hash_to_smart_contract_without_twin(options)
@@ -909,7 +942,7 @@ defmodule Explorer.Chain.SmartContract do
defp abi_decode_address_output(nil), do: nil
- defp abi_decode_address_output("0x"), do: @burn_address_hash_str
+ defp abi_decode_address_output("0x"), do: burn_address_hash_string()
defp abi_decode_address_output(address) when is_binary(address) do
if String.length(address) > 42 do
diff --git a/apps/explorer/lib/explorer/chain/token.ex b/apps/explorer/lib/explorer/chain/token.ex
index b59f6ef2de5d..3b9eb2e95e18 100644
--- a/apps/explorer/lib/explorer/chain/token.ex
+++ b/apps/explorer/lib/explorer/chain/token.ex
@@ -41,6 +41,7 @@ defmodule Explorer.Chain.Token do
* `fiat_value` - The price of a token in a configured currency (USD by default).
* `circulating_market_cap` - The circulating market cap of a token in a configured currency (USD by default).
* `icon_url` - URL of the token's icon.
+ * `is_verified_via_admin_panel` - is token verified via admin panel.
"""
@type t :: %Token{
name: String.t(),
@@ -56,7 +57,8 @@ defmodule Explorer.Chain.Token do
total_supply_updated_at_block: non_neg_integer() | nil,
fiat_value: Decimal.t() | nil,
circulating_market_cap: Decimal.t() | nil,
- icon_url: String.t()
+ icon_url: String.t(),
+ is_verified_via_admin_panel: boolean()
}
@derive {Poison.Encoder,
@@ -89,6 +91,7 @@ defmodule Explorer.Chain.Token do
field(:fiat_value, :decimal)
field(:circulating_market_cap, :decimal)
field(:icon_url, :string)
+ field(:is_verified_via_admin_panel, :boolean)
belongs_to(
:contract_address,
@@ -103,14 +106,13 @@ defmodule Explorer.Chain.Token do
end
@required_attrs ~w(contract_address_hash type)a
- @optional_attrs ~w(cataloged decimals name symbol total_supply skip_metadata total_supply_updated_at_block updated_at fiat_value circulating_market_cap icon_url)a
+ @optional_attrs ~w(cataloged decimals name symbol total_supply skip_metadata total_supply_updated_at_block updated_at fiat_value circulating_market_cap icon_url is_verified_via_admin_panel)a
@doc false
def changeset(%Token{} = token, params \\ %{}) do
token
|> cast(params, @required_attrs ++ @optional_attrs)
|> validate_required(@required_attrs)
- |> foreign_key_constraint(:contract_address)
|> trim_name()
|> sanitize_token_input(:name)
|> sanitize_token_input(:symbol)
diff --git a/apps/explorer/lib/explorer/chain/token_transfer.ex b/apps/explorer/lib/explorer/chain/token_transfer.ex
index d1abd9971e74..ff17c0f768cb 100644
--- a/apps/explorer/lib/explorer/chain/token_transfer.ex
+++ b/apps/explorer/lib/explorer/chain/token_transfer.ex
@@ -136,9 +136,6 @@ defmodule Explorer.Chain.TokenTransfer do
struct
|> cast(params, @required_attrs ++ @optional_attrs)
|> validate_required(@required_attrs)
- |> foreign_key_constraint(:from_address)
- |> foreign_key_constraint(:to_address)
- |> foreign_key_constraint(:token_contract_address)
|> foreign_key_constraint(:transaction)
end
diff --git a/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex b/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex
index 5ca1520cb2b5..573ab8a988a5 100644
--- a/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex
+++ b/apps/explorer/lib/explorer/counters/address_gas_usage_counter.ex
@@ -5,8 +5,9 @@ defmodule Explorer.Counters.AddressTransactionsGasUsageCounter do
use GenServer
alias Ecto.Changeset
- alias Explorer.{Chain, Repo}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Counters.Helper
+ alias Explorer.Repo
@cache_name :address_transactions_gas_usage_counter
@last_update_key "last_update"
@@ -67,7 +68,7 @@ defmodule Explorer.Counters.AddressTransactionsGasUsageCounter do
defp update_cache(address) do
address_hash_string = to_string(address.hash)
put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", Helper.current_time())
- new_data = Chain.address_to_gas_usage_count(address)
+ new_data = Counters.address_to_gas_usage_count(address)
put_into_cache("hash_#{address_hash_string}", new_data)
put_into_db(address, new_data)
end
diff --git a/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex b/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex
index ffec588f3131..db3c82da3b48 100644
--- a/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex
+++ b/apps/explorer/lib/explorer/counters/address_token_transfers_counter.ex
@@ -5,8 +5,9 @@ defmodule Explorer.Counters.AddressTokenTransfersCounter do
use GenServer
alias Ecto.Changeset
- alias Explorer.{Chain, Repo}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Counters.Helper
+ alias Explorer.Repo
@cache_name :address_token_transfers_counter
@last_update_key "last_update"
@@ -67,7 +68,7 @@ defmodule Explorer.Counters.AddressTokenTransfersCounter do
defp update_cache(address) do
address_hash_string = to_string(address.hash)
put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", Helper.current_time())
- new_data = Chain.address_to_token_transfer_count(address)
+ new_data = Counters.address_to_token_transfer_count(address)
put_into_cache("hash_#{address_hash_string}", new_data)
put_into_db(address, new_data)
end
diff --git a/apps/explorer/lib/explorer/counters/address_transactions_counter.ex b/apps/explorer/lib/explorer/counters/address_transactions_counter.ex
index e3c6dfffb690..7b2c912335fa 100644
--- a/apps/explorer/lib/explorer/counters/address_transactions_counter.ex
+++ b/apps/explorer/lib/explorer/counters/address_transactions_counter.ex
@@ -5,8 +5,9 @@ defmodule Explorer.Counters.AddressTransactionsCounter do
use GenServer
alias Ecto.Changeset
- alias Explorer.{Chain, Repo}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Counters.Helper
+ alias Explorer.Repo
@cache_name :address_transactions_counter
@last_update_key "last_update"
@@ -67,7 +68,7 @@ defmodule Explorer.Counters.AddressTransactionsCounter do
defp update_cache(address) do
address_hash_string = to_string(address.hash)
put_into_cache("hash_#{address_hash_string}_#{@last_update_key}", Helper.current_time())
- new_data = Chain.address_to_transaction_count(address)
+ new_data = Counters.address_to_transaction_count(address)
put_into_cache("hash_#{address_hash_string}", new_data)
put_into_db(address, new_data)
end
diff --git a/apps/explorer/lib/explorer/counters/addresses_counter.ex b/apps/explorer/lib/explorer/counters/addresses_counter.ex
index 820d96a9152f..51fb845bb945 100644
--- a/apps/explorer/lib/explorer/counters/addresses_counter.ex
+++ b/apps/explorer/lib/explorer/counters/addresses_counter.ex
@@ -7,7 +7,7 @@ defmodule Explorer.Counters.AddressesCounter do
use GenServer
- alias Explorer.Chain
+ alias Explorer.Chain.Address.Counters
@table :addresses_counter
@@ -104,7 +104,7 @@ defmodule Explorer.Counters.AddressesCounter do
Consolidates the info by populating the `:ets` table with the current database information.
"""
def consolidate do
- counter = Chain.count_addresses()
+ counter = Counters.count_addresses()
insert_counter({cache_key(), counter})
end
diff --git a/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex b/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex
index 1358e52a21e8..53621029afd7 100644
--- a/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex
+++ b/apps/explorer/lib/explorer/counters/addresses_with_balance_counter.ex
@@ -7,7 +7,7 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do
use GenServer
- alias Explorer.Chain
+ alias Explorer.Chain.Address.Counters
@table :addresses_with_balance_counter
@@ -104,7 +104,7 @@ defmodule Explorer.Counters.AddressesWithBalanceCounter do
Consolidates the info by populating the `:ets` table with the current database information.
"""
def consolidate do
- counter = Chain.count_addresses_with_balance()
+ counter = Counters.count_addresses_with_balance()
insert_counter({cache_key(), counter})
end
diff --git a/apps/explorer/lib/explorer/etherscan.ex b/apps/explorer/lib/explorer/etherscan.ex
index 604bfae66fc2..4663c3c9b9db 100644
--- a/apps/explorer/lib/explorer/etherscan.ex
+++ b/apps/explorer/lib/explorer/etherscan.ex
@@ -4,6 +4,7 @@ defmodule Explorer.Etherscan do
"""
import Ecto.Query, only: [from: 2, where: 3, or_where: 3, union: 2, subquery: 1, order_by: 3]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
alias Explorer.Etherscan.Logs
alias Explorer.{Chain, Repo}
@@ -21,8 +22,6 @@ defmodule Explorer.Etherscan do
end_timestamp: nil
}
- @burn_address_hash_str "0x0000000000000000000000000000000000000000"
-
@doc """
Returns the maximum allowed page size number.
@@ -585,7 +584,7 @@ defmodule Explorer.Etherscan do
@spec fetch_sum_coin_total_supply_minus_burnt() :: non_neg_integer
def fetch_sum_coin_total_supply_minus_burnt do
- {:ok, burn_address_hash} = Chain.string_to_address_hash(@burn_address_hash_str)
+ {:ok, burn_address_hash} = Chain.string_to_address_hash(burn_address_hash_string())
query =
from(
diff --git a/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex b/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex
index 4c726ccc5106..d9ce085dee93 100644
--- a/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex
+++ b/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex
@@ -152,6 +152,17 @@ defmodule Explorer.ExchangeRates.Source.CoinGecko do
end
end
+ @doc """
+ Converts date time string into DateTime object formatted as date
+ """
+ @spec date(String.t()) :: Date.t()
+ def date(date_time_string) do
+ with {:ok, datetime, _} <- DateTime.from_iso8601(date_time_string) do
+ datetime
+ |> DateTime.to_date()
+ end
+ end
+
defp api_key do
config(:api_key) || nil
end
diff --git a/apps/explorer/lib/explorer/exchange_rates/source/coin_market_cap.ex b/apps/explorer/lib/explorer/exchange_rates/source/coin_market_cap.ex
index fb1b5472a3fb..0ef28b6c395b 100644
--- a/apps/explorer/lib/explorer/exchange_rates/source/coin_market_cap.ex
+++ b/apps/explorer/lib/explorer/exchange_rates/source/coin_market_cap.ex
@@ -18,7 +18,7 @@ defmodule Explorer.ExchangeRates.Source.CoinMarketCap do
last_updated = get_last_updated(token_properties)
current_price = get_current_price(token_properties)
- id = token_properties && token_properties["id"]
+ id = token_properties["id"]
btc_value =
if Application.get_env(:explorer, Explorer.ExchangeRates)[:fetch_btc_value],
@@ -40,8 +40,8 @@ defmodule Explorer.ExchangeRates.Source.CoinMarketCap do
id: id,
last_updated: last_updated,
market_cap_usd: to_decimal(market_cap_data_usd),
- name: token_properties && token_properties["name"],
- symbol: token_properties && String.upcase(token_properties["symbol"]),
+ name: token_properties["name"],
+ symbol: String.upcase(token_properties["symbol"]),
usd_value: current_price,
volume_24h_usd: to_decimal(total_volume_data_usd)
}
@@ -98,45 +98,54 @@ defmodule Explorer.ExchangeRates.Source.CoinMarketCap do
config(:coin_id)
end
- defp get_token_properties(market_data) do
- token_values_list =
- market_data
- |> Map.values()
-
- if Enum.count(token_values_list) > 0 do
- token_values = token_values_list |> Enum.at(0)
-
- if Enum.count(token_values) > 0 do
+ @doc """
+ Extracts token properties from CoinMarketCap coin endpoint response
+ """
+ @spec get_token_properties(map()) :: map()
+ def get_token_properties(market_data) do
+ with token_values_list <- market_data |> Map.values(),
+ true <- Enum.count(token_values_list) > 0,
+ token_values <- token_values_list |> Enum.at(0),
+ true <- Enum.count(token_values) > 0 do
+ if is_list(token_values) do
token_values |> Enum.at(0)
else
- %{}
+ token_values
end
else
- %{}
+ _ -> %{}
end
end
defp get_circulating_supply(token_properties) do
- token_properties && token_properties["circulating_supply"]
+ token_properties["circulating_supply"]
end
defp get_total_supply(token_properties) do
- token_properties && token_properties["total_supply"]
+ token_properties["total_supply"]
end
- defp get_market_cap_data_usd(token_properties) do
- token_properties && token_properties["quote"] &&
+ @doc """
+ Extracts market cap in usd from token properties, which are returned in get_token_properties/1
+ """
+ @spec get_market_cap_data_usd(map()) :: String.t()
+ def get_market_cap_data_usd(token_properties) do
+ token_properties["quote"] &&
token_properties["quote"]["USD"] &&
token_properties["quote"]["USD"]["market_cap"]
end
defp get_total_volume_data_usd(token_properties) do
- token_properties && token_properties["quote"] &&
+ token_properties["quote"] &&
token_properties["quote"]["USD"] &&
token_properties["quote"]["USD"]["volume_24h"]
end
- defp get_last_updated(token_properties) do
+ @doc """
+ Extracts last updated from token properties, which are returned in get_token_properties/1
+ """
+ @spec get_last_updated(map()) :: DateTime.t()
+ def get_last_updated(token_properties) do
last_updated_data = token_properties && token_properties["last_updated"]
if last_updated_data do
@@ -147,8 +156,12 @@ defmodule Explorer.ExchangeRates.Source.CoinMarketCap do
end
end
- defp get_current_price(token_properties) do
- if token_properties && token_properties["quote"] && token_properties["quote"]["USD"] &&
+ @doc """
+ Extracts current price from token properties, which are returned in get_token_properties/1
+ """
+ @spec get_current_price(map()) :: String.t() | non_neg_integer()
+ def get_current_price(token_properties) do
+ if token_properties["quote"] && token_properties["quote"]["USD"] &&
token_properties["quote"]["USD"]["price"] do
to_decimal(token_properties["quote"]["USD"]["price"])
else
diff --git a/apps/explorer/lib/explorer/market/history/cataloger.ex b/apps/explorer/lib/explorer/market/history/cataloger.ex
index 0672412d3311..a6bb33604bdd 100644
--- a/apps/explorer/lib/explorer/market/history/cataloger.ex
+++ b/apps/explorer/lib/explorer/market/history/cataloger.ex
@@ -8,26 +8,15 @@ defmodule Explorer.Market.History.Cataloger do
source will follow exponential backoff `100ms * 2^(n+1)` where `n` is the
number of failed requests.
- ## Configuration
-
- The following example shows the configurable values in a sample config.
-
- config :explorer, Explorer.Market.History.Cataloger,
- # fetch interval in milliseconds
- history_fetch_interval: :timer.minutes(60),
- # Base backoff in milliseconds for failed requests to history API
- base_backoff: 100
-
"""
use GenServer
require Logger
+ alias Explorer.History.Process, as: HistoryProcess
alias Explorer.Market
- @typep milliseconds :: non_neg_integer()
-
@price_failed_attempts 10
@market_cap_failed_attempts 3
@@ -108,6 +97,16 @@ defmodule Explorer.Market.History.Cataloger do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
+ @spec config_or_default(atom(), term(), term()) :: term()
+ defp config_or_default(key, module, default) do
+ Application.get_env(:explorer, module)[key] || default
+ end
+
+ @spec config_or_default(atom(), term()) :: term()
+ defp config_or_default(key, default) do
+ Application.get_env(:explorer, __MODULE__)[key] || default
+ end
+
defp market_cap_history(records, state) do
Market.bulk_insert_history(records)
@@ -118,30 +117,24 @@ defmodule Explorer.Market.History.Cataloger do
{:noreply, state}
end
- @spec base_backoff :: milliseconds()
- defp base_backoff do
- config_or_default(:base_backoff, 100)
- end
-
- @spec config_or_default(atom(), term()) :: term()
- defp config_or_default(key, default) do
- Application.get_env(:explorer, __MODULE__, [])[key] || default
- end
-
@spec source_price() :: module()
defp source_price do
- config_or_default(:source, Explorer.Market.History.Source.Price.CryptoCompare)
+ config_or_default(:price_source, Explorer.ExchangeRates.Source, Explorer.Market.History.Source.Price.CryptoCompare)
end
@spec source_market_cap() :: module()
defp source_market_cap do
- config_or_default(:source_market_cap, Explorer.Market.History.Source.MarketCap.CoinGecko)
+ config_or_default(
+ :market_cap_source,
+ Explorer.ExchangeRates.Source,
+ Explorer.Market.History.Source.MarketCap.CoinGecko
+ )
end
@spec fetch_price_history(non_neg_integer(), non_neg_integer()) :: Task.t()
defp fetch_price_history(day_count, failed_attempts \\ 0) do
Task.Supervisor.async_nolink(Explorer.MarketTaskSupervisor, fn ->
- Process.sleep(delay(failed_attempts))
+ Process.sleep(HistoryProcess.delay(failed_attempts))
if failed_attempts < @price_failed_attempts do
{:price_history, {day_count, failed_attempts, source_price().fetch_price_history(day_count)}}
@@ -154,7 +147,7 @@ defmodule Explorer.Market.History.Cataloger do
@spec fetch_market_cap_history(non_neg_integer()) :: Task.t()
defp fetch_market_cap_history(failed_attempts \\ 0) do
Task.Supervisor.async_nolink(Explorer.MarketTaskSupervisor, fn ->
- Process.sleep(delay(failed_attempts))
+ Process.sleep(HistoryProcess.delay(failed_attempts))
if failed_attempts < @market_cap_failed_attempts do
{:market_cap_history, {failed_attempts, source_market_cap().fetch_market_cap()}}
@@ -186,14 +179,4 @@ defmodule Explorer.Market.History.Cataloger do
price_records
end
end
-
- @spec delay(non_neg_integer()) :: milliseconds()
- defp delay(0), do: 0
- defp delay(1), do: base_backoff()
-
- defp delay(failed_attempts) do
- # Simulates 2^n
- multiplier = Enum.reduce(2..failed_attempts, 1, fn _, acc -> 2 * acc end)
- multiplier * base_backoff()
- end
end
diff --git a/apps/explorer/lib/explorer/market/history/source/market_cap/coin_gecko.ex b/apps/explorer/lib/explorer/market/history/source/market_cap/coin_gecko.ex
index 9875f0d0a663..fee23a9b9cd3 100644
--- a/apps/explorer/lib/explorer/market/history/source/market_cap/coin_gecko.ex
+++ b/apps/explorer/lib/explorer/market/history/source/market_cap/coin_gecko.ex
@@ -37,14 +37,6 @@ defmodule Explorer.Market.History.Source.MarketCap.CoinGecko do
end
end
- @spec date(String.t()) :: Date.t()
- defp date(date_time_string) do
- with {:ok, datetime, _} <- DateTime.from_iso8601(date_time_string) do
- datetime
- |> DateTime.to_date()
- end
- end
-
@spec format_data(term()) :: SourceMarketCap.record() | nil
defp format_data(nil), do: nil
@@ -54,7 +46,7 @@ defmodule Explorer.Market.History.Source.MarketCap.CoinGecko do
%{
market_cap: Decimal.new(to_string(market_cap["usd"])),
- date: date(data["last_updated"])
+ date: ExchangeRatesSourceCoinGecko.date(data["last_updated"])
}
end
end
diff --git a/apps/explorer/lib/explorer/market/history/source/market_cap/coin_market_cap.ex b/apps/explorer/lib/explorer/market/history/source/market_cap/coin_market_cap.ex
new file mode 100644
index 000000000000..9a95ed1e73dd
--- /dev/null
+++ b/apps/explorer/lib/explorer/market/history/source/market_cap/coin_market_cap.ex
@@ -0,0 +1,54 @@
+defmodule Explorer.Market.History.Source.MarketCap.CoinMarketCap do
+ @moduledoc """
+ Adapter for fetching current market from CoinMarketCap.
+ """
+
+ alias Explorer.ExchangeRates.Source
+ alias Explorer.ExchangeRates.Source.CoinMarketCap, as: ExchangeRatesSourceCoinMarketCap
+ alias Explorer.Market.History.Source.MarketCap, as: SourceMarketCap
+
+ import Source, only: [to_decimal: 1]
+
+ @behaviour SourceMarketCap
+
+ @impl SourceMarketCap
+ def fetch_market_cap do
+ url = ExchangeRatesSourceCoinMarketCap.source_url()
+
+ if url do
+ case Source.http_request(url, ExchangeRatesSourceCoinMarketCap.headers()) do
+ {:ok, data} ->
+ result =
+ data
+ |> format_data()
+
+ {:ok, result}
+
+ _ ->
+ :error
+ end
+ else
+ :error
+ end
+ end
+
+ @spec format_data(term()) :: SourceMarketCap.record() | nil
+ defp format_data(nil), do: nil
+
+ defp format_data(%{"data" => _} = json_data) do
+ market_data = json_data["data"]
+ token_properties = ExchangeRatesSourceCoinMarketCap.get_token_properties(market_data)
+
+ last_updated =
+ token_properties
+ |> ExchangeRatesSourceCoinMarketCap.get_last_updated()
+ |> DateTime.to_date()
+
+ market_cap_data_usd = ExchangeRatesSourceCoinMarketCap.get_market_cap_data_usd(token_properties)
+
+ %{
+ market_cap: to_decimal(market_cap_data_usd),
+ date: last_updated
+ }
+ end
+end
diff --git a/apps/explorer/lib/explorer/market/history/source/price/coin_gecko.ex b/apps/explorer/lib/explorer/market/history/source/price/coin_gecko.ex
new file mode 100644
index 000000000000..e4cf9dfa15a3
--- /dev/null
+++ b/apps/explorer/lib/explorer/market/history/source/price/coin_gecko.ex
@@ -0,0 +1,59 @@
+defmodule Explorer.Market.History.Source.Price.CoinGecko do
+ @moduledoc """
+ Adapter for fetching current market from CoinGecko.
+ """
+
+ alias Explorer.ExchangeRates.Source
+ alias Explorer.ExchangeRates.Source.CoinGecko, as: ExchangeRatesSourceCoinGecko
+ alias Explorer.Market.History.Source.Price, as: SourcePrice
+
+ @behaviour SourcePrice
+
+ @impl SourcePrice
+ def fetch_price_history(_previous_days \\ nil) do
+ url = ExchangeRatesSourceCoinGecko.source_url()
+
+ if url do
+ case Source.http_request(url, ExchangeRatesSourceCoinGecko.headers()) do
+ {:ok, data} ->
+ result =
+ data
+ |> format_data()
+
+ {:ok, result}
+
+ _ ->
+ :error
+ end
+ else
+ :error
+ end
+ end
+
+ @spec format_data(term()) :: SourcePrice.record() | nil
+ defp format_data(nil), do: nil
+
+ defp format_data(data) do
+ market_data = data["market_data"]
+ current_price = market_data["current_price"]
+ current_price_usd = Decimal.new(to_string(current_price["usd"]))
+ price_change_percentage_24h_in_currency = market_data["price_change_percentage_24h_in_currency"]
+
+ delta_perc = Decimal.new(to_string(price_change_percentage_24h_in_currency["usd"]))
+
+ delta =
+ current_price_usd
+ |> Decimal.mult(delta_perc)
+ |> Decimal.div(100)
+
+ opening_price = Decimal.add(current_price_usd, delta)
+
+ [
+ %{
+ closing_price: current_price_usd,
+ date: ExchangeRatesSourceCoinGecko.date(data["last_updated"]),
+ opening_price: opening_price
+ }
+ ]
+ end
+end
diff --git a/apps/explorer/lib/explorer/market/history/source/price/coin_market_cap.ex b/apps/explorer/lib/explorer/market/history/source/price/coin_market_cap.ex
new file mode 100644
index 000000000000..0a8c4bf28dae
--- /dev/null
+++ b/apps/explorer/lib/explorer/market/history/source/price/coin_market_cap.ex
@@ -0,0 +1,55 @@
+defmodule Explorer.Market.History.Source.Price.CoinMarketCap do
+ @moduledoc """
+ Adapter for fetching current market from CoinMarketCap.
+ """
+
+ alias Explorer.ExchangeRates.Source
+ alias Explorer.ExchangeRates.Source.CoinMarketCap, as: ExchangeRatesSourceCoinMarketCap
+ alias Explorer.Market.History.Source.Price, as: SourcePrice
+
+ @behaviour SourcePrice
+
+ @impl SourcePrice
+ def fetch_price_history(_previous_days \\ nil) do
+ url = ExchangeRatesSourceCoinMarketCap.source_url()
+
+ if url do
+ case Source.http_request(url, ExchangeRatesSourceCoinMarketCap.headers()) do
+ {:ok, data} ->
+ result =
+ data
+ |> format_data()
+
+ {:ok, result}
+
+ _ ->
+ :error
+ end
+ else
+ :error
+ end
+ end
+
+ @spec format_data(term()) :: SourcePrice.record() | nil
+ defp format_data(nil), do: nil
+
+ defp format_data(%{"data" => _} = json_data) do
+ market_data = json_data["data"]
+ token_properties = ExchangeRatesSourceCoinMarketCap.get_token_properties(market_data)
+
+ last_updated =
+ token_properties
+ |> ExchangeRatesSourceCoinMarketCap.get_last_updated()
+ |> DateTime.to_date()
+
+ current_price_usd = ExchangeRatesSourceCoinMarketCap.get_current_price(token_properties)
+
+ [
+ %{
+ closing_price: current_price_usd,
+ date: last_updated,
+ opening_price: current_price_usd
+ }
+ ]
+ end
+end
diff --git a/apps/explorer/lib/explorer/smart_contract/reader.ex b/apps/explorer/lib/explorer/smart_contract/reader.ex
index 4fa3e8dadf86..19b8a86af152 100644
--- a/apps/explorer/lib/explorer/smart_contract/reader.ex
+++ b/apps/explorer/lib/explorer/smart_contract/reader.ex
@@ -754,6 +754,27 @@ defmodule Explorer.SmartContract.Reader do
Map.put_new(output, "value", Encoder.unescape(value))
end
+ defp new_value(%{"type" => "tuple" <> _types = type} = output, values, index) do
+ value = Enum.at(values, index)
+
+ result =
+ if String.ends_with?(type, "[]") do
+ value
+ |> Enum.map(fn tuple -> new_value(%{"type" => String.slice(type, 0..-3)}, [tuple], 0) end)
+ |> flat_arrays_map()
+ else
+ value
+ |> zip_tuple_values_with_types(type)
+ |> Enum.map(fn {type, part_value} ->
+ new_value(%{"type" => type}, [part_value], 0)
+ end)
+ |> flat_arrays_map()
+ |> List.to_tuple()
+ end
+
+ Map.put_new(output, "value", result)
+ end
+
defp new_value(output, [value], _index) do
Map.put_new(output, "value", value)
end
@@ -762,6 +783,68 @@ defmodule Explorer.SmartContract.Reader do
Map.put_new(output, "value", Enum.at(values, index))
end
+ defp flat_arrays_map(%{"value" => value}) do
+ flat_arrays_map(value)
+ end
+
+ defp flat_arrays_map(value) when is_list(value) do
+ Enum.map(value, &flat_arrays_map/1)
+ end
+
+ defp flat_arrays_map(value) when is_tuple(value) do
+ value
+ |> Tuple.to_list()
+ |> flat_arrays_map()
+ |> List.to_tuple()
+ end
+
+ defp flat_arrays_map(value) do
+ value
+ end
+
+ @spec zip_tuple_values_with_types(tuple, binary) :: [{binary, any}]
+ def zip_tuple_values_with_types(value, type) do
+ types_string =
+ type
+ |> String.slice(6..-2)
+
+ types =
+ if String.trim(types_string) == "" do
+ []
+ else
+ types_string
+ |> String.graphemes()
+ end
+
+ tuple_types =
+ types
+ |> Enum.reduce(
+ {[""], 0},
+ fn
+ ",", {types_acc, 0} ->
+ {["" | types_acc], 0}
+
+ char, {[acc | types_acc], bracket_stack} ->
+ new_bracket_stack =
+ case char do
+ "[" -> bracket_stack + 1
+ "]" -> bracket_stack - 1
+ _ -> bracket_stack
+ end
+
+ {[acc <> char | types_acc], new_bracket_stack}
+ end
+ )
+ |> elem(0)
+ |> Enum.reverse()
+
+ values_list =
+ value
+ |> Tuple.to_list()
+
+ Enum.zip(tuple_types, values_list)
+ end
+
@spec bytes_to_string(<<_::_*8>>) :: String.t()
defp bytes_to_string(value) do
if value do
diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex
index 96455e7c327c..045766198150 100644
--- a/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex
+++ b/apps/explorer/lib/explorer/smart_contract/solidity/publisher.ex
@@ -3,6 +3,8 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
Module responsible to control the contract verification.
"""
+ require Logger
+
import Explorer.SmartContract.Helper, only: [cast_libraries: 1]
alias Explorer.Chain
@@ -10,6 +12,10 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
alias Explorer.SmartContract.{CompilerVersion, Helper}
alias Explorer.SmartContract.Solidity.Verifier
+ @sc_verification_via_flattened_file_started "Smart-contract verification via flattened file started"
+ @sc_verification_via_standard_json_input_started "Smart-contract verification via standard json input started"
+ @sc_verification_via_multipart_files_started "Smart-contract verification via multipart files started"
+
@doc """
Evaluates smart contract authenticity and saves its details.
@@ -27,6 +33,7 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
"""
def publish(address_hash, params, external_libraries \\ %{}) do
+ Logger.info(@sc_verification_via_flattened_file_started)
params_with_external_libraries = add_external_libraries(params, external_libraries)
case Verifier.evaluate_authenticity(address_hash, params_with_external_libraries) do
@@ -65,6 +72,8 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
end
def publish_with_standard_json_input(%{"address_hash" => address_hash} = params, json_input) do
+ Logger.info(@sc_verification_via_standard_json_input_started)
+
case Verifier.evaluate_authenticity_via_standard_json_input(address_hash, params, json_input) do
{:ok,
%{
@@ -102,6 +111,7 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
end
def publish_with_multi_part_files(%{"address_hash" => address_hash} = params, external_libraries \\ %{}, files) do
+ Logger.info(@sc_verification_via_multipart_files_started)
params_with_external_libraries = add_external_libraries(params, external_libraries)
case Verifier.evaluate_authenticity_via_multi_part_files(address_hash, params_with_external_libraries, files) do
@@ -187,6 +197,8 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
end
defp create_or_update_smart_contract(address_hash, attrs) do
+ Logger.info("Publish successfully verified Solidity smart-contract #{address_hash} into the DB")
+
if Chain.smart_contract_verified?(address_hash) do
Chain.update_smart_contract(attrs, attrs.external_libraries, attrs.secondary_sources)
else
@@ -209,6 +221,8 @@ defmodule Explorer.SmartContract.Solidity.Publisher do
verification_with_files?
)
+ Logger.error("Solidity smart-contract verification #{address_hash} failed because of the error #{error}")
+
%{changeset | action: :insert}
end
diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/publisher_worker.ex b/apps/explorer/lib/explorer/smart_contract/solidity/publisher_worker.ex
index b8dbc3f81dba..b9ae134d54cb 100644
--- a/apps/explorer/lib/explorer/smart_contract/solidity/publisher_worker.ex
+++ b/apps/explorer/lib/explorer/smart_contract/solidity/publisher_worker.ex
@@ -3,6 +3,8 @@ defmodule Explorer.SmartContract.Solidity.PublisherWorker do
Background smart contract verification worker.
"""
+ require Logger
+
use Que.Worker, concurrency: 5
alias Explorer.Chain.Events.Publisher, as: EventsPublisher
@@ -68,6 +70,8 @@ defmodule Explorer.SmartContract.Solidity.PublisherWorker do
{:error, changeset}
end
+ Logger.info("Smart-contract #{address_hash} verification: broadcast verification results")
+
if conn do
EventsPublisher.broadcast([{:contract_verification_result, {address_hash, result, conn}}], :on_demand)
else
diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex
index 57c11709abd5..ee5554a0361d 100644
--- a/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex
+++ b/apps/explorer/lib/explorer/smart_contract/solidity/verifier.ex
@@ -11,8 +11,10 @@ defmodule Explorer.SmartContract.Solidity.Verifier do
import Explorer.SmartContract.Helper,
only: [cast_libraries: 1, prepare_bytecode_for_microservice: 3, contract_creation_input: 1]
+ # import Explorer.Chain.SmartContract, only: [:function_description]
alias ABI.{FunctionSelector, TypeDecoder}
alias Explorer.Chain
+ alias Explorer.Chain.{Data, Hash, SmartContract}
alias Explorer.SmartContract.RustVerifierInterface
alias Explorer.SmartContract.Solidity.CodeCompiler
@@ -533,4 +535,53 @@ defmodule Explorer.SmartContract.Solidity.Verifier do
def parse_boolean(false), do: false
def parse_boolean(_), do: false
+
+ @doc """
+ Function tries to parse constructor args from smart contract creation input.
+ 1. using `extract_meta_from_deployed_bytecode/1` we derive CBOR metadata string
+ 2. using metadata we split creation_tx_input and try to decode resulting constructor arguments
+ 2.1. if we successfully decoded args using constructor's abi, then return constructor args
+ 2.2 otherwise return nil
+ """
+ @spec parse_constructor_arguments_for_sourcify_contract(Hash.Address.t(), SmartContract.abi()) :: nil | binary
+ def parse_constructor_arguments_for_sourcify_contract(address_hash, abi) do
+ parse_constructor_arguments_for_sourcify_contract(address_hash, abi, Chain.smart_contract_bytecode(address_hash))
+ end
+
+ @doc """
+ Clause for cases when we already can pass deployed bytecode to this function (in order to avoid excessive read DB accesses)
+ """
+ @spec parse_constructor_arguments_for_sourcify_contract(
+ Hash.Address.t(),
+ SmartContract.abi(),
+ binary | Explorer.Chain.Data.t()
+ ) :: nil | binary
+ def parse_constructor_arguments_for_sourcify_contract(address_hash, abi, deployed_bytecode)
+ when is_binary(deployed_bytecode) do
+ creation_tx_input =
+ case Chain.smart_contract_creation_tx_bytecode(address_hash) do
+ %{init: init, created_contract_code: _created_contract_code} ->
+ "0x" <> init_without_0x = init
+ init_without_0x
+
+ _ ->
+ nil
+ end
+
+ with true <- has_constructor_with_params?(abi),
+ check_function <- parse_constructor_and_return_check_function(abi),
+ false <- is_nil(creation_tx_input) || deployed_bytecode == "0x",
+ {meta, meta_length} <- extract_meta_from_deployed_bytecode(deployed_bytecode),
+ [_bytecode, constructor_args] <- String.split(creation_tx_input, meta <> meta_length),
+ ^constructor_args <- check_function.(constructor_args) do
+ constructor_args
+ else
+ _ ->
+ nil
+ end
+ end
+
+ def parse_constructor_arguments_for_sourcify_contract(address_hash, abi, deployed_bytecode) do
+ parse_constructor_arguments_for_sourcify_contract(address_hash, abi, Data.to_string(deployed_bytecode))
+ end
end
diff --git a/apps/explorer/lib/explorer/smart_contract/vyper/publisher.ex b/apps/explorer/lib/explorer/smart_contract/vyper/publisher.ex
index 64f91345f787..e5c38116d06f 100644
--- a/apps/explorer/lib/explorer/smart_contract/vyper/publisher.ex
+++ b/apps/explorer/lib/explorer/smart_contract/vyper/publisher.ex
@@ -5,6 +5,8 @@ defmodule Explorer.SmartContract.Vyper.Publisher do
import Explorer.SmartContract.Helper, only: [cast_libraries: 1]
+ require Logger
+
alias Explorer.Chain
alias Explorer.Chain.SmartContract
alias Explorer.SmartContract.CompilerVersion
@@ -119,6 +121,7 @@ defmodule Explorer.SmartContract.Vyper.Publisher do
end
def publish_smart_contract(address_hash, params, abi) do
+ Logger.info("Publish successfully verified Vyper smart-contract #{address_hash} into the DB")
attrs = address_hash |> attributes(params, abi)
Chain.create_smart_contract(attrs, attrs.external_libraries, attrs.secondary_sources)
@@ -136,6 +139,8 @@ defmodule Explorer.SmartContract.Vyper.Publisher do
verification_with_files?
)
+ Logger.error("Vyper smart-contract verification #{address_hash} failed because of the error #{error}")
+
%{changeset | action: :insert}
end
diff --git a/apps/explorer/lib/explorer/smart_contract/vyper/publisher_worker.ex b/apps/explorer/lib/explorer/smart_contract/vyper/publisher_worker.ex
index 45b8feccffa9..690efc346635 100644
--- a/apps/explorer/lib/explorer/smart_contract/vyper/publisher_worker.ex
+++ b/apps/explorer/lib/explorer/smart_contract/vyper/publisher_worker.ex
@@ -3,6 +3,8 @@ defmodule Explorer.SmartContract.Vyper.PublisherWorker do
Background smart contract verification worker.
"""
+ require Logger
+
use Que.Worker, concurrency: 5
alias Explorer.Chain.Events.Publisher, as: EventsPublisher
@@ -34,6 +36,8 @@ defmodule Explorer.SmartContract.Vyper.PublisherWorker do
{:error, changeset}
end
+ Logger.info("Smart-contract #{address_hash} verification: broadcast verification results")
+
if conn do
EventsPublisher.broadcast([{:contract_verification_result, {address_hash, result, conn}}], :on_demand)
else
diff --git a/apps/explorer/lib/explorer/utility/missing_block_range.ex b/apps/explorer/lib/explorer/utility/missing_block_range.ex
index b9355d0c6192..4892334d5fd5 100644
--- a/apps/explorer/lib/explorer/utility/missing_block_range.ex
+++ b/apps/explorer/lib/explorer/utility/missing_block_range.ex
@@ -61,6 +61,7 @@ defmodule Explorer.Utility.MissingBlockRange do
update_range(range_1, %{from_number: range_2.from_number})
_ ->
+ delete_ranges_between(max_number, min_number)
insert_range(%{from_number: max_number, to_number: min_number})
end
end
diff --git a/apps/explorer/mix.exs b/apps/explorer/mix.exs
index fb2cb75bfa64..7bf6eb62cc2d 100644
--- a/apps/explorer/mix.exs
+++ b/apps/explorer/mix.exs
@@ -24,7 +24,7 @@ defmodule Explorer.Mixfile do
dialyzer: :test
],
start_permanent: Mix.env() == :prod,
- version: "5.2.1",
+ version: "5.2.2",
xref: [exclude: [BlockScoutWeb.WebRouter.Helpers]]
]
end
diff --git a/apps/explorer/priv/repo/migrations/20230809134253_add_is_verified_via_admin_panel.exs b/apps/explorer/priv/repo/migrations/20230809134253_add_is_verified_via_admin_panel.exs
new file mode 100644
index 000000000000..1cfa57cb6fca
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20230809134253_add_is_verified_via_admin_panel.exs
@@ -0,0 +1,9 @@
+defmodule Explorer.Repo.Migrations.AddIsVerifiedViaAdminPanel do
+ use Ecto.Migration
+
+ def change do
+ alter table(:tokens) do
+ add(:is_verified_via_admin_panel, :boolean, null: true, default: false)
+ end
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20230815131151_drop_logs_address_hash_foreign_key.exs b/apps/explorer/priv/repo/migrations/20230815131151_drop_logs_address_hash_foreign_key.exs
new file mode 100644
index 000000000000..e847cb14d74f
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20230815131151_drop_logs_address_hash_foreign_key.exs
@@ -0,0 +1,8 @@
+# cspell:ignore fkey
+defmodule Explorer.Repo.Migrations.DropLogsAddressHashForeignKey do
+ use Ecto.Migration
+
+ def change do
+ drop_if_exists(constraint(:logs, :logs_address_hash_fkey))
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20230816061723_drop_token_transfers_and_transactions_address_foreign_key.exs b/apps/explorer/priv/repo/migrations/20230816061723_drop_token_transfers_and_transactions_address_foreign_key.exs
new file mode 100644
index 000000000000..1cfe0a5fb3d7
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20230816061723_drop_token_transfers_and_transactions_address_foreign_key.exs
@@ -0,0 +1,13 @@
+# cspell:ignore fkey
+defmodule Explorer.Repo.Migrations.DropTokenTransfersAndTransactionsAddressForeignKey do
+ use Ecto.Migration
+
+ def change do
+ drop_if_exists(constraint(:token_transfers, :token_transfers_from_address_hash_fkey))
+ drop_if_exists(constraint(:token_transfers, :token_transfers_to_address_hash_fkey))
+ drop_if_exists(constraint(:token_transfers, :token_transfers_token_contract_address_hash_fkey))
+ drop_if_exists(constraint(:transactions, :transactions_created_contract_address_hash_fkey))
+ drop_if_exists(constraint(:transactions, :transactions_from_address_hash_fkey))
+ drop_if_exists(constraint(:transactions, :transactions_to_address_hash_fkey))
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20230817061317_drop_address_foreign_keys.exs b/apps/explorer/priv/repo/migrations/20230817061317_drop_address_foreign_keys.exs
new file mode 100644
index 000000000000..f10c301b76e3
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20230817061317_drop_address_foreign_keys.exs
@@ -0,0 +1,14 @@
+# cspell:ignore fkey
+defmodule Explorer.Repo.Migrations.DropAddressForeignKeys do
+ use Ecto.Migration
+
+ def change do
+ drop_if_exists(constraint(:address_coin_balances, :address_coin_balances_address_hash_fkey))
+ drop_if_exists(constraint(:address_token_balances, :address_token_balances_address_hash_fkey))
+ drop_if_exists(constraint(:address_current_token_balances, :address_current_token_balances_address_hash_fkey))
+ drop_if_exists(constraint(:tokens, :tokens_contract_address_hash_fkey))
+ drop_if_exists(constraint(:internal_transactions, :internal_transactions_created_contract_address_hash_fkey))
+ drop_if_exists(constraint(:internal_transactions, :internal_transactions_from_address_hash_fkey))
+ drop_if_exists(constraint(:internal_transactions, :internal_transactions_to_address_hash_fkey))
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20230821120625_drop_rest_address_foreign_keys.exs b/apps/explorer/priv/repo/migrations/20230821120625_drop_rest_address_foreign_keys.exs
new file mode 100644
index 000000000000..36cdd2353fa5
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20230821120625_drop_rest_address_foreign_keys.exs
@@ -0,0 +1,14 @@
+# cspell:ignore fkey
+defmodule Explorer.Repo.Migrations.DropRestAddressForeignKeys do
+ use Ecto.Migration
+
+ def change do
+ drop_if_exists(constraint(:address_coin_balances_daily, :address_coin_balances_daily_address_hash_fkey))
+ drop_if_exists(constraint(:address_to_tags, :address_to_tags_address_hash_fkey))
+ drop_if_exists(constraint(:block_rewards, :block_rewards_address_hash_fkey))
+ drop_if_exists(constraint(:decompiled_smart_contracts, :decompiled_smart_contracts_address_hash_fkey))
+ drop_if_exists(constraint(:smart_contracts, :smart_contracts_address_hash_fkey))
+ drop_if_exists(constraint(:withdrawals, :withdrawals_address_hash_fkey))
+ drop_if_exists(constraint(:blocks, :blocks_miner_hash_fkey))
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20230831122819_drop_current_token_balances_tokens_foreign_key.exs b/apps/explorer/priv/repo/migrations/20230831122819_drop_current_token_balances_tokens_foreign_key.exs
new file mode 100644
index 000000000000..3befa9600c66
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20230831122819_drop_current_token_balances_tokens_foreign_key.exs
@@ -0,0 +1,10 @@
+# cspell:ignore fkey
+defmodule Explorer.Repo.Migrations.DropCurrentTokenBalancesTokensForeignKey do
+ use Ecto.Migration
+
+ def change do
+ drop_if_exists(
+ constraint(:address_current_token_balances, :address_current_token_balances_token_contract_address_hash_fkey)
+ )
+ end
+end
diff --git a/apps/explorer/priv/repo/migrations/20230905085809_drop_token_balances_tokens_foreign_key.exs b/apps/explorer/priv/repo/migrations/20230905085809_drop_token_balances_tokens_foreign_key.exs
new file mode 100644
index 000000000000..265933ff4c23
--- /dev/null
+++ b/apps/explorer/priv/repo/migrations/20230905085809_drop_token_balances_tokens_foreign_key.exs
@@ -0,0 +1,8 @@
+# cspell:ignore fkey
+defmodule Explorer.Repo.Migrations.DropTokenBalancesTokensForeignKey do
+ use Ecto.Migration
+
+ def change do
+ drop_if_exists(constraint(:address_token_balances, :address_token_balances_token_contract_address_hash_fkey))
+ end
+end
diff --git a/apps/explorer/test/explorer/chain/csv_export/address_log_csv_exporter_test.exs b/apps/explorer/test/explorer/chain/csv_export/address_log_csv_exporter_test.exs
index b863792f8165..bff1ca818d33 100644
--- a/apps/explorer/test/explorer/chain/csv_export/address_log_csv_exporter_test.exs
+++ b/apps/explorer/test/explorer/chain/csv_export/address_log_csv_exporter_test.exs
@@ -1,6 +1,7 @@
defmodule Explorer.Chain.AddressLogCsvExporterTest do
use Explorer.DataCase
+ alias Explorer.Chain.Address
alias Explorer.Chain.CSVExport.AddressLogCsvExporter
describe "export/3" do
@@ -74,7 +75,7 @@ defmodule Explorer.Chain.AddressLogCsvExporterTest do
assert result.index == to_string(log.index)
assert result.block_number == to_string(log.block_number)
assert result.block_hash == to_string(log.block_hash)
- assert result.address == String.downcase(to_string(log.address))
+ assert result.address == Address.checksum(log.address.hash)
assert result.data == to_string(log.data)
assert result.first_topic == to_string(log.first_topic)
assert result.second_topic == to_string(log.second_topic)
diff --git a/apps/explorer/test/explorer/chain/import/runner/address/current_token_balances_test.exs b/apps/explorer/test/explorer/chain/import/runner/address/current_token_balances_test.exs
index 31eba0553de0..fa8d97e0a5c2 100644
--- a/apps/explorer/test/explorer/chain/import/runner/address/current_token_balances_test.exs
+++ b/apps/explorer/test/explorer/chain/import/runner/address/current_token_balances_test.exs
@@ -218,7 +218,8 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalancesTest do
address_hash: address.hash,
block_number: 2,
token_contract_address_hash: token.contract_address_hash,
- value: Decimal.new(200)
+ value: Decimal.new(200),
+ value_fetched_at: DateTime.utc_now()
},
options
)
@@ -300,7 +301,8 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalancesTest do
address_hash: address_hash,
token_contract_address_hash: token_contract_address_hash,
block_number: block_number,
- value: value
+ value: value,
+ value_fetched_at: DateTime.utc_now()
},
options
)
@@ -344,7 +346,8 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalancesTest do
address_hash: address_hash,
token_contract_address_hash: token_contract_address_hash,
block_number: block_number,
- value: value
+ value: value,
+ value_fetched_at: DateTime.utc_now()
},
options
)
@@ -404,13 +407,15 @@ defmodule Explorer.Chain.Import.Runner.Address.CurrentTokenBalancesTest do
address_hash: non_holder_becomes_holder_address_hash,
token_contract_address_hash: token_contract_address_hash,
block_number: block_number,
- value: non_holder_becomes_holder_value
+ value: non_holder_becomes_holder_value,
+ value_fetched_at: DateTime.utc_now()
},
%{
address_hash: holder_becomes_non_holder_address_hash,
token_contract_address_hash: token_contract_address_hash,
block_number: block_number,
- value: holder_becomes_non_holder_value
+ value: holder_becomes_non_holder_value,
+ value_fetched_at: DateTime.utc_now()
}
],
options
diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs
index fbfc00668853..728d7adc2971 100644
--- a/apps/explorer/test/explorer/chain_test.exs
+++ b/apps/explorer/test/explorer/chain_test.exs
@@ -28,6 +28,7 @@ defmodule Explorer.ChainTest do
}
alias Explorer.{Chain, Etherscan}
+ alias Explorer.Chain.Address.Counters
alias Explorer.Chain.Cache.Block, as: BlockCache
alias Explorer.Chain.Cache.Transaction, as: TransactionCache
alias Explorer.Chain.Cache.PendingBlockOperation, as: PendingBlockOperationCache
@@ -84,7 +85,7 @@ defmodule Explorer.ChainTest do
start_supervised!(AddressesWithBalanceCounter)
AddressesWithBalanceCounter.consolidate()
- addresses_with_balance = Chain.count_addresses_with_balance_from_cache()
+ addresses_with_balance = Counters.count_addresses_with_balance_from_cache()
assert is_integer(addresses_with_balance)
assert addresses_with_balance == 2
@@ -100,7 +101,7 @@ defmodule Explorer.ChainTest do
start_supervised!(AddressesCounter)
AddressesCounter.consolidate()
- addresses_with_balance = Chain.address_estimated_count()
+ addresses_with_balance = Counters.address_estimated_count()
assert is_integer(addresses_with_balance)
assert addresses_with_balance == 3
@@ -108,7 +109,7 @@ defmodule Explorer.ChainTest do
test "returns 0 on empty table" do
start_supervised!(AddressesCounter)
- assert 0 == Chain.address_estimated_count()
+ assert 0 == Counters.address_estimated_count()
end
end
@@ -875,7 +876,7 @@ defmodule Explorer.ChainTest do
|> insert(nonce: 100, from_address: address)
|> with_block(insert(:block, number: 1000))
- assert Chain.total_transactions_sent_by_address(address.hash) == 101
+ assert Counters.total_transactions_sent_by_address(address.hash) == 101
end
test "returns 0 when the address did not send transactions" do
@@ -885,7 +886,7 @@ defmodule Explorer.ChainTest do
|> insert(nonce: 100, to_address: address)
|> with_block(insert(:block, number: 1000))
- assert Chain.total_transactions_sent_by_address(address.hash) == 0
+ assert Counters.total_transactions_sent_by_address(address.hash) == 0
end
end
@@ -1099,13 +1100,13 @@ defmodule Explorer.ChainTest do
test "without transactions" do
%Address{hash: address_hash} = insert(:address)
- assert Chain.address_to_incoming_transaction_count(address_hash) == 0
+ assert Counters.address_to_incoming_transaction_count(address_hash) == 0
end
test "with transactions" do
%Transaction{to_address: to_address} = insert(:transaction)
- assert Chain.address_to_incoming_transaction_count(to_address.hash) == 1
+ assert Counters.address_to_incoming_transaction_count(to_address.hash) == 1
end
end
diff --git a/apps/explorer/test/explorer/exchange_rates/source/coin_market_cap_test.exs b/apps/explorer/test/explorer/exchange_rates/source/coin_market_cap_test.exs
index c9bfea7ad1f5..1d957f4e4aa0 100644
--- a/apps/explorer/test/explorer/exchange_rates/source/coin_market_cap_test.exs
+++ b/apps/explorer/test/explorer/exchange_rates/source/coin_market_cap_test.exs
@@ -34,4 +34,103 @@ defmodule Explorer.ExchangeRates.Source.CoinMarketCapTest do
CoinMarketCap.source_url("ETH")
end
end
+
+ @token_properties %{
+ "circulating_supply" => 0,
+ "cmc_rank" => 2977,
+ "date_added" => "2021-12-06T11:25:31.000Z",
+ "id" => 15658,
+ "infinite_supply" => false,
+ "is_active" => 1,
+ "is_fiat" => 0,
+ "last_updated" => "2023-09-12T09:03:00.000Z",
+ "max_supply" => 210_240_000,
+ "name" => "Qitmeer Network",
+ "num_market_pairs" => 10,
+ "platform" => nil,
+ "quote" => %{
+ "USD" => %{
+ "fully_diluted_market_cap" => 27_390_222.61,
+ "last_updated" => "2023-09-12T09:03:00.000Z",
+ "market_cap" => 0,
+ "market_cap_dominance" => 0,
+ "percent_change_1h" => -0.14807635,
+ "percent_change_24h" => -4.05784287,
+ "percent_change_30d" => -20.18918329,
+ "percent_change_60d" => 85.21384726,
+ "percent_change_7d" => -5.49776979,
+ "percent_change_90d" => 22.27442093,
+ "price" => 0.13028073920022334,
+ "tvl" => nil,
+ "volume_24h" => 93766.09652096,
+ "volume_change_24h" => -0.9423
+ }
+ },
+ "self_reported_circulating_supply" => 71_348_557,
+ "self_reported_market_cap" => 9_295_342.74682927,
+ "slug" => "qitmeer-network",
+ "symbol" => "MEER",
+ "tags" => [],
+ "total_supply" => 71_348_557,
+ "tvl_ratio" => nil
+ }
+
+ @market_data_multiple_tokens %{
+ "MEER" => [
+ @token_properties,
+ %{
+ "circulating_supply" => nil,
+ "cmc_rank" => nil,
+ "date_added" => "2023-05-12T15:52:05.000Z",
+ "id" => 25240,
+ "infinite_supply" => false,
+ "is_active" => 0,
+ "is_fiat" => 0,
+ "last_updated" => "2023-09-12T09:05:15.725Z",
+ "max_supply" => 210_240_000,
+ "name" => "Meer Coin",
+ "num_market_pairs" => nil,
+ "platform" => nil,
+ "quote" => %{
+ "USD" => %{
+ "fully_diluted_market_cap" => nil,
+ "last_updated" => "2023-09-12T09:05:15.725Z",
+ "market_cap" => nil,
+ "market_cap_dominance" => nil,
+ "percent_change_1h" => nil,
+ "percent_change_24h" => nil,
+ "percent_change_30d" => nil,
+ "percent_change_60d" => nil,
+ "percent_change_7d" => nil,
+ "percent_change_90d" => nil,
+ "price" => 0,
+ "tvl" => nil,
+ "volume_24h" => nil,
+ "volume_change_24h" => nil
+ }
+ },
+ "self_reported_circulating_supply" => nil,
+ "self_reported_market_cap" => nil,
+ "slug" => "meer-coin",
+ "symbol" => "MEER",
+ "tags" => [],
+ "total_supply" => nil,
+ "tvl_ratio" => nil
+ }
+ ]
+ }
+
+ @market_data_single_token %{
+ "15658" => @token_properties
+ }
+
+ describe "get_token_properties/1" do
+ test "returns a single token property, when market_data contains multiple tokens" do
+ assert CoinMarketCap.get_token_properties(@market_data_multiple_tokens) == @token_properties
+ end
+
+ test "returns a single token property, when market_data contains a single token" do
+ assert CoinMarketCap.get_token_properties(@market_data_single_token) == @token_properties
+ end
+ end
end
diff --git a/apps/explorer/test/explorer/market/history/cataloger_test.exs b/apps/explorer/test/explorer/market/history/cataloger_test.exs
index 0acc04a7f24b..68f2aa9779cc 100644
--- a/apps/explorer/test/explorer/market/history/cataloger_test.exs
+++ b/apps/explorer/test/explorer/market/history/cataloger_test.exs
@@ -6,7 +6,9 @@ defmodule Explorer.Market.History.CatalogerTest do
alias Explorer.Market.MarketHistory
alias Explorer.Market.History.Cataloger
alias Explorer.Market.History.Source.Price.TestSource
+ alias Explorer.Market.History.Source.Price.CryptoCompare
alias Explorer.Repo
+ alias Plug.Conn
setup do
Application.put_env(:explorer, Cataloger, source: TestSource)
@@ -19,6 +21,38 @@ defmodule Explorer.Market.History.CatalogerTest do
end
test "handle_info with `{:fetch_price_history, days}`" do
+ bypass = Bypass.open()
+ Application.put_env(:explorer, CryptoCompare, base_url: "http://localhost:#{bypass.port}")
+
+ resp = """
+ {
+ "Response": "Success",
+ "Type": 100,
+ "Aggregated": false,
+ "TimeTo": 1522569618,
+ "TimeFrom": 1522566018,
+ "FirstValueInArray": true,
+ "ConversionType": {
+ "type": "multiply",
+ "conversionSymbol": "ETH"
+ },
+ "Data": [{
+ "time": 1522566018,
+ "high": 10,
+ "low": 5,
+ "open": 5,
+ "volumefrom": 0,
+ "volumeto": 0,
+ "close": 10,
+ "conversionType": "multiply",
+ "conversionSymbol": "ETH"
+ }],
+ "RateLimit": {},
+ "HasWarning": false
+ }
+ """
+
+ Bypass.expect(bypass, fn conn -> Conn.resp(conn, 200, resp) end)
records = [%{date: ~D[2018-04-01], closing_price: Decimal.new(10), opening_price: Decimal.new(5)}]
expect(TestSource, :fetch_price_history, fn 1 -> {:ok, records} end)
set_mox_global()
diff --git a/apps/explorer/test/explorer/token/instance_metadata_retriever_test.exs b/apps/explorer/test/explorer/token/instance_metadata_retriever_test.exs
index e9ef52dc583e..a9255d04c796 100644
--- a/apps/explorer/test/explorer/token/instance_metadata_retriever_test.exs
+++ b/apps/explorer/test/explorer/token/instance_metadata_retriever_test.exs
@@ -1,8 +1,7 @@
-defmodule Explorer.Token.InstanceMetadataRetrieverTest do
+defmodule Explorer.Token.MetadataRetrieverTest do
use EthereumJSONRPC.Case
- alias EthereumJSONRPC.Encoder
- alias Explorer.Token.InstanceMetadataRetriever
+ alias Indexer.Fetcher.TokenInstance.MetadataRetriever
alias Plug.Conn
import Mox
@@ -90,7 +89,7 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
assert %{
"c87b56dd" => {:ok, ["https://vault.warriders.com/18290729947667102496.json"]}
} ==
- InstanceMetadataRetriever.query_contract(
+ MetadataRetriever.query_contract(
"0x5caebd3b32e210e85ce3e9d51638b9c445481567",
%{
"c87b56dd" => [18_290_729_947_667_102_496]
@@ -133,7 +132,7 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
assert %{
"0e89341c" => {:ok, ["https://vault.warriders.com/18290729947667102496.json"]}
} ==
- InstanceMetadataRetriever.query_contract(
+ MetadataRetriever.query_contract(
"0x5caebd3b32e210e85ce3e9d51638b9c445481567",
%{
"0e89341c" => [18_290_729_947_667_102_496]
@@ -164,28 +163,7 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
end)
assert {:ok, %{metadata: %{"name" => "Sérgio Mendonça"}}} ==
- InstanceMetadataRetriever.fetch_json(%{
- "c87b56dd" => {:ok, ["http://localhost:#{bypass.port}#{path}"]}
- })
- end
-
- test "fetches json metadata for kitties" do
- Application.put_env(:explorer, :http_adapter, Explorer.Mox.HTTPoison)
-
- result =
- "{\"id\":100500,\"name\":\"KittyBlue_2_Lemonade\",\"generation\":20,\"genes\":\"623509754227292470437941473598751240781530569131665917719736997423495595\",\"created_at\":\"2017-12-06T01:56:27.000Z\",\"birthday\":\"2017-12-06T00:00:00.000Z\",\"image_url\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/100500.svg\",\"image_url_cdn\":\"https://img.cn.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/100500.svg\",\"color\":\"strawberry\",\"background_color\":\"#ffe0e5\",\"bio\":\"Shalom! I'm KittyBlue_2_Lemonade. I'm a professional Foreign Film Director and I love cantaloupe. I'm convinced that the world is flat. One day I'll prove it. It's pawesome to meet you!\",\"kitty_type\":null,\"is_fancy\":false,\"is_exclusive\":false,\"is_special_edition\":false,\"fancy_type\":null,\"language\":\"en\",\"is_prestige\":false,\"prestige_type\":null,\"prestige_ranking\":null,\"prestige_time_limit\":null,\"status\":{\"is_ready\":true,\"is_gestating\":false,\"cooldown\":1410310201506,\"dynamic_cooldown\":1475064986478,\"cooldown_index\":10,\"cooldown_end_block\":0,\"pending_tx_type\":null,\"pending_tx_since\":null},\"purrs\":{\"count\":1,\"is_purred\":false},\"watchlist\":{\"count\":0,\"is_watchlisted\":false},\"hatcher\":{\"address\":\"0x7b9ea9ac69b8fde875554321472c732eeff06ca0\",\"image\":\"14\",\"nickname\":\"KittyBlu\",\"hasDapper\":false,\"twitter_id\":null,\"twitter_image_url\":null,\"twitter_handle\":null},\"auction\":{},\"offer\":{},\"owner\":{\"address\":\"0x7b9ea9ac69b8fde875554321472c732eeff06ca0\",\"hasDapper\":false,\"twitter_id\":null,\"twitter_image_url\":null,\"twitter_handle\":null,\"image\":\"14\",\"nickname\":\"KittyBlu\"},\"matron\":{\"id\":46234,\"name\":\"KittyBlue_1_Limegreen\",\"generation\":10,\"enhanced_cattributes\":[{\"type\":\"body\",\"kittyId\":19631,\"position\":105,\"description\":\"cymric\"},{\"type\":\"coloreyes\",\"kittyId\":40356,\"position\":263,\"description\":\"limegreen\"},{\"type\":\"eyes\",\"kittyId\":3185,\"position\":16,\"description\":\"raisedbrow\"},{\"type\":\"pattern\",\"kittyId\":46234,\"position\":-1,\"description\":\"totesbasic\"},{\"type\":\"mouth\",\"kittyId\":46234,\"position\":-1,\"description\":\"happygokitty\"},{\"type\":\"colorprimary\",\"kittyId\":46234,\"position\":-1,\"description\":\"greymatter\"},{\"type\":\"colorsecondary\",\"kittyId\":46234,\"position\":-1,\"description\":\"lemonade\"},{\"type\":\"colortertiary\",\"kittyId\":46234,\"position\":-1,\"description\":\"granitegrey\"}],\"owner_wallet_address\":\"0x7b9ea9ac69b8fde875554321472c732eeff06ca0\",\"owner\":{\"address\":\"0x7b9ea9ac69b8fde875554321472c732eeff06ca0\"},\"created_at\":\"2017-12-03T21:29:17.000Z\",\"image_url\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/46234.svg\",\"image_url_cdn\":\"https://img.cn.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/46234.svg\",\"color\":\"limegreen\",\"is_fancy\":false,\"kitty_type\":null,\"is_exclusive\":false,\"is_special_edition\":false,\"fancy_type\":null,\"status\":{\"is_ready\":true,\"is_gestating\":false,\"cooldown\":1486487069384},\"hatched\":true,\"wrapped\":false,\"image_url_png\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/46234.png\"},\"sire\":{\"id\":82090,\"name\":null,\"generation\":19,\"enhanced_cattributes\":[{\"type\":\"body\",\"kittyId\":82090,\"position\":-1,\"description\":\"himalayan\"},{\"type\":\"coloreyes\",\"kittyId\":82090,\"position\":-1,\"description\":\"strawberry\"},{\"type\":\"eyes\",\"kittyId\":82090,\"position\":-1,\"description\":\"thicccbrowz\"},{\"type\":\"pattern\",\"kittyId\":82090,\"position\":-1,\"description\":\"totesbasic\"},{\"type\":\"mouth\",\"kittyId\":82090,\"position\":-1,\"description\":\"pouty\"},{\"type\":\"colorprimary\",\"kittyId\":82090,\"position\":-1,\"description\":\"aquamarine\"},{\"type\":\"colorsecondary\",\"kittyId\":82090,\"position\":-1,\"description\":\"chocolate\"},{\"type\":\"colortertiary\",\"kittyId\":82090,\"position\":-1,\"description\":\"granitegrey\"}],\"owner_wallet_address\":\"0x798fdad0cedc4b298fc7d53a982fa0c5f447eaa5\",\"owner\":{\"address\":\"0x798fdad0cedc4b298fc7d53a982fa0c5f447eaa5\"},\"created_at\":\"2017-12-05T06:30:05.000Z\",\"image_url\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/82090.svg\",\"image_url_cdn\":\"https://img.cn.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/82090.svg\",\"color\":\"strawberry\",\"is_fancy\":false,\"is_exclusive\":false,\"is_special_edition\":false,\"fancy_type\":null,\"status\":{\"is_ready\":true,\"is_gestating\":false,\"cooldown\":1486619010030},\"kitty_type\":null,\"hatched\":true,\"wrapped\":false,\"image_url_png\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/82090.png\"},\"children\":[],\"hatched\":true,\"wrapped\":false,\"enhanced_cattributes\":[{\"type\":\"colorprimary\",\"description\":\"greymatter\",\"position\":null,\"kittyId\":100500},{\"type\":\"coloreyes\",\"description\":\"strawberry\",\"position\":null,\"kittyId\":100500},{\"type\":\"body\",\"description\":\"himalayan\",\"position\":null,\"kittyId\":100500},{\"type\":\"colorsecondary\",\"description\":\"lemonade\",\"position\":null,\"kittyId\":100500},{\"type\":\"mouth\",\"description\":\"pouty\",\"position\":null,\"kittyId\":100500},{\"type\":\"pattern\",\"description\":\"totesbasic\",\"position\":null,\"kittyId\":100500},{\"type\":\"eyes\",\"description\":\"thicccbrowz\",\"position\":null,\"kittyId\":100500},{\"type\":\"colortertiary\",\"description\":\"kittencream\",\"position\":null,\"kittyId\":100500},{\"type\":\"secret\",\"description\":\"se5\",\"position\":-1,\"kittyId\":100500},{\"type\":\"purrstige\",\"description\":\"pu20\",\"position\":-1,\"kittyId\":100500}],\"variation\":null,\"variation_ranking\":null,\"image_url_png\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/100500.png\",\"items\":[]}"
-
- Explorer.Mox.HTTPoison
- |> expect(:get, fn "https://api.cryptokitties.co/kitties/100500", _headers, _options ->
- {:ok, %HTTPoison.Response{status_code: 200, body: result}}
- end)
-
- {:ok, %{metadata: metadata}} =
- InstanceMetadataRetriever.fetch_metadata("0x06012c8cf97bead5deae237070f9587f8e7a266d", 100_500)
-
- assert Map.get(metadata, "name") == "KittyBlue_2_Lemonade"
-
- Application.put_env(:explorer, :http_adapter, HTTPoison)
+ MetadataRetriever.fetch_json({:ok, ["http://localhost:#{bypass.port}#{path}"]})
end
test "fetches json metadata when HTTP status 301", %{bypass: bypass} do
@@ -212,120 +190,19 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
Conn.resp(conn, 200, json)
end)
- {:ok, %{metadata: metadata}} =
- InstanceMetadataRetriever.fetch_metadata_from_uri("http://localhost:#{bypass.port}#{path}")
+ {:ok, %{metadata: metadata}} = MetadataRetriever.fetch_metadata_from_uri("http://localhost:#{bypass.port}#{path}")
assert Map.get(metadata, "attributes") == Jason.decode!(attributes)
end
- test "replace {id} with actual token_id", %{bypass: bypass} do
- json = """
- {
- "name": "Sérgio Mendonça {id}"
- }
- """
-
- abi =
- [
- %{
- "type" => "function",
- "stateMutability" => "nonpayable",
- "payable" => false,
- "outputs" => [],
- "name" => "tokenURI",
- "inputs" => [
- %{"type" => "string", "name" => "name", "internalType" => "string"}
- ]
- }
- ]
- |> ABI.parse_specification()
- |> Enum.at(0)
-
- encoded_url =
- abi
- |> Encoder.encode_function_call(["http://localhost:#{bypass.port}/api/card/{id}"])
- |> String.replace("4cf12d26", "")
-
- EthereumJSONRPC.Mox
- |> expect(:json_rpc, fn [
- %{
- id: 0,
- jsonrpc: "2.0",
- method: "eth_call",
- params: [
- %{
- data:
- "0xc87b56dd0000000000000000000000000000000000000000000000000000000000000309",
- to: "0x5caebd3b32e210e85ce3e9d51638b9c445481567"
- },
- "latest"
- ]
- }
- ],
- _options ->
- {:ok,
- [
- %{
- id: 0,
- jsonrpc: "2.0",
- error: %{code: -32000, message: "execution reverted"}
- }
- ]}
- end)
- |> expect(:json_rpc, fn [
- %{
- id: 0,
- jsonrpc: "2.0",
- method: "eth_call",
- params: [
- %{
- data:
- "0x0e89341c0000000000000000000000000000000000000000000000000000000000000309",
- to: "0x5caebd3b32e210e85ce3e9d51638b9c445481567"
- },
- "latest"
- ]
- }
- ],
- _options ->
+ test "decodes json file in tokenURI" do
+ data =
{:ok,
[
- %{
- id: 0,
- jsonrpc: "2.0",
- result: encoded_url
- }
+ "data:application/json,{\"name\":\"Home%20Address%20-%200x0000000000C1A6066c6c8B9d63e9B6E8865dC117\",\"description\":\"This%20NFT%20can%20be%20redeemed%20on%20HomeWork%20to%20grant%20a%20controller%20the%20exclusive%20right%20to%20deploy%20contracts%20with%20arbitrary%20bytecode%20to%20the%20designated%20home%20address.\",\"image\":\"data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNDQgNzIiPjxzdHlsZT48IVtDREFUQVsuQntzdHJva2UtbGluZWpvaW46cm91bmR9LkN7c3Ryb2tlLW1pdGVybGltaXQ6MTB9LkR7c3Ryb2tlLXdpZHRoOjJ9LkV7ZmlsbDojOWI5YjlhfS5Ge3N0cm9rZS1saW5lY2FwOnJvdW5kfV1dPjwvc3R5bGU+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMiAwIDAgMS4wMiA4LjEgMCkiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0xOSAzMmgzNHYyNEgxOXoiLz48ZyBzdHJva2U9IiMwMDAiIGNsYXNzPSJCIEMgRCI+PHBhdGggZmlsbD0iI2E1NzkzOSIgZD0iTTI1IDQwaDl2MTZoLTl6Ii8+PHBhdGggZmlsbD0iIzkyZDNmNSIgZD0iTTQwIDQwaDh2N2gtOHoiLz48cGF0aCBmaWxsPSIjZWE1YTQ3IiBkPSJNNTMgMzJIMTl2LTFsMTYtMTYgMTggMTZ6Ii8+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTE5IDMyaDM0djI0SDE5eiIvPjxwYXRoIGZpbGw9IiNlYTVhNDciIGQ9Ik0yOSAyMWwtNSA1di05aDV6Ii8+PC9nPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCguODQgMCAwIC44NCA2NSA1KSI+PHBhdGggZD0iTTkuNSAyMi45bDQuOCA2LjRhMy4xMiAzLjEyIDAgMCAxLTMgMi4ybC00LjgtNi40Yy4zLTEuNCAxLjYtMi40IDMtMi4yeiIgZmlsbD0iI2QwY2ZjZSIvPjxwYXRoIGZpbGw9IiMwMTAxMDEiIGQ9Ik00MS43IDM4LjVsNS4xLTYuNSIvPjxwYXRoIGQ9Ik00Mi45IDI3LjhMMTguNCA1OC4xIDI0IDYybDIxLjgtMjcuMyAyLjMtMi44eiIgY2xhc3M9IkUiLz48cGF0aCBmaWxsPSIjMDEwMTAxIiBkPSJNNDMuNCAyOS4zbC00LjcgNS44Ii8+PHBhdGggZD0iTTQ2LjggMzJjMy4yIDIuNiA4LjcgMS4yIDEyLjEtMy4yczMuNi05LjkuMy0xMi41bC01LjEgNi41LTIuOC0uMS0uNy0yLjcgNS4xLTYuNWMtMy4yLTIuNi04LjctMS4yLTEyLjEgMy4ycy0zLjYgOS45LS4zIDEyLjUiIGNsYXNzPSJFIi8+PHBhdGggZmlsbD0iI2E1NzkzOSIgZD0iTTI3LjMgMjZsMTEuOCAxNS43IDMuNCAyLjQgOS4xIDE0LjQtMy4yIDIuMy0xIC43LTEwLjItMTMuNi0xLjMtMy45LTExLjgtMTUuN3oiLz48cGF0aCBkPSJNMTIgMTkuOWw1LjkgNy45IDEwLjItNy42LTMuNC00LjVzNi44LTUuMSAxMC43LTQuNWMwIDAtNi42LTMtMTMuMyAxLjFTMTIgMTkuOSAxMiAxOS45eiIgY2xhc3M9IkUiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIGNsYXNzPSJCIEMgRCI+PHBhdGggZD0iTTUyIDU4LjlMNDAuOSA0My4ybC0zLjEtMi4zLTEwLjYtMTQuNy0yLjkgMi4yIDEwLjYgMTQuNyAxLjEgMy42IDExLjUgMTUuNXpNMTIuNSAxOS44bDUuOCA4IDEwLjMtNy40LTMuMy00LjZzNi45LTUgMTAuOC00LjNjMCAwLTYuNi0zLjEtMTMuMy45cy0xMC4zIDcuNC0xMC4zIDcuNHptLTIuNiAyLjlsNC43IDYuNWMtLjUgMS4zLTEuNyAyLjEtMyAyLjJsLTQuNy02LjVjLjMtMS40IDEuNi0yLjQgMy0yLjJ6Ii8+PHBhdGggZD0iTTQxLjMgMzguNWw1LjEtNi41bS0zLjUtMi43bC00LjYgNS44bTguMS0zLjFjMy4yIDIuNiA4LjcgMS4yIDEyLjEtMy4yczMuNi05LjkuMy0xMi41bC01LjEgNi41LTIuOC0uMS0uOC0yLjcgNS4xLTYuNWMtMy4yLTIuNi04LjctMS4yLTEyLjEgMy4yLTMuNCA0LjMtMy42IDkuOS0uMyAxMi41IiBjbGFzcz0iRiIvPjxwYXRoIGQ9Ik0zMC44IDQ0LjRMMTkgNTguOWw0IDMgMTAtMTIuNyIgY2xhc3M9IkYiLz48L2c+PC9nPjwvc3ZnPg==\"}"
]}
- end)
-
- Bypass.expect(
- bypass,
- "GET",
- "/api/card/0000000000000000000000000000000000000000000000000000000000000309",
- fn conn ->
- Conn.resp(conn, 200, json)
- end
- )
- assert {:ok,
- %{
- metadata: %{
- "name" => "Sérgio Mendonça 0000000000000000000000000000000000000000000000000000000000000309"
- }
- }} ==
- InstanceMetadataRetriever.fetch_metadata("0x5caebd3b32e210e85ce3e9d51638b9c445481567", 777)
- end
-
- test "decodes json file in tokenURI" do
- data = %{
- "c87b56dd" =>
- {:ok,
- [
- "data:application/json,{\"name\":\"Home%20Address%20-%200x0000000000C1A6066c6c8B9d63e9B6E8865dC117\",\"description\":\"This%20NFT%20can%20be%20redeemed%20on%20HomeWork%20to%20grant%20a%20controller%20the%20exclusive%20right%20to%20deploy%20contracts%20with%20arbitrary%20bytecode%20to%20the%20designated%20home%20address.\",\"image\":\"data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNDQgNzIiPjxzdHlsZT48IVtDREFUQVsuQntzdHJva2UtbGluZWpvaW46cm91bmR9LkN7c3Ryb2tlLW1pdGVybGltaXQ6MTB9LkR7c3Ryb2tlLXdpZHRoOjJ9LkV7ZmlsbDojOWI5YjlhfS5Ge3N0cm9rZS1saW5lY2FwOnJvdW5kfV1dPjwvc3R5bGU+PGcgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMiAwIDAgMS4wMiA4LjEgMCkiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0xOSAzMmgzNHYyNEgxOXoiLz48ZyBzdHJva2U9IiMwMDAiIGNsYXNzPSJCIEMgRCI+PHBhdGggZmlsbD0iI2E1NzkzOSIgZD0iTTI1IDQwaDl2MTZoLTl6Ii8+PHBhdGggZmlsbD0iIzkyZDNmNSIgZD0iTTQwIDQwaDh2N2gtOHoiLz48cGF0aCBmaWxsPSIjZWE1YTQ3IiBkPSJNNTMgMzJIMTl2LTFsMTYtMTYgMTggMTZ6Ii8+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTE5IDMyaDM0djI0SDE5eiIvPjxwYXRoIGZpbGw9IiNlYTVhNDciIGQ9Ik0yOSAyMWwtNSA1di05aDV6Ii8+PC9nPjwvZz48ZyB0cmFuc2Zvcm09Im1hdHJpeCguODQgMCAwIC44NCA2NSA1KSI+PHBhdGggZD0iTTkuNSAyMi45bDQuOCA2LjRhMy4xMiAzLjEyIDAgMCAxLTMgMi4ybC00LjgtNi40Yy4zLTEuNCAxLjYtMi40IDMtMi4yeiIgZmlsbD0iI2QwY2ZjZSIvPjxwYXRoIGZpbGw9IiMwMTAxMDEiIGQ9Ik00MS43IDM4LjVsNS4xLTYuNSIvPjxwYXRoIGQ9Ik00Mi45IDI3LjhMMTguNCA1OC4xIDI0IDYybDIxLjgtMjcuMyAyLjMtMi44eiIgY2xhc3M9IkUiLz48cGF0aCBmaWxsPSIjMDEwMTAxIiBkPSJNNDMuNCAyOS4zbC00LjcgNS44Ii8+PHBhdGggZD0iTTQ2LjggMzJjMy4yIDIuNiA4LjcgMS4yIDEyLjEtMy4yczMuNi05LjkuMy0xMi41bC01LjEgNi41LTIuOC0uMS0uNy0yLjcgNS4xLTYuNWMtMy4yLTIuNi04LjctMS4yLTEyLjEgMy4ycy0zLjYgOS45LS4zIDEyLjUiIGNsYXNzPSJFIi8+PHBhdGggZmlsbD0iI2E1NzkzOSIgZD0iTTI3LjMgMjZsMTEuOCAxNS43IDMuNCAyLjQgOS4xIDE0LjQtMy4yIDIuMy0xIC43LTEwLjItMTMuNi0xLjMtMy45LTExLjgtMTUuN3oiLz48cGF0aCBkPSJNMTIgMTkuOWw1LjkgNy45IDEwLjItNy42LTMuNC00LjVzNi44LTUuMSAxMC43LTQuNWMwIDAtNi42LTMtMTMuMyAxLjFTMTIgMTkuOSAxMiAxOS45eiIgY2xhc3M9IkUiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIGNsYXNzPSJCIEMgRCI+PHBhdGggZD0iTTUyIDU4LjlMNDAuOSA0My4ybC0zLjEtMi4zLTEwLjYtMTQuNy0yLjkgMi4yIDEwLjYgMTQuNyAxLjEgMy42IDExLjUgMTUuNXpNMTIuNSAxOS44bDUuOCA4IDEwLjMtNy40LTMuMy00LjZzNi45LTUgMTAuOC00LjNjMCAwLTYuNi0zLjEtMTMuMy45cy0xMC4zIDcuNC0xMC4zIDcuNHptLTIuNiAyLjlsNC43IDYuNWMtLjUgMS4zLTEuNyAyLjEtMyAyLjJsLTQuNy02LjVjLjMtMS40IDEuNi0yLjQgMy0yLjJ6Ii8+PHBhdGggZD0iTTQxLjMgMzguNWw1LjEtNi41bS0zLjUtMi43bC00LjYgNS44bTguMS0zLjFjMy4yIDIuNiA4LjcgMS4yIDEyLjEtMy4yczMuNi05LjkuMy0xMi41bC01LjEgNi41LTIuOC0uMS0uOC0yLjcgNS4xLTYuNWMtMy4yLTIuNi04LjctMS4yLTEyLjEgMy4yLTMuNCA0LjMtMy42IDkuOS0uMyAxMi41IiBjbGFzcz0iRiIvPjxwYXRoIGQ9Ik0zMC44IDQ0LjRMMTkgNTguOWw0IDMgMTAtMTIuNyIgY2xhc3M9IkYiLz48L2c+PC9nPjwvc3ZnPg==\"}"
- ]}
- }
-
- assert InstanceMetadataRetriever.fetch_json(data) ==
+ assert MetadataRetriever.fetch_json(data) ==
{:ok,
%{
metadata: %{
@@ -339,15 +216,13 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
end
test "decodes base64 encoded json file in tokenURI" do
- data = %{
- "c87b56dd" =>
- {:ok,
- [
- "data:application/json;base64,eyJuYW1lIjogIi54ZGFpIiwgImRlc2NyaXB0aW9uIjogIlB1bmsgRG9tYWlucyBkaWdpdGFsIGlkZW50aXR5LiBWaXNpdCBodHRwczovL3B1bmsuZG9tYWlucy8iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhacFpYZENiM2c5SWpBZ01DQTFNREFnTlRBd0lpQjNhV1IwYUQwaU5UQXdJaUJvWldsbmFIUTlJalV3TUNJK1BHUmxabk0rUEd4cGJtVmhja2R5WVdScFpXNTBJR2xrUFNKbmNtRmtJaUI0TVQwaU1DVWlJSGt4UFNJd0pTSWdlREk5SWpFd01DVWlJSGt5UFNJd0pTSStQSE4wYjNBZ2IyWm1jMlYwUFNJd0pTSWdjM1I1YkdVOUluTjBiM0F0WTI5c2IzSTZjbWRpS0RVNExERTNMREV4TmlrN2MzUnZjQzF2Y0dGamFYUjVPakVpSUM4K1BITjBiM0FnYjJabWMyVjBQU0l4TURBbElpQnpkSGxzWlQwaWMzUnZjQzFqYjJ4dmNqcHlaMklvTVRFMkxESTFMREUzS1R0emRHOXdMVzl3WVdOcGRIazZNU0lnTHo0OEwyeHBibVZoY2tkeVlXUnBaVzUwUGp3dlpHVm1jejQ4Y21WamRDQjRQU0l3SWlCNVBTSXdJaUIzYVdSMGFEMGlOVEF3SWlCb1pXbG5hSFE5SWpVd01DSWdabWxzYkQwaWRYSnNLQ05uY21Ga0tTSXZQangwWlhoMElIZzlJalV3SlNJZ2VUMGlOVEFsSWlCa2IyMXBibUZ1ZEMxaVlYTmxiR2x1WlQwaWJXbGtaR3hsSWlCbWFXeHNQU0ozYUdsMFpTSWdkR1Y0ZEMxaGJtTm9iM0k5SW0xcFpHUnNaU0lnWm05dWRDMXphWHBsUFNKNExXeGhjbWRsSWo0dWVHUmhhVHd2ZEdWNGRENDhkR1Y0ZENCNFBTSTFNQ1VpSUhrOUlqY3dKU0lnWkc5dGFXNWhiblF0WW1GelpXeHBibVU5SW0xcFpHUnNaU0lnWm1sc2JEMGlkMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0p0YVdSa2JHVWlQbkIxYm1zdVpHOXRZV2x1Y3p3dmRHVjRkRDQ4TDNOMlp6ND0ifQ=="
- ]}
- }
+ data =
+ {:ok,
+ [
+ "data:application/json;base64,eyJuYW1lIjogIi54ZGFpIiwgImRlc2NyaXB0aW9uIjogIlB1bmsgRG9tYWlucyBkaWdpdGFsIGlkZW50aXR5LiBWaXNpdCBodHRwczovL3B1bmsuZG9tYWlucy8iLCAiaW1hZ2UiOiAiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhacFpYZENiM2c5SWpBZ01DQTFNREFnTlRBd0lpQjNhV1IwYUQwaU5UQXdJaUJvWldsbmFIUTlJalV3TUNJK1BHUmxabk0rUEd4cGJtVmhja2R5WVdScFpXNTBJR2xrUFNKbmNtRmtJaUI0TVQwaU1DVWlJSGt4UFNJd0pTSWdlREk5SWpFd01DVWlJSGt5UFNJd0pTSStQSE4wYjNBZ2IyWm1jMlYwUFNJd0pTSWdjM1I1YkdVOUluTjBiM0F0WTI5c2IzSTZjbWRpS0RVNExERTNMREV4TmlrN2MzUnZjQzF2Y0dGamFYUjVPakVpSUM4K1BITjBiM0FnYjJabWMyVjBQU0l4TURBbElpQnpkSGxzWlQwaWMzUnZjQzFqYjJ4dmNqcHlaMklvTVRFMkxESTFMREUzS1R0emRHOXdMVzl3WVdOcGRIazZNU0lnTHo0OEwyeHBibVZoY2tkeVlXUnBaVzUwUGp3dlpHVm1jejQ4Y21WamRDQjRQU0l3SWlCNVBTSXdJaUIzYVdSMGFEMGlOVEF3SWlCb1pXbG5hSFE5SWpVd01DSWdabWxzYkQwaWRYSnNLQ05uY21Ga0tTSXZQangwWlhoMElIZzlJalV3SlNJZ2VUMGlOVEFsSWlCa2IyMXBibUZ1ZEMxaVlYTmxiR2x1WlQwaWJXbGtaR3hsSWlCbWFXeHNQU0ozYUdsMFpTSWdkR1Y0ZEMxaGJtTm9iM0k5SW0xcFpHUnNaU0lnWm05dWRDMXphWHBsUFNKNExXeGhjbWRsSWo0dWVHUmhhVHd2ZEdWNGRENDhkR1Y0ZENCNFBTSTFNQ1VpSUhrOUlqY3dKU0lnWkc5dGFXNWhiblF0WW1GelpXeHBibVU5SW0xcFpHUnNaU0lnWm1sc2JEMGlkMmhwZEdVaUlIUmxlSFF0WVc1amFHOXlQU0p0YVdSa2JHVWlQbkIxYm1zdVpHOXRZV2x1Y3p3dmRHVjRkRDQ4TDNOMlp6ND0ifQ=="
+ ]}
- assert InstanceMetadataRetriever.fetch_json(data) ==
+ assert MetadataRetriever.fetch_json(data) ==
{:ok,
%{
metadata: %{
@@ -360,15 +235,13 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
end
test "decodes base64 encoded json file (with unicode string) in tokenURI" do
- data = %{
- "c87b56dd" =>
- {:ok,
- [
- "data:application/json;base64,eyJkZXNjcmlwdGlvbiI6ICJQdW5rIERvbWFpbnMgZGlnaXRhbCBpZGVudGl0eSDDry4gVmlzaXQgaHR0cHM6Ly9wdW5rLmRvbWFpbnMvIn0="
- ]}
- }
+ data =
+ {:ok,
+ [
+ "data:application/json;base64,eyJkZXNjcmlwdGlvbiI6ICJQdW5rIERvbWFpbnMgZGlnaXRhbCBpZGVudGl0eSDDry4gVmlzaXQgaHR0cHM6Ly9wdW5rLmRvbWFpbnMvIn0="
+ ]}
- assert InstanceMetadataRetriever.fetch_json(data) ==
+ assert MetadataRetriever.fetch_json(data) ==
{:ok,
%{
metadata: %{
@@ -390,20 +263,18 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
Conn.resp(conn, 200, json)
end)
- data = %{
- "c87b56dd" =>
- {:ok,
- [
- "http://localhost:#{bypass.port}#{path}"
- ]}
- }
+ data =
+ {:ok,
+ [
+ "http://localhost:#{bypass.port}#{path}"
+ ]}
assert {:ok,
%{
metadata: %{
"image" => "https://ipfs.io/ipfs/bafybeig6nlmyzui7llhauc52j2xo5hoy4lzp6442lkve5wysdvjkizxonu"
}
- }} == InstanceMetadataRetriever.fetch_json(data)
+ }} == MetadataRetriever.fetch_json(data)
end
test "Fetches metadata from ipfs", %{bypass: bypass} do
@@ -419,18 +290,16 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
Conn.resp(conn, 200, json)
end)
- data = %{
- "c87b56dd" =>
- {:ok,
- [
- "http://localhost:#{bypass.port}#{path}"
- ]}
- }
+ data =
+ {:ok,
+ [
+ "http://localhost:#{bypass.port}#{path}"
+ ]}
{:ok,
%{
metadata: metadata
- }} = InstanceMetadataRetriever.fetch_json(data)
+ }} = MetadataRetriever.fetch_json(data)
assert "ipfs://bafybeihxuj3gxk7x5p36amzootyukbugmx3pw7dyntsrohg3se64efkuga/51.png" == Map.get(metadata, "image")
end
@@ -438,13 +307,11 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
test "Fetches metadata from '${url}'", %{bypass: bypass} do
path = "/data/8/8578.json"
- data = %{
- "c87b56dd" =>
- {:ok,
- [
- "'http://localhost:#{bypass.port}#{path}'"
- ]}
- }
+ data =
+ {:ok,
+ [
+ "'http://localhost:#{bypass.port}#{path}'"
+ ]}
json = """
{
@@ -467,17 +334,15 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
assert {:ok,
%{
metadata: Jason.decode!(json)
- }} == InstanceMetadataRetriever.fetch_json(data)
+ }} == MetadataRetriever.fetch_json(data)
end
test "Process custom execution reverted" do
- data = %{
- "c87b56dd" =>
- {:error,
- "(3) execution reverted: Nonexistent token (0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000114e6f6e6578697374656e7420746f6b656e000000000000000000000000000000)"}
- }
+ data =
+ {:error,
+ "(3) execution reverted: Nonexistent token (0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000114e6f6e6578697374656e7420746f6b656e000000000000000000000000000000)"}
- assert {:ok, %{error: "VM execution error"}} == InstanceMetadataRetriever.fetch_json(data)
+ assert {:ok, %{error: "VM execution error"}} == MetadataRetriever.fetch_json(data)
end
test "Process CIDv0 IPFS links" do
@@ -507,7 +372,7 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
"name" => "asda",
"salePrice" => 34
}
- }} == InstanceMetadataRetriever.fetch_json(%{"0e89341c" => {:ok, [data]}})
+ }} == MetadataRetriever.fetch_json({:ok, [data]})
Application.put_env(:explorer, :http_adapter, HTTPoison)
end
@@ -553,54 +418,7 @@ defmodule Explorer.Token.InstanceMetadataRetrieverTest do
%{
metadata: Jason.decode!(json)
}} ==
- InstanceMetadataRetriever.fetch_json(%{"0e89341c" => {:ok, ["http://localhost:#{bypass.port}#{path}"]}})
- end
-
- test "fetch ipfs of ipfs/{id} format" do
- EthereumJSONRPC.Mox
- |> expect(:json_rpc, fn [
- %{
- id: 0,
- jsonrpc: "2.0",
- method: "eth_call",
- params: [
- %{
- data:
- "0xc87b56dd0000000000000000000000000000000000000000000000000000000000000000",
- to: "0x7e01CC81fCfdf6a71323900288A69e234C464f63"
- },
- "latest"
- ]
- }
- ],
- _options ->
- {:ok,
- [
- %{
- id: 0,
- jsonrpc: "2.0",
- result:
- "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000033697066732f516d6439707654684577676a544262456b4e6d6d47466263704a4b773137666e524241543454643472636f67323200000000000000000000000000"
- }
- ]}
- end)
-
- Application.put_env(:explorer, :http_adapter, Explorer.Mox.HTTPoison)
-
- Explorer.Mox.HTTPoison
- |> expect(:get, fn "https://ipfs.io/ipfs/Qmd9pvThEwgjTBbEkNmmGFbcpJKw17fnRBAT4Td4rcog22", _headers, _options ->
- {:ok, %HTTPoison.Response{status_code: 200, body: "123", headers: [{"Content-Type", "image/jpg"}]}}
- end)
-
- assert {:ok,
- %{
- metadata: %{
- "image" => "https://ipfs.io/ipfs/Qmd9pvThEwgjTBbEkNmmGFbcpJKw17fnRBAT4Td4rcog22"
- }
- }} ==
- InstanceMetadataRetriever.fetch_metadata("0x7e01CC81fCfdf6a71323900288A69e234C464f63", 0)
-
- Application.put_env(:explorer, :http_adapter, HTTPoison)
+ MetadataRetriever.fetch_json({:ok, ["http://localhost:#{bypass.port}#{path}"]})
end
end
end
diff --git a/apps/explorer/test/support/factory.ex b/apps/explorer/test/support/factory.ex
index 9c33824972eb..da2e13f6669d 100644
--- a/apps/explorer/test/support/factory.ex
+++ b/apps/explorer/test/support/factory.ex
@@ -142,14 +142,18 @@ defmodule Explorer.Factory do
def address_to_tag_factory do
%AddressToTag{
- tag: %AddressTag{
- label: sequence("label"),
- display_name: sequence("display_name")
- },
+ tag: build(:address_tag),
address: build(:address)
}
end
+ def address_tag_factory do
+ %AddressTag{
+ label: sequence("label"),
+ display_name: sequence("display_name")
+ }
+ end
+
def account_watchlist_address_factory do
hash = build(:address).hash
@@ -656,7 +660,8 @@ defmodule Explorer.Factory do
type: "ERC-20",
cataloged: true,
icon_url: sequence("https://example.com/icon"),
- fiat_value: 10.1
+ fiat_value: 10.1,
+ is_verified_via_admin_panel: Enum.random([true, false])
}
end
@@ -893,7 +898,23 @@ defmodule Explorer.Factory do
%CurrentTokenBalance{
address: build(:address),
- token_contract_address_hash: insert(:token).contract_address_hash,
+ token_contract_address_hash: insert(:token, type: token_type).contract_address_hash,
+ block_number: block_number(),
+ value: Enum.random(1_000_000_000_000_000_000..10_000_000_000_000_000_000),
+ value_fetched_at: DateTime.utc_now(),
+ token_id: token_id,
+ token_type: token_type
+ }
+ end
+
+ def address_current_token_balance_with_token_id_and_fixed_token_type_factory(%{
+ token_type: token_type,
+ address: address,
+ token_id: token_id
+ }) do
+ %CurrentTokenBalance{
+ address: address,
+ token_contract_address_hash: insert(:token, type: token_type).contract_address_hash,
block_number: block_number(),
value: Enum.random(1_000_000_000_000_000_000..10_000_000_000_000_000_000),
value_fetched_at: DateTime.utc_now(),
diff --git a/apps/explorer/test/support/fakes/no_op_price_source.ex b/apps/explorer/test/support/fakes/no_op_price_source.ex
new file mode 100644
index 000000000000..b9a460ac8876
--- /dev/null
+++ b/apps/explorer/test/support/fakes/no_op_price_source.ex
@@ -0,0 +1,12 @@
+defmodule Explorer.ExchangeRates.Source.NoOpPriceSource do
+ @moduledoc false
+
+ alias Explorer.Market.History.Source.Price, as: SourcePrice
+
+ @behaviour SourcePrice
+
+ @impl SourcePrice
+ def fetch_price_history(_previous_days) do
+ {:ok, []}
+ end
+end
diff --git a/apps/indexer/lib/indexer/application.ex b/apps/indexer/lib/indexer/application.ex
index e47f5deeed23..9984918e06f9 100644
--- a/apps/indexer/lib/indexer/application.ex
+++ b/apps/indexer/lib/indexer/application.ex
@@ -24,7 +24,13 @@ defmodule Indexer.Application do
json_rpc_named_arguments = Application.fetch_env!(:indexer, :json_rpc_named_arguments)
+ pool_size =
+ Application.get_env(:indexer, Indexer.Fetcher.TokenInstance.Retry)[:concurrency] +
+ Application.get_env(:indexer, Indexer.Fetcher.TokenInstance.Realtime)[:concurrency] +
+ Application.get_env(:indexer, Indexer.Fetcher.TokenInstance.Sanitize)[:concurrency]
+
base_children = [
+ :hackney_pool.child_spec(:token_instance_fetcher, max_connections: pool_size),
{Memory.Monitor, [memory_monitor_options, [name: memory_monitor_name]]},
{CoinBalanceOnDemand.Supervisor, [json_rpc_named_arguments]},
{TokenTotalSupplyOnDemand.Supervisor, []},
diff --git a/apps/indexer/lib/indexer/block/catchup/fetcher.ex b/apps/indexer/lib/indexer/block/catchup/fetcher.ex
index 6a7d63e8710d..3b5fcbbc31fa 100644
--- a/apps/indexer/lib/indexer/block/catchup/fetcher.ex
+++ b/apps/indexer/lib/indexer/block/catchup/fetcher.ex
@@ -55,7 +55,9 @@ defmodule Indexer.Block.Catchup.Fetcher do
shrunk: false
}
- missing_ranges ->
+ latest_missing_ranges ->
+ missing_ranges = filter_consensus_blocks(latest_missing_ranges)
+
first.._ = List.first(missing_ranges)
_..last = List.last(missing_ranges)
@@ -85,6 +87,21 @@ defmodule Indexer.Block.Catchup.Fetcher do
end
end
+ defp filter_consensus_blocks(ranges) do
+ filtered_ranges =
+ ranges
+ |> Enum.map(&Chain.missing_block_number_ranges(&1))
+ |> List.flatten()
+
+ consensus_blocks = ranges_to_numbers(ranges) -- ranges_to_numbers(filtered_ranges)
+
+ consensus_blocks
+ |> numbers_to_ranges()
+ |> MissingRangesManipulator.clear_batch()
+
+ filtered_ranges
+ end
+
@doc """
The number of blocks to request in one call to the JSONRPC. Defaults to
10. Block requests also include the transactions for those blocks. *These transactions
@@ -230,9 +247,6 @@ defmodule Indexer.Block.Catchup.Fetcher do
rescue
exception ->
Logger.error(fn -> [Exception.format(:error, exception, __STACKTRACE__), ?\n, ?\n, "Retrying."] end)
-
- push_back(sequence, range)
-
{:error, exception}
end
@@ -306,6 +320,12 @@ defmodule Indexer.Block.Catchup.Fetcher do
)
end
+ defp ranges_to_numbers(ranges) do
+ ranges
+ |> Enum.map(&Enum.to_list/1)
+ |> List.flatten()
+ end
+
defp put_memory_monitor(sequence_options, %__MODULE__{memory_monitor: nil}) when is_list(sequence_options),
do: sequence_options
diff --git a/apps/indexer/lib/indexer/block/fetcher.ex b/apps/indexer/lib/indexer/block/fetcher.ex
index d7b9be8d31e7..cffd739843bf 100644
--- a/apps/indexer/lib/indexer/block/fetcher.ex
+++ b/apps/indexer/lib/indexer/block/fetcher.ex
@@ -29,7 +29,7 @@ defmodule Indexer.Block.Fetcher do
UncleBlock
}
- alias Indexer.{Prometheus, Tracer}
+ alias Indexer.{Prometheus, TokenBalances, Tracer}
alias Indexer.Transform.{
AddressCoinBalances,
@@ -182,6 +182,9 @@ defmodule Indexer.Block.Fetcher do
address_coin_balances: %{params: coin_balances_params_set},
address_coin_balances_daily: %{params: coin_balances_params_daily_set},
address_token_balances: %{params: address_token_balances},
+ address_current_token_balances: %{
+ params: address_token_balances |> MapSet.to_list() |> TokenBalances.to_address_current_token_balances()
+ },
blocks: %{params: blocks},
block_second_degree_relations: %{params: block_second_degree_relations_params},
block_rewards: %{errors: beneficiaries_errors, params: beneficiaries_with_gas_payment},
diff --git a/apps/indexer/lib/indexer/block/realtime/fetcher.ex b/apps/indexer/lib/indexer/block/realtime/fetcher.ex
index 720672987370..1b3a8fcb74fc 100644
--- a/apps/indexer/lib/indexer/block/realtime/fetcher.ex
+++ b/apps/indexer/lib/indexer/block/realtime/fetcher.ex
@@ -30,6 +30,7 @@ defmodule Indexer.Block.Realtime.Fetcher do
alias Explorer.Chain.Cache.Accounts
alias Explorer.Chain.Events.Publisher
alias Explorer.Counters.AverageBlockTime
+ alias Explorer.Utility.MissingRangesManipulator
alias Indexer.{Block, Tracer}
alias Indexer.Block.Realtime.TaskSupervisor
alias Indexer.Fetcher.CoinBalance
@@ -310,6 +311,7 @@ defmodule Indexer.Block.Realtime.Fetcher do
case result do
{:ok, %{inserted: inserted, errors: []}} ->
log_import_timings(inserted, fetch_duration, time_before)
+ MissingRangesManipulator.clear_batch([block_number_to_fetch..block_number_to_fetch])
Logger.debug("Fetched and imported.")
{:ok, %{inserted: _, errors: [_ | _] = errors}} ->
diff --git a/apps/indexer/lib/indexer/fetcher/token.ex b/apps/indexer/lib/indexer/fetcher/token.ex
index 57b815a03e54..9d4b0dd253f3 100644
--- a/apps/indexer/lib/indexer/fetcher/token.ex
+++ b/apps/indexer/lib/indexer/fetcher/token.ex
@@ -14,12 +14,7 @@ defmodule Indexer.Fetcher.Token do
@behaviour BufferedTask
- @defaults [
- flush_interval: 300,
- max_batch_size: 1,
- max_concurrency: 10,
- task_supervisor: Indexer.Fetcher.Token.TaskSupervisor
- ]
+ @default_max_concurrency 10
@doc false
def child_spec([init_options, gen_server_options]) do
@@ -32,7 +27,7 @@ defmodule Indexer.Fetcher.Token do
end
merged_init_opts =
- @defaults
+ defaults()
|> Keyword.merge(mergeable_init_options)
|> Keyword.put(:state, state)
@@ -81,4 +76,13 @@ defmodule Indexer.Fetcher.Token do
{:ok, _} = Chain.update_token(token, token_params)
:ok
end
+
+ defp defaults do
+ [
+ flush_interval: 300,
+ max_batch_size: 1,
+ max_concurrency: Application.get_env(:indexer, __MODULE__)[:concurrency] || @default_max_concurrency,
+ task_supervisor: Indexer.Fetcher.Token.TaskSupervisor
+ ]
+ end
end
diff --git a/apps/indexer/lib/indexer/fetcher/token_balance.ex b/apps/indexer/lib/indexer/fetcher/token_balance.ex
index 9a40d88e6f0b..93add63827d2 100644
--- a/apps/indexer/lib/indexer/fetcher/token_balance.ex
+++ b/apps/indexer/lib/indexer/fetcher/token_balance.ex
@@ -26,6 +26,7 @@ defmodule Indexer.Fetcher.TokenBalance do
@behaviour BufferedTask
@default_max_batch_size 100
+ @default_max_concurrency 10
@max_retries 3
@@ -75,8 +76,7 @@ defmodule Indexer.Fetcher.TokenBalance do
token_balance
|> entry()
|> reducer.(acc)
- end,
- true
+ end
)
final
@@ -235,7 +235,7 @@ defmodule Indexer.Fetcher.TokenBalance do
[
flush_interval: 300,
max_batch_size: Application.get_env(:indexer, __MODULE__)[:batch_size] || @default_max_batch_size,
- max_concurrency: 10,
+ max_concurrency: Application.get_env(:indexer, __MODULE__)[:concurrency] || @default_max_concurrency,
task_supervisor: Indexer.Fetcher.TokenBalance.TaskSupervisor
]
end
diff --git a/apps/indexer/lib/indexer/fetcher/token_balance_on_demand.ex b/apps/indexer/lib/indexer/fetcher/token_balance_on_demand.ex
index 3f3c05bb7932..d1dfcf6d3364 100644
--- a/apps/indexer/lib/indexer/fetcher/token_balance_on_demand.ex
+++ b/apps/indexer/lib/indexer/fetcher/token_balance_on_demand.ex
@@ -9,15 +9,18 @@ defmodule Indexer.Fetcher.TokenBalanceOnDemand do
alias Explorer.Chain
alias Explorer.Chain.Address.CurrentTokenBalance
alias Explorer.Chain.Cache.BlockNumber
+ alias Explorer.Chain.Events.Publisher
alias Explorer.Chain.Hash
alias Explorer.Counters.AverageBlockTime
alias Explorer.Token.BalanceReader
alias Timex.Duration
+ require Logger
+
## Interface
- @spec trigger_fetch(Hash.t(), [CurrentTokenBalance.t()]) :: :ok
- def trigger_fetch(address_hash, current_token_balances) do
+ @spec trigger_fetch(Hash.t()) :: :ok
+ def trigger_fetch(address_hash) do
latest_block_number = latest_block_number()
case stale_balance_window(latest_block_number) do
@@ -25,7 +28,7 @@ defmodule Indexer.Fetcher.TokenBalanceOnDemand do
:current
stale_balance_window ->
- do_trigger_fetch(address_hash, current_token_balances, latest_block_number, stale_balance_window)
+ do_trigger_fetch(address_hash, latest_block_number, stale_balance_window)
end
end
@@ -36,7 +39,6 @@ defmodule Indexer.Fetcher.TokenBalanceOnDemand do
Decimal.t() | nil,
non_neg_integer()
) :: {:ok, pid}
-
def trigger_historic_fetch(address_hash, contract_address_hash, token_type, token_id, block_number) do
Task.start(fn ->
do_trigger_historic_fetch(address_hash, contract_address_hash, token_type, token_id, block_number)
@@ -45,10 +47,11 @@ defmodule Indexer.Fetcher.TokenBalanceOnDemand do
## Implementation
- defp do_trigger_fetch(address_hash, current_token_balances, latest_block_number, stale_balance_window)
+ defp do_trigger_fetch(address_hash, latest_block_number, stale_balance_window)
when not is_nil(address_hash) do
stale_current_token_balances =
- current_token_balances
+ address_hash
+ |> Chain.fetch_last_token_balances_include_unfetched()
|> Enum.filter(fn current_token_balance -> current_token_balance.block_number < stale_balance_window end)
if Enum.count(stale_current_token_balances) > 0 do
@@ -61,51 +64,101 @@ defmodule Indexer.Fetcher.TokenBalanceOnDemand do
end
defp fetch_and_update(block_number, address_hash, stale_current_token_balances) do
- current_token_balances_update_params =
+ %{erc_1155: erc_1155_ctbs, other: other_ctbs, tokens: tokens} =
stale_current_token_balances
- |> Enum.map(fn %{token_id: token_id} = stale_current_token_balance ->
- stale_current_token_balances_to_fetch = [
- %{
- token_contract_address_hash:
- "0x" <> Base.encode16(stale_current_token_balance.token.contract_address_hash.bytes),
- address_hash: "0x" <> Base.encode16(address_hash.bytes),
- block_number: block_number,
- token_id: token_id && Decimal.to_integer(token_id)
- }
- ]
-
- balance_response =
- case stale_current_token_balance.token_type do
- "ERC-1155" -> BalanceReader.get_balances_of_erc_1155(stale_current_token_balances_to_fetch)
- _ -> BalanceReader.get_balances_of(stale_current_token_balances_to_fetch)
+ |> Enum.reduce(%{erc_1155: [], other: [], tokens: %{}}, fn %{token_id: token_id} = stale_current_token_balance,
+ acc ->
+ prepared_ctb = %{
+ token_contract_address_hash:
+ "0x" <> Base.encode16(stale_current_token_balance.token.contract_address_hash.bytes),
+ address_hash: "0x" <> Base.encode16(address_hash.bytes),
+ block_number: block_number,
+ token_id: token_id && Decimal.to_integer(token_id),
+ token_type: stale_current_token_balance.token_type
+ }
+
+ updated_tokens =
+ Map.put_new(
+ acc[:tokens],
+ stale_current_token_balance.token.contract_address_hash.bytes,
+ stale_current_token_balance.token
+ )
+
+ result =
+ if stale_current_token_balance.token_type == "ERC-1155" do
+ Map.put(acc, :erc_1155, [prepared_ctb | acc[:erc_1155]])
+ else
+ Map.put(acc, :other, [prepared_ctb | acc[:other]])
end
- updated_balance = balance_response[:ok]
-
- if updated_balance do
- %{}
- |> Map.put(:address_hash, stale_current_token_balance.address_hash)
- |> Map.put(:token_contract_address_hash, stale_current_token_balance.token.contract_address_hash)
- |> Map.put(:token_type, stale_current_token_balance.token.type)
- |> Map.put(:token_id, token_id)
- |> Map.put(:block_number, block_number)
- |> Map.put(:value, Decimal.new(updated_balance))
- |> Map.put(:value_fetched_at, DateTime.utc_now())
- else
- nil
- end
+ Map.put(result, :tokens, updated_tokens)
end)
+ erc_1155_ctbs_reversed = Enum.reverse(erc_1155_ctbs)
+ other_ctbs_reversed = Enum.reverse(other_ctbs)
+
+ updated_erc_1155_ctbs =
+ if Enum.count(erc_1155_ctbs_reversed) > 0 do
+ erc_1155_ctbs_reversed
+ |> BalanceReader.get_balances_of_erc_1155()
+ |> Enum.zip(erc_1155_ctbs_reversed)
+ |> Enum.map(&prepare_updated_balance(&1, block_number))
+ else
+ []
+ end
+
+ updated_other_ctbs =
+ if Enum.count(other_ctbs_reversed) > 0 do
+ other_ctbs_reversed
+ |> BalanceReader.get_balances_of()
+ |> Enum.zip(other_ctbs_reversed)
+ |> Enum.map(&prepare_updated_balance(&1, block_number))
+ else
+ []
+ end
+
filtered_current_token_balances_update_params =
- current_token_balances_update_params
+ (updated_erc_1155_ctbs ++ updated_other_ctbs)
|> Enum.filter(&(!is_nil(&1)))
- Chain.import(%{
- address_current_token_balances: %{
- params: filtered_current_token_balances_update_params
+ {:ok,
+ %{
+ address_current_token_balances: imported_ctbs
+ }} =
+ Chain.import(%{
+ address_current_token_balances: %{
+ params: filtered_current_token_balances_update_params
+ },
+ broadcast: false
+ })
+
+ Publisher.broadcast(
+ %{
+ address_current_token_balances: %{
+ address_hash: to_string(address_hash),
+ address_current_token_balances:
+ imported_ctbs
+ |> Enum.map(fn ctb -> %CurrentTokenBalance{ctb | token: tokens[ctb.token_contract_address_hash.bytes]} end)
+ }
},
- broadcast: :on_demand
- })
+ :on_demand
+ )
+ end
+
+ defp prepare_updated_balance({{:ok, updated_balance}, stale_current_token_balance}, block_number) do
+ %{}
+ |> Map.put(:address_hash, stale_current_token_balance.address_hash)
+ |> Map.put(:token_contract_address_hash, stale_current_token_balance.token_contract_address_hash)
+ |> Map.put(:token_type, stale_current_token_balance.token_type)
+ |> Map.put(:token_id, stale_current_token_balance.token_id)
+ |> Map.put(:block_number, block_number)
+ |> Map.put(:value, Decimal.new(updated_balance))
+ |> Map.put(:value_fetched_at, DateTime.utc_now())
+ end
+
+ defp prepare_updated_balance({{:error, error}, _ctb}, _block_number) do
+ Logger.warn(fn -> ["Error on updating current token balance: ", inspect(error)] end)
+ nil
end
defp do_trigger_historic_fetch(address_hash, contract_address_hash, token_type, token_id, block_number) do
diff --git a/apps/indexer/lib/indexer/fetcher/token_instance/helper.ex b/apps/indexer/lib/indexer/fetcher/token_instance/helper.ex
index 57bc8ca37f58..e5e2256ff9eb 100644
--- a/apps/indexer/lib/indexer/fetcher/token_instance/helper.ex
+++ b/apps/indexer/lib/indexer/fetcher/token_instance/helper.ex
@@ -3,45 +3,171 @@ defmodule Indexer.Fetcher.TokenInstance.Helper do
Common functions for Indexer.Fetcher.TokenInstance fetchers
"""
alias Explorer.Chain
- alias Explorer.Chain.{Hash, Token.Instance}
- alias Explorer.Token.InstanceMetadataRetriever
-
- @spec fetch_instance(Hash.Address.t(), Decimal.t() | non_neg_integer()) :: {:ok, Instance.t()}
- def fetch_instance(token_contract_address_hash, token_id) do
- token_id = prepare_token_id(token_id)
-
- case InstanceMetadataRetriever.fetch_metadata(to_string(token_contract_address_hash), token_id) do
- {:ok, %{metadata: metadata}} ->
- params = %{
- token_id: token_id,
- token_contract_address_hash: token_contract_address_hash,
- metadata: metadata,
- error: nil
+ alias Explorer.SmartContract.Reader
+ alias Indexer.Fetcher.TokenInstance.MetadataRetriever
+
+ @cryptokitties_address_hash "0x06012c8cf97bead5deae237070f9587f8e7a266d"
+
+ @token_uri "c87b56dd"
+ @uri "0e89341c"
+
+ @erc_721_1155_abi [
+ %{
+ "type" => "function",
+ "stateMutability" => "view",
+ "payable" => false,
+ "outputs" => [
+ %{"type" => "string", "name" => ""}
+ ],
+ "name" => "tokenURI",
+ "inputs" => [
+ %{
+ "type" => "uint256",
+ "name" => "_tokenId"
+ }
+ ],
+ "constant" => true
+ },
+ %{
+ "type" => "function",
+ "stateMutability" => "view",
+ "payable" => false,
+ "outputs" => [
+ %{
+ "type" => "string",
+ "name" => "",
+ "internalType" => "string"
}
+ ],
+ "name" => "uri",
+ "inputs" => [
+ %{
+ "type" => "uint256",
+ "name" => "_id",
+ "internalType" => "uint256"
+ }
+ ],
+ "constant" => true
+ }
+ ]
+
+ @spec batch_fetch_instances([%{}]) :: list()
+ def batch_fetch_instances(token_instances) do
+ token_instances =
+ Enum.map(token_instances, fn
+ %{contract_address_hash: hash, token_id: token_id} -> {hash, token_id}
+ {_, _} = tuple -> tuple
+ end)
+
+ splitted =
+ Enum.group_by(token_instances, fn {contract_address_hash, _token_id} ->
+ to_string(contract_address_hash) == @cryptokitties_address_hash
+ end)
- {:ok, _result} = Chain.upsert_token_instance(params)
+ cryptokitties =
+ (splitted[true] || [])
+ |> Enum.map(fn {contract_address_hash, token_id} ->
+ {{:ok, ["https://api.cryptokitties.co/kitties/{id}"]}, to_string(token_id), contract_address_hash, token_id}
+ end)
- {:ok, %{error: error}} ->
- upsert_token_instance_with_error(token_id, token_contract_address_hash, error)
+ other = splitted[false] || []
- {:error_code, code} ->
- upsert_token_instance_with_error(token_id, token_contract_address_hash, "request error: #{code}")
+ token_types_map =
+ Enum.reduce(other, %{}, fn {contract_address_hash, _token_id}, acc ->
+ address_hash_string = to_string(contract_address_hash)
- {:error, reason} ->
- upsert_token_instance_with_error(token_id, token_contract_address_hash, reason)
- end
+ Map.put_new(acc, address_hash_string, Chain.get_token_type(contract_address_hash))
+ end)
+
+ contract_results =
+ (other
+ |> Enum.map(fn {contract_address_hash, token_id} ->
+ token_id = prepare_token_id(token_id)
+ contract_address_hash_string = to_string(contract_address_hash)
+
+ prepare_request(token_types_map[contract_address_hash_string], contract_address_hash_string, token_id)
+ end)
+ |> Reader.query_contracts(@erc_721_1155_abi, [], false)
+ |> Enum.zip_reduce(other, [], fn result, {contract_address_hash, token_id}, acc ->
+ token_id = prepare_token_id(token_id)
+
+ [
+ {result, normalize_token_id(token_types_map[to_string(contract_address_hash)], token_id),
+ contract_address_hash, token_id}
+ | acc
+ ]
+ end)
+ |> Enum.reverse()) ++
+ cryptokitties
+
+ contract_results
+ |> Enum.map(fn {result, normalized_token_id, _contract_address_hash, _token_id} ->
+ Task.async(fn -> MetadataRetriever.fetch_json(result, normalized_token_id) end)
+ end)
+ |> Task.yield_many(:infinity)
+ |> Enum.zip(contract_results)
+ |> Enum.map(fn {{_task, res}, {_result, _normalized_token_id, contract_address_hash, token_id}} ->
+ case res do
+ {:ok, result} ->
+ result_to_insert_params(result, contract_address_hash, token_id)
+
+ {:exit, reason} ->
+ result_to_insert_params(
+ {:error, MetadataRetriever.truncate_error("Terminated:" <> inspect(reason))},
+ contract_address_hash,
+ token_id
+ )
+ end
+ end)
+ |> Chain.upsert_token_instances_list()
end
defp prepare_token_id(%Decimal{} = token_id), do: Decimal.to_integer(token_id)
defp prepare_token_id(token_id), do: token_id
- defp upsert_token_instance_with_error(token_id, token_contract_address_hash, error) do
- params = %{
+ defp prepare_request("ERC-721", contract_address_hash_string, token_id) do
+ %{
+ contract_address: contract_address_hash_string,
+ method_id: @token_uri,
+ args: [token_id],
+ block_number: nil
+ }
+ end
+
+ defp prepare_request(_token_type, contract_address_hash_string, token_id) do
+ %{
+ contract_address: contract_address_hash_string,
+ method_id: @uri,
+ args: [token_id],
+ block_number: nil
+ }
+ end
+
+ defp normalize_token_id("ERC-721", _token_id), do: nil
+
+ defp normalize_token_id(_token_type, token_id),
+ do: token_id |> Integer.to_string(16) |> String.downcase() |> String.pad_leading(64, "0")
+
+ defp result_to_insert_params({:ok, %{metadata: metadata}}, token_contract_address_hash, token_id) do
+ %{
token_id: token_id,
token_contract_address_hash: token_contract_address_hash,
- error: error
+ metadata: metadata,
+ error: nil
}
+ end
+
+ defp result_to_insert_params({:error_code, code}, token_contract_address_hash, token_id),
+ do: token_instance_map_with_error(token_id, token_contract_address_hash, "request error: #{code}")
- {:ok, _result} = Chain.upsert_token_instance(params)
+ defp result_to_insert_params({:error, reason}, token_contract_address_hash, token_id),
+ do: token_instance_map_with_error(token_id, token_contract_address_hash, reason)
+
+ defp token_instance_map_with_error(token_id, token_contract_address_hash, error) do
+ %{
+ token_id: token_id,
+ token_contract_address_hash: token_contract_address_hash,
+ error: error
+ }
end
end
diff --git a/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex b/apps/indexer/lib/indexer/fetcher/token_instance/metadata_retriever.ex
similarity index 76%
rename from apps/explorer/lib/explorer/token/instance_metadata_retriever.ex
rename to apps/indexer/lib/indexer/fetcher/token_instance/metadata_retriever.ex
index 6967a756aed3..89c383f5a5d0 100644
--- a/apps/explorer/lib/explorer/token/instance_metadata_retriever.ex
+++ b/apps/indexer/lib/indexer/fetcher/token_instance/metadata_retriever.ex
@@ -1,6 +1,6 @@
-defmodule Explorer.Token.InstanceMetadataRetriever do
+defmodule Indexer.Fetcher.TokenInstance.MetadataRetriever do
@moduledoc """
- Fetches ERC721 token instance metadata.
+ Fetches ERC-721 & ERC-1155 token instance metadata.
"""
require Logger
@@ -8,55 +8,6 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
alias Explorer.SmartContract.Reader
alias HTTPoison.{Error, Response}
- @token_uri "c87b56dd"
-
- @abi [
- %{
- "type" => "function",
- "stateMutability" => "view",
- "payable" => false,
- "outputs" => [
- %{"type" => "string", "name" => ""}
- ],
- "name" => "tokenURI",
- "inputs" => [
- %{
- "type" => "uint256",
- "name" => "_tokenId"
- }
- ],
- "constant" => true
- }
- ]
-
- @uri "0e89341c"
-
- @abi_uri [
- %{
- "type" => "function",
- "stateMutability" => "view",
- "payable" => false,
- "outputs" => [
- %{
- "type" => "string",
- "name" => "",
- "internalType" => "string"
- }
- ],
- "name" => "uri",
- "inputs" => [
- %{
- "type" => "uint256",
- "name" => "_id",
- "internalType" => "uint256"
- }
- ],
- "constant" => true
- }
- ]
-
- @cryptokitties_address_hash "0x06012c8cf97bead5deae237070f9587f8e7a266d"
-
@no_uri_error "no uri"
@vm_execution_error "VM execution error"
@ipfs_protocol "ipfs://"
@@ -69,54 +20,29 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
@ignored_hosts ["localhost", "127.0.0.1", "0.0.0.0", "", nil]
- def fetch_metadata(unquote(@cryptokitties_address_hash), token_id) do
- %{@token_uri => {:ok, ["https://api.cryptokitties.co/kitties/{id}"]}}
- |> fetch_json(to_string(token_id))
- end
-
- def fetch_metadata(contract_address_hash, token_id) do
- # c87b56dd = keccak256(tokenURI(uint256))
- contract_functions = %{@token_uri => [token_id]}
-
- res =
- contract_address_hash
- |> query_contract(contract_functions, @abi)
- |> fetch_json()
-
- if res == {:ok, %{error: @vm_execution_error}} do
- hex_normalized_token_id = token_id |> Integer.to_string(16) |> String.downcase() |> String.pad_leading(64, "0")
-
- contract_functions_uri = %{@uri => [token_id]}
-
- contract_address_hash
- |> query_contract(contract_functions_uri, @abi_uri)
- |> fetch_json(hex_normalized_token_id)
- else
- res
- end
- end
-
def query_contract(contract_address_hash, contract_functions, abi) do
Reader.query_contract(contract_address_hash, abi, contract_functions, false)
end
+ @doc """
+ Fetch/parse metadata using smart-contract's response
+ """
+ @spec fetch_json(any, binary() | nil) :: {:error, binary} | {:error_code, any} | {:ok, %{metadata: any}}
def fetch_json(uri, hex_token_id \\ nil)
- def fetch_json(uri, _hex_token_id) when uri in [%{@token_uri => {:ok, [""]}}, %{@uri => {:ok, [""]}}] do
- {:ok, %{error: @no_uri_error}}
- end
-
- def fetch_json(%{@token_uri => uri}, hex_token_id) do
- fetch_json_from_uri(uri, hex_token_id)
+ def fetch_json(uri, _hex_token_id) when uri in [{:ok, [""]}, {:ok, [""]}] do
+ {:error, @no_uri_error}
end
- def fetch_json(%{@uri => uri}, hex_token_id) do
+ def fetch_json(uri, hex_token_id) do
fetch_json_from_uri(uri, hex_token_id)
end
defp fetch_json_from_uri({:error, error}, _hex_token_id) do
+ error = to_string(error)
+
if error =~ "execution reverted" or error =~ @vm_execution_error do
- {:ok, %{error: @vm_execution_error}}
+ {:error, @vm_execution_error}
else
Logger.debug(["Unknown metadata format error #{inspect(error)}."], fetcher: :token_instances)
@@ -245,7 +171,8 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
def fetch_metadata_from_uri_inner(uri, hex_token_id) do
case Application.get_env(:explorer, :http_adapter).get(uri, [],
recv_timeout: 30_000,
- follow_redirect: true
+ follow_redirect: true,
+ hackney: [pool: :token_instance_fetcher]
) do
{:ok, %Response{body: body, status_code: 200, headers: headers}} ->
content_type = get_content_type_from_headers(headers)
@@ -350,5 +277,9 @@ defmodule Explorer.Token.InstanceMetadataRetriever do
String.replace(token_uri, @erc1155_token_id_placeholder, hex_token_id)
end
- defp truncate_error(error), do: String.slice(error, 0, @max_error_length)
+ @doc """
+ Truncate error string to @max_error_length symbols
+ """
+ @spec truncate_error(binary()) :: binary()
+ def truncate_error(error), do: String.slice(error, 0, @max_error_length)
end
diff --git a/apps/indexer/lib/indexer/fetcher/token_instance/realtime.ex b/apps/indexer/lib/indexer/fetcher/token_instance/realtime.ex
index 3f82494b55b6..804c9258c851 100644
--- a/apps/indexer/lib/indexer/fetcher/token_instance/realtime.ex
+++ b/apps/indexer/lib/indexer/fetcher/token_instance/realtime.ex
@@ -32,10 +32,12 @@ defmodule Indexer.Fetcher.TokenInstance.Realtime do
end
@impl BufferedTask
- def run([%{contract_address_hash: hash, token_id: token_id}], _json_rpc_named_arguments) do
- if not Chain.token_instance_exists?(token_id, hash) do
- fetch_instance(hash, token_id)
- end
+ def run(token_instances, _) when is_list(token_instances) do
+ token_instances
+ |> Enum.filter(fn %{contract_address_hash: hash, token_id: token_id} ->
+ not Chain.token_instance_exists?(token_id, hash)
+ end)
+ |> batch_fetch_instances()
:ok
end
@@ -75,7 +77,7 @@ defmodule Indexer.Fetcher.TokenInstance.Realtime do
[
flush_interval: 100,
max_concurrency: Application.get_env(:indexer, __MODULE__)[:concurrency] || @default_max_concurrency,
- max_batch_size: @default_max_batch_size,
+ max_batch_size: Application.get_env(:indexer, __MODULE__)[:batch_size] || @default_max_batch_size,
poll: false,
task_supervisor: __MODULE__.TaskSupervisor
]
diff --git a/apps/indexer/lib/indexer/fetcher/token_instance/retry.ex b/apps/indexer/lib/indexer/fetcher/token_instance/retry.ex
index 24b2df433f81..a09bce459698 100644
--- a/apps/indexer/lib/indexer/fetcher/token_instance/retry.ex
+++ b/apps/indexer/lib/indexer/fetcher/token_instance/retry.ex
@@ -13,7 +13,7 @@ defmodule Indexer.Fetcher.TokenInstance.Retry do
@behaviour BufferedTask
- @default_max_batch_size 1
+ @default_max_batch_size 10
@default_max_concurrency 10
@doc false
@@ -40,14 +40,16 @@ defmodule Indexer.Fetcher.TokenInstance.Retry do
end
@impl BufferedTask
- def run([%{contract_address_hash: hash, token_id: token_id, updated_at: updated_at}], _json_rpc_named_arguments) do
+ def run(token_instances, _json_rpc_named_arguments) when is_list(token_instances) do
refetch_interval = Application.get_env(:indexer, __MODULE__)[:refetch_interval]
- if updated_at
- |> DateTime.add(refetch_interval, :millisecond)
- |> DateTime.compare(DateTime.utc_now()) != :gt do
- fetch_instance(hash, token_id)
- end
+ token_instances
+ |> Enum.filter(fn %{contract_address_hash: _hash, token_id: _token_id, updated_at: updated_at} ->
+ updated_at
+ |> DateTime.add(refetch_interval, :millisecond)
+ |> DateTime.compare(DateTime.utc_now()) != :gt
+ end)
+ |> batch_fetch_instances()
:ok
end
@@ -56,7 +58,7 @@ defmodule Indexer.Fetcher.TokenInstance.Retry do
[
flush_interval: :timer.minutes(10),
max_concurrency: Application.get_env(:indexer, __MODULE__)[:concurrency] || @default_max_concurrency,
- max_batch_size: @default_max_batch_size,
+ max_batch_size: Application.get_env(:indexer, __MODULE__)[:batch_size] || @default_max_batch_size,
task_supervisor: __MODULE__.TaskSupervisor
]
end
diff --git a/apps/indexer/lib/indexer/fetcher/token_instance/sanitize.ex b/apps/indexer/lib/indexer/fetcher/token_instance/sanitize.ex
index 31c594ec0055..1bc3a70bd1f1 100644
--- a/apps/indexer/lib/indexer/fetcher/token_instance/sanitize.ex
+++ b/apps/indexer/lib/indexer/fetcher/token_instance/sanitize.ex
@@ -13,7 +13,7 @@ defmodule Indexer.Fetcher.TokenInstance.Sanitize do
@behaviour BufferedTask
- @default_max_batch_size 1
+ @default_max_batch_size 10
@default_max_concurrency 10
@doc false
def child_spec([init_options, gen_server_options]) do
@@ -36,10 +36,12 @@ defmodule Indexer.Fetcher.TokenInstance.Sanitize do
end
@impl BufferedTask
- def run([%{contract_address_hash: hash, token_id: token_id}], _json_rpc_named_arguments) do
- if not Chain.token_instance_exists?(token_id, hash) do
- fetch_instance(hash, token_id)
- end
+ def run(token_instances, _) when is_list(token_instances) do
+ token_instances
+ |> Enum.filter(fn %{contract_address_hash: hash, token_id: token_id} ->
+ not Chain.token_instance_exists?(token_id, hash)
+ end)
+ |> batch_fetch_instances()
:ok
end
@@ -48,7 +50,7 @@ defmodule Indexer.Fetcher.TokenInstance.Sanitize do
[
flush_interval: :infinity,
max_concurrency: Application.get_env(:indexer, __MODULE__)[:concurrency] || @default_max_concurrency,
- max_batch_size: @default_max_batch_size,
+ max_batch_size: Application.get_env(:indexer, __MODULE__)[:batch_size] || @default_max_batch_size,
poll: false,
task_supervisor: __MODULE__.TaskSupervisor
]
diff --git a/apps/indexer/lib/indexer/transform/address_token_balances.ex b/apps/indexer/lib/indexer/transform/address_token_balances.ex
index 3dc7b5be525d..cae8b2cbac7b 100644
--- a/apps/indexer/lib/indexer/transform/address_token_balances.ex
+++ b/apps/indexer/lib/indexer/transform/address_token_balances.ex
@@ -3,7 +3,7 @@ defmodule Indexer.Transform.AddressTokenBalances do
Extracts `Explorer.Address.TokenBalance` params from other schema's params.
"""
- @burn_address "0x0000000000000000000000000000000000000000"
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
def params_set(%{} = import_options) do
Enum.reduce(import_options, MapSet.new(), &reducer/2)
@@ -35,7 +35,7 @@ defmodule Indexer.Transform.AddressTokenBalances do
Enum.filter(token_transfers_params, &do_filter_burn_address/1)
end
- defp add_token_balance_address(map_set, unquote(@burn_address), _, _, _, _), do: map_set
+ defp add_token_balance_address(map_set, unquote(burn_address_hash_string()), _, _, _, _), do: map_set
defp add_token_balance_address(map_set, address, token_contract_address, token_id, token_type, block_number) do
MapSet.put(map_set, %{
@@ -47,7 +47,7 @@ defmodule Indexer.Transform.AddressTokenBalances do
})
end
- def do_filter_burn_address(%{to_address_hash: unquote(@burn_address), token_type: "ERC-721"}) do
+ def do_filter_burn_address(%{to_address_hash: unquote(burn_address_hash_string()), token_type: "ERC-721"}) do
false
end
diff --git a/apps/indexer/lib/indexer/transform/token_transfers.ex b/apps/indexer/lib/indexer/transform/token_transfers.ex
index 80d153d0f2cc..f5c3e3cabf06 100644
--- a/apps/indexer/lib/indexer/transform/token_transfers.ex
+++ b/apps/indexer/lib/indexer/transform/token_transfers.ex
@@ -5,13 +5,13 @@ defmodule Indexer.Transform.TokenTransfers do
require Logger
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
+
alias ABI.TypeDecoder
alias Explorer.Repo
alias Explorer.Chain.{Token, TokenTransfer}
alias Indexer.Fetcher.TokenTotalSupplyUpdater
- @burn_address "0x0000000000000000000000000000000000000000"
-
@doc """
Returns a list of token transfers given a list of logs.
"""
@@ -51,7 +51,8 @@ defmodule Indexer.Transform.TokenTransfers do
token_transfers
|> Enum.filter(fn token_transfer ->
- token_transfer.to_address_hash == @burn_address || token_transfer.from_address_hash == @burn_address
+ token_transfer.to_address_hash == burn_address_hash_string() ||
+ token_transfer.from_address_hash == burn_address_hash_string()
end)
|> Enum.map(fn token_transfer ->
token_transfer.token_contract_address_hash
@@ -177,9 +178,9 @@ defmodule Indexer.Transform.TokenTransfers do
{from_address_hash, to_address_hash} =
if log.first_topic == TokenTransfer.weth_deposit_signature() do
- {@burn_address, truncate_address_hash(log.second_topic)}
+ {burn_address_hash_string(), truncate_address_hash(log.second_topic)}
else
- {truncate_address_hash(log.second_topic), @burn_address}
+ {truncate_address_hash(log.second_topic), burn_address_hash_string()}
end
token_transfer = %{
@@ -315,7 +316,7 @@ defmodule Indexer.Transform.TokenTransfers do
{token, token_transfer}
end
- defp truncate_address_hash(nil), do: "0x0000000000000000000000000000000000000000"
+ defp truncate_address_hash(nil), do: burn_address_hash_string()
defp truncate_address_hash("0x000000000000000000000000" <> truncated_hash) do
"0x#{truncated_hash}"
diff --git a/apps/indexer/lib/indexer/transform/transaction_actions.ex b/apps/indexer/lib/indexer/transform/transaction_actions.ex
index 549be9fa80cb..d22274decd98 100644
--- a/apps/indexer/lib/indexer/transform/transaction_actions.ex
+++ b/apps/indexer/lib/indexer/transform/transaction_actions.ex
@@ -6,6 +6,7 @@ defmodule Indexer.Transform.TransactionActions do
require Logger
import Ecto.Query, only: [from: 2]
+ import Explorer.Chain.SmartContract, only: [burn_address_hash_string: 0]
alias ABI.TypeDecoder
alias Explorer.Chain.Cache.NetVersion
@@ -18,10 +19,10 @@ defmodule Indexer.Transform.TransactionActions do
@goerli 5
@optimism 10
@polygon 137
+ @base_mainnet 8453
@base_goerli 84531
# @gnosis 100
- @burn_address "0x0000000000000000000000000000000000000000"
@uniswap_v3_factory_abi [
%{
"inputs" => [
@@ -161,7 +162,7 @@ defmodule Indexer.Transform.TransactionActions do
end
defp parse_uniswap_v3(logs, actions, protocols_to_rewrite, chain_id) do
- if Enum.member?([@mainnet, @goerli, @optimism, @polygon, @base_goerli], chain_id) and
+ if Enum.member?([@mainnet, @goerli, @optimism, @polygon, @base_mainnet, @base_goerli], chain_id) and
(is_nil(protocols_to_rewrite) or Enum.empty?(protocols_to_rewrite) or
Enum.member?(protocols_to_rewrite, "uniswap_v3")) do
uniswap_v3_positions_nft =
@@ -449,7 +450,7 @@ defmodule Indexer.Transform.TransactionActions do
from = truncate_address_hash(log.second_topic)
# credo:disable-for-next-line
- if from == @burn_address do
+ if from == burn_address_hash_string() do
to = truncate_address_hash(log.third_topic)
[token_id] = decode_data(log.fourth_topic, [{:uint, 256}])
mint_nft_ids = Map.put_new(acc, to, %{ids: [], log_index: log.index})
@@ -650,8 +651,8 @@ defmodule Indexer.Transform.TransactionActions do
end
end)
|> Enum.map(fn {pool_address, pool} ->
- token0 = if is_address_correct?(pool.token0), do: String.downcase(pool.token0), else: @burn_address
- token1 = if is_address_correct?(pool.token1), do: String.downcase(pool.token1), else: @burn_address
+ token0 = if is_address_correct?(pool.token0), do: String.downcase(pool.token0), else: burn_address_hash_string()
+ token1 = if is_address_correct?(pool.token1), do: String.downcase(pool.token1), else: burn_address_hash_string()
fee = if pool.fee == "", do: 0, else: pool.fee
# we will call getPool(token0, token1, fee) public getter
@@ -998,7 +999,7 @@ defmodule Indexer.Transform.TransactionActions do
if is_nil(first_topic), do: "", else: String.downcase(first_topic)
end
- defp truncate_address_hash(nil), do: @burn_address
+ defp truncate_address_hash(nil), do: burn_address_hash_string()
defp truncate_address_hash("0x000000000000000000000000" <> truncated_hash) do
"0x#{truncated_hash}"
diff --git a/apps/indexer/mix.exs b/apps/indexer/mix.exs
index b24c16733a2e..444a7a27e772 100644
--- a/apps/indexer/mix.exs
+++ b/apps/indexer/mix.exs
@@ -14,7 +14,7 @@ defmodule Indexer.MixProject do
elixirc_paths: elixirc_paths(Mix.env()),
lockfile: "../../mix.lock",
start_permanent: Mix.env() == :prod,
- version: "5.2.1"
+ version: "5.2.2"
]
end
diff --git a/apps/indexer/test/indexer/fetcher/token_instance/helper_test.exs b/apps/indexer/test/indexer/fetcher/token_instance/helper_test.exs
new file mode 100644
index 000000000000..8d9987f9de24
--- /dev/null
+++ b/apps/indexer/test/indexer/fetcher/token_instance/helper_test.exs
@@ -0,0 +1,178 @@
+defmodule Indexer.Fetcher.TokenInstance.HelperTest do
+ use EthereumJSONRPC.Case
+ use Explorer.DataCase
+
+ alias Explorer.Chain.Token.Instance
+ alias EthereumJSONRPC.Encoder
+ alias Indexer.Fetcher.TokenInstance.Helper
+ alias Plug.Conn
+
+ import Mox
+
+ setup :verify_on_exit!
+ setup :set_mox_global
+
+ setup do
+ bypass = Bypass.open()
+
+ {:ok, bypass: bypass}
+ end
+
+ describe "fetch instance tests" do
+ test "fetches json metadata for kitties" do
+ Application.put_env(:explorer, :http_adapter, Explorer.Mox.HTTPoison)
+
+ result =
+ "{\"id\":100500,\"name\":\"KittyBlue_2_Lemonade\",\"generation\":20,\"genes\":\"623509754227292470437941473598751240781530569131665917719736997423495595\",\"created_at\":\"2017-12-06T01:56:27.000Z\",\"birthday\":\"2017-12-06T00:00:00.000Z\",\"image_url\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/100500.svg\",\"image_url_cdn\":\"https://img.cn.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/100500.svg\",\"color\":\"strawberry\",\"background_color\":\"#ffe0e5\",\"bio\":\"Shalom! I'm KittyBlue_2_Lemonade. I'm a professional Foreign Film Director and I love cantaloupe. I'm convinced that the world is flat. One day I'll prove it. It's pawesome to meet you!\",\"kitty_type\":null,\"is_fancy\":false,\"is_exclusive\":false,\"is_special_edition\":false,\"fancy_type\":null,\"language\":\"en\",\"is_prestige\":false,\"prestige_type\":null,\"prestige_ranking\":null,\"prestige_time_limit\":null,\"status\":{\"is_ready\":true,\"is_gestating\":false,\"cooldown\":1410310201506,\"dynamic_cooldown\":1475064986478,\"cooldown_index\":10,\"cooldown_end_block\":0,\"pending_tx_type\":null,\"pending_tx_since\":null},\"purrs\":{\"count\":1,\"is_purred\":false},\"watchlist\":{\"count\":0,\"is_watchlisted\":false},\"hatcher\":{\"address\":\"0x7b9ea9ac69b8fde875554321472c732eeff06ca0\",\"image\":\"14\",\"nickname\":\"KittyBlu\",\"hasDapper\":false,\"twitter_id\":null,\"twitter_image_url\":null,\"twitter_handle\":null},\"auction\":{},\"offer\":{},\"owner\":{\"address\":\"0x7b9ea9ac69b8fde875554321472c732eeff06ca0\",\"hasDapper\":false,\"twitter_id\":null,\"twitter_image_url\":null,\"twitter_handle\":null,\"image\":\"14\",\"nickname\":\"KittyBlu\"},\"matron\":{\"id\":46234,\"name\":\"KittyBlue_1_Limegreen\",\"generation\":10,\"enhanced_cattributes\":[{\"type\":\"body\",\"kittyId\":19631,\"position\":105,\"description\":\"cymric\"},{\"type\":\"coloreyes\",\"kittyId\":40356,\"position\":263,\"description\":\"limegreen\"},{\"type\":\"eyes\",\"kittyId\":3185,\"position\":16,\"description\":\"raisedbrow\"},{\"type\":\"pattern\",\"kittyId\":46234,\"position\":-1,\"description\":\"totesbasic\"},{\"type\":\"mouth\",\"kittyId\":46234,\"position\":-1,\"description\":\"happygokitty\"},{\"type\":\"colorprimary\",\"kittyId\":46234,\"position\":-1,\"description\":\"greymatter\"},{\"type\":\"colorsecondary\",\"kittyId\":46234,\"position\":-1,\"description\":\"lemonade\"},{\"type\":\"colortertiary\",\"kittyId\":46234,\"position\":-1,\"description\":\"granitegrey\"}],\"owner_wallet_address\":\"0x7b9ea9ac69b8fde875554321472c732eeff06ca0\",\"owner\":{\"address\":\"0x7b9ea9ac69b8fde875554321472c732eeff06ca0\"},\"created_at\":\"2017-12-03T21:29:17.000Z\",\"image_url\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/46234.svg\",\"image_url_cdn\":\"https://img.cn.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/46234.svg\",\"color\":\"limegreen\",\"is_fancy\":false,\"kitty_type\":null,\"is_exclusive\":false,\"is_special_edition\":false,\"fancy_type\":null,\"status\":{\"is_ready\":true,\"is_gestating\":false,\"cooldown\":1486487069384},\"hatched\":true,\"wrapped\":false,\"image_url_png\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/46234.png\"},\"sire\":{\"id\":82090,\"name\":null,\"generation\":19,\"enhanced_cattributes\":[{\"type\":\"body\",\"kittyId\":82090,\"position\":-1,\"description\":\"himalayan\"},{\"type\":\"coloreyes\",\"kittyId\":82090,\"position\":-1,\"description\":\"strawberry\"},{\"type\":\"eyes\",\"kittyId\":82090,\"position\":-1,\"description\":\"thicccbrowz\"},{\"type\":\"pattern\",\"kittyId\":82090,\"position\":-1,\"description\":\"totesbasic\"},{\"type\":\"mouth\",\"kittyId\":82090,\"position\":-1,\"description\":\"pouty\"},{\"type\":\"colorprimary\",\"kittyId\":82090,\"position\":-1,\"description\":\"aquamarine\"},{\"type\":\"colorsecondary\",\"kittyId\":82090,\"position\":-1,\"description\":\"chocolate\"},{\"type\":\"colortertiary\",\"kittyId\":82090,\"position\":-1,\"description\":\"granitegrey\"}],\"owner_wallet_address\":\"0x798fdad0cedc4b298fc7d53a982fa0c5f447eaa5\",\"owner\":{\"address\":\"0x798fdad0cedc4b298fc7d53a982fa0c5f447eaa5\"},\"created_at\":\"2017-12-05T06:30:05.000Z\",\"image_url\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/82090.svg\",\"image_url_cdn\":\"https://img.cn.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/82090.svg\",\"color\":\"strawberry\",\"is_fancy\":false,\"is_exclusive\":false,\"is_special_edition\":false,\"fancy_type\":null,\"status\":{\"is_ready\":true,\"is_gestating\":false,\"cooldown\":1486619010030},\"kitty_type\":null,\"hatched\":true,\"wrapped\":false,\"image_url_png\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/82090.png\"},\"children\":[],\"hatched\":true,\"wrapped\":false,\"enhanced_cattributes\":[{\"type\":\"colorprimary\",\"description\":\"greymatter\",\"position\":null,\"kittyId\":100500},{\"type\":\"coloreyes\",\"description\":\"strawberry\",\"position\":null,\"kittyId\":100500},{\"type\":\"body\",\"description\":\"himalayan\",\"position\":null,\"kittyId\":100500},{\"type\":\"colorsecondary\",\"description\":\"lemonade\",\"position\":null,\"kittyId\":100500},{\"type\":\"mouth\",\"description\":\"pouty\",\"position\":null,\"kittyId\":100500},{\"type\":\"pattern\",\"description\":\"totesbasic\",\"position\":null,\"kittyId\":100500},{\"type\":\"eyes\",\"description\":\"thicccbrowz\",\"position\":null,\"kittyId\":100500},{\"type\":\"colortertiary\",\"description\":\"kittencream\",\"position\":null,\"kittyId\":100500},{\"type\":\"secret\",\"description\":\"se5\",\"position\":-1,\"kittyId\":100500},{\"type\":\"purrstige\",\"description\":\"pu20\",\"position\":-1,\"kittyId\":100500}],\"variation\":null,\"variation_ranking\":null,\"image_url_png\":\"https://img.cryptokitties.co/0x06012c8cf97bead5deae237070f9587f8e7a266d/100500.png\",\"items\":[]}"
+
+ Explorer.Mox.HTTPoison
+ |> expect(:get, fn "https://api.cryptokitties.co/kitties/100500", _headers, _options ->
+ {:ok, %HTTPoison.Response{status_code: 200, body: result}}
+ end)
+
+ insert(:token,
+ contract_address: build(:address, hash: "0x06012c8cf97bead5deae237070f9587f8e7a266d"),
+ type: "ERC-721"
+ )
+
+ [{:ok, %Instance{metadata: metadata}}] =
+ Helper.batch_fetch_instances([{"0x06012c8cf97bead5deae237070f9587f8e7a266d", 100_500}])
+
+ assert Map.get(metadata, "name") == "KittyBlue_2_Lemonade"
+
+ Application.put_env(:explorer, :http_adapter, HTTPoison)
+ end
+
+ test "replace {id} with actual token_id", %{bypass: bypass} do
+ json = """
+ {
+ "name": "Sérgio Mendonça {id}"
+ }
+ """
+
+ abi =
+ [
+ %{
+ "type" => "function",
+ "stateMutability" => "nonpayable",
+ "payable" => false,
+ "outputs" => [],
+ "name" => "tokenURI",
+ "inputs" => [
+ %{"type" => "string", "name" => "name", "internalType" => "string"}
+ ]
+ }
+ ]
+ |> ABI.parse_specification()
+ |> Enum.at(0)
+
+ encoded_url =
+ abi
+ |> Encoder.encode_function_call(["http://localhost:#{bypass.port}/api/card/{id}"])
+ |> String.replace("4cf12d26", "")
+
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_call",
+ params: [
+ %{
+ data:
+ "0x0e89341c0000000000000000000000000000000000000000000000000000000000000309",
+ to: "0x5caebd3b32e210e85ce3e9d51638b9c445481567"
+ },
+ "latest"
+ ]
+ }
+ ],
+ _options ->
+ {:ok,
+ [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result: encoded_url
+ }
+ ]}
+ end)
+
+ Bypass.expect(
+ bypass,
+ "GET",
+ "/api/card/0000000000000000000000000000000000000000000000000000000000000309",
+ fn conn ->
+ Conn.resp(conn, 200, json)
+ end
+ )
+
+ insert(:token,
+ contract_address: build(:address, hash: "0x5caebd3b32e210e85ce3e9d51638b9c445481567"),
+ type: "ERC-1155"
+ )
+
+ assert [
+ {:ok,
+ %Instance{
+ metadata: %{
+ "name" => "Sérgio Mendonça 0000000000000000000000000000000000000000000000000000000000000309"
+ }
+ }}
+ ] = Helper.batch_fetch_instances([{"0x5caebd3b32e210e85ce3e9d51638b9c445481567", 777}])
+ end
+
+ test "fetch ipfs of ipfs/{id} format" do
+ EthereumJSONRPC.Mox
+ |> expect(:json_rpc, fn [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ method: "eth_call",
+ params: [
+ %{
+ data:
+ "0xc87b56dd0000000000000000000000000000000000000000000000000000000000000000",
+ to: "0x7e01CC81fCfdf6a71323900288A69e234C464f63"
+ },
+ "latest"
+ ]
+ }
+ ],
+ _options ->
+ {:ok,
+ [
+ %{
+ id: 0,
+ jsonrpc: "2.0",
+ result:
+ "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000033697066732f516d6439707654684577676a544262456b4e6d6d47466263704a4b773137666e524241543454643472636f67323200000000000000000000000000"
+ }
+ ]}
+ end)
+
+ Application.put_env(:explorer, :http_adapter, Explorer.Mox.HTTPoison)
+
+ Explorer.Mox.HTTPoison
+ |> expect(:get, fn "https://ipfs.io/ipfs/Qmd9pvThEwgjTBbEkNmmGFbcpJKw17fnRBAT4Td4rcog22", _headers, _options ->
+ {:ok, %HTTPoison.Response{status_code: 200, body: "123", headers: [{"Content-Type", "image/jpg"}]}}
+ end)
+
+ insert(:token,
+ contract_address: build(:address, hash: "0x7e01CC81fCfdf6a71323900288A69e234C464f63"),
+ type: "ERC-721"
+ )
+
+ assert [
+ {:ok,
+ %Instance{
+ metadata: %{
+ "image" => "https://ipfs.io/ipfs/Qmd9pvThEwgjTBbEkNmmGFbcpJKw17fnRBAT4Td4rcog22"
+ }
+ }}
+ ] = Helper.batch_fetch_instances([{"0x7e01CC81fCfdf6a71323900288A69e234C464f63", 0}])
+
+ Application.put_env(:explorer, :http_adapter, HTTPoison)
+ end
+ end
+end
diff --git a/apps/indexer/test/test_helper.exs b/apps/indexer/test/test_helper.exs
index 0df43337026a..381b6272bc29 100644
--- a/apps/indexer/test/test_helper.exs
+++ b/apps/indexer/test/test_helper.exs
@@ -17,6 +17,7 @@ end
Mox.defmock(EthereumJSONRPC.Mox, for: EthereumJSONRPC.Transport)
Mox.defmock(Indexer.BufferedTaskTest.RetryableTask, for: Indexer.BufferedTask)
Mox.defmock(Indexer.BufferedTaskTest.ShrinkableTask, for: Indexer.BufferedTask)
+Mox.defmock(Explorer.Mox.HTTPoison, for: HTTPoison.Base)
ExUnit.configure(formatters: [JUnitFormatter, ExUnit.CLIFormatter])
ExUnit.start()
diff --git a/config/config_helper.exs b/config/config_helper.exs
index 23224e698b92..a7e0706d3088 100644
--- a/config/config_helper.exs
+++ b/config/config_helper.exs
@@ -1,6 +1,7 @@
defmodule ConfigHelper do
import Bitwise
alias Explorer.ExchangeRates.Source
+ alias Explorer.Market.History.Source.{MarketCap, Price}
alias Indexer.Transform.Blocks
@spec hackney_options() :: any()
@@ -88,10 +89,29 @@ defmodule ConfigHelper do
@spec exchange_rates_source() :: Source.CoinGecko | Source.CoinMarketCap
def exchange_rates_source do
- cond do
- System.get_env("EXCHANGE_RATES_SOURCE") == "coin_gecko" -> Source.CoinGecko
- System.get_env("EXCHANGE_RATES_SOURCE") == "coin_market_cap" -> Source.CoinMarketCap
- true -> Source.CoinGecko
+ case System.get_env("EXCHANGE_RATES_MARKET_CAP_SOURCE") do
+ "coin_gecko" -> Source.CoinGecko
+ "coin_market_cap" -> Source.CoinMarketCap
+ _ -> Source.CoinGecko
+ end
+ end
+
+ @spec exchange_rates_market_cap_source() :: MarketCap.CoinGecko | MarketCap.CoinMarketCap
+ def exchange_rates_market_cap_source do
+ case System.get_env("EXCHANGE_RATES_MARKET_CAP_SOURCE") do
+ "coin_gecko" -> MarketCap.CoinGecko
+ "coin_market_cap" -> MarketCap.CoinMarketCap
+ _ -> MarketCap.CoinGecko
+ end
+ end
+
+ @spec exchange_rates_price_source() :: Price.CoinGecko | Price.CoinMarketCap | Price.CryptoCompare
+ def exchange_rates_price_source do
+ case System.get_env("EXCHANGE_RATES_PRICE_SOURCE") do
+ "coin_gecko" -> Price.CoinGecko
+ "coin_market_cap" -> Price.CoinMarketCap
+ "crypto_compare" -> Price.CryptoCompare
+ _ -> Price.CryptoCompare
end
end
diff --git a/config/runtime.exs b/config/runtime.exs
index 81f5e8aaec6a..e167253514c5 100644
--- a/config/runtime.exs
+++ b/config/runtime.exs
@@ -164,6 +164,9 @@ config :ethereum_jsonrpc, EthereumJSONRPC.Geth,
config :ethereum_jsonrpc, EthereumJSONRPC.PendingTransaction,
type: System.get_env("ETHEREUM_JSONRPC_PENDING_TRANSACTIONS_TYPE", "default")
+config :ethereum_jsonrpc, EthereumJSONRPC.RequestCoordinator,
+ wait_per_timeout: ConfigHelper.parse_time_env_var("ETHEREUM_JSONRPC_WAIT_PER_TIMEOUT", "20s")
+
################
### Explorer ###
################
@@ -267,7 +270,10 @@ config :explorer, Explorer.ExchangeRates,
enabled: !ConfigHelper.parse_bool_env_var("DISABLE_EXCHANGE_RATES"),
fetch_btc_value: ConfigHelper.parse_bool_env_var("EXCHANGE_RATES_FETCH_BTC_VALUE")
-config :explorer, Explorer.ExchangeRates.Source, source: ConfigHelper.exchange_rates_source()
+config :explorer, Explorer.ExchangeRates.Source,
+ source: ConfigHelper.exchange_rates_source(),
+ price_source: ConfigHelper.exchange_rates_price_source(),
+ market_cap_source: ConfigHelper.exchange_rates_market_cap_source()
config :explorer, Explorer.ExchangeRates.Source.CoinMarketCap,
api_key: System.get_env("EXCHANGE_RATES_COINMARKETCAP_API_KEY"),
@@ -445,8 +451,11 @@ config :indexer, Indexer.Fetcher.PendingTransaction.Supervisor,
System.get_env("ETHEREUM_JSONRPC_VARIANT") == "besu" ||
ConfigHelper.parse_bool_env_var("INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER")
+config :indexer, Indexer.Fetcher.Token, concurrency: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_CONCURRENCY", 10)
+
config :indexer, Indexer.Fetcher.TokenBalance,
- batch_size: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_BALANCES_BATCH_SIZE", 100)
+ batch_size: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_BALANCES_BATCH_SIZE", 100),
+ concurrency: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_BALANCES_CONCURRENCY", 10)
config :indexer, Indexer.Fetcher.TokenBalanceOnDemand,
threshold: ConfigHelper.parse_time_env_var("TOKEN_BALANCE_ON_DEMAND_FETCHER_THRESHOLD", "1h"),
@@ -502,13 +511,16 @@ config :indexer, Indexer.Fetcher.BlockReward,
config :indexer, Indexer.Fetcher.TokenInstance.Retry,
concurrency: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_INSTANCE_RETRY_CONCURRENCY", 10),
+ batch_size: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_INSTANCE_RETRY_BATCH_SIZE", 10),
refetch_interval: ConfigHelper.parse_time_env_var("INDEXER_TOKEN_INSTANCE_RETRY_REFETCH_INTERVAL", "24h")
config :indexer, Indexer.Fetcher.TokenInstance.Realtime,
- concurrency: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_INSTANCE_REALTIME_CONCURRENCY", 10)
+ concurrency: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_INSTANCE_REALTIME_CONCURRENCY", 10),
+ batch_size: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_INSTANCE_REALTIME_BATCH_SIZE", 1)
config :indexer, Indexer.Fetcher.TokenInstance.Sanitize,
- concurrency: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_INSTANCE_SANITIZE_CONCURRENCY", 10)
+ concurrency: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_INSTANCE_SANITIZE_CONCURRENCY", 10),
+ batch_size: ConfigHelper.parse_integer_env_var("INDEXER_TOKEN_INSTANCE_SANITIZE_BATCH_SIZE", 10)
config :indexer, Indexer.Fetcher.InternalTransaction,
batch_size: ConfigHelper.parse_integer_env_var("INDEXER_INTERNAL_TRANSACTIONS_BATCH_SIZE", 10),
diff --git a/config/test.exs b/config/test.exs
index c87adaeda1de..92ddca6a93a0 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -10,6 +10,8 @@ config :logger, :ecto,
config :logger, :error, path: Path.absname("logs/test/error.log")
-config :explorer, Explorer.ExchangeRates,
+config :explorer, Explorer.ExchangeRates, store: :none
+
+config :explorer, Explorer.ExchangeRates.Source,
source: Explorer.ExchangeRates.Source.NoOpSource,
- store: :none
+ price_source: Explorer.ExchangeRates.Source.NoOpPriceSource
diff --git a/cspell.json b/cspell.json
index 2c733cb6d8ad..ef83d12ef464 100644
--- a/cspell.json
+++ b/cspell.json
@@ -519,7 +519,12 @@
"erts",
"Asfpp",
"Nerg",
- "secp"
+ "secp",
+ "qwertyuioiuytrewertyuioiuytrertyuio",
+ "urlset",
+ "lastmod",
+ "qitmeer",
+ "meer",
],
"enableFiletypes": [
"dotenv",
diff --git a/docker-compose/docker-compose-no-build-erigon.yml b/docker-compose/docker-compose-no-build-erigon.yml
index 29231c45d1ef..5c93dd2547f3 100644
--- a/docker-compose/docker-compose-no-build-erigon.yml
+++ b/docker-compose/docker-compose-no-build-erigon.yml
@@ -35,6 +35,7 @@ services:
DATABASE_URL: postgresql://postgres:@host.docker.internal:7432/blockscout?ssl=false
ECTO_USE_SSL: 'false'
SECRET_KEY_BASE: '56NtB48ear7+wMSf0IQuWDAAazhpb31qyc7GiyspBP2vh7t5zlCsF5QDv76chXeN'
+ MIX_ENV: 'prod'
ports:
- 4000:4000
volumes:
diff --git a/docker-compose/docker-compose-no-build-external-backend.yml b/docker-compose/docker-compose-no-build-external-backend.yml
new file mode 100644
index 000000000000..3e1726bf846e
--- /dev/null
+++ b/docker-compose/docker-compose-no-build-external-backend.yml
@@ -0,0 +1,52 @@
+version: '3.8'
+
+services:
+ redis_db:
+ extends:
+ file: ./services/docker-compose-redis.yml
+ service: redis_db
+
+ db:
+ extends:
+ file: ./services/docker-compose-db.yml
+ service: db
+
+ smart-contract-verifier:
+ extends:
+ file: ./services/docker-compose-smart-contract-verifier.yml
+ service: smart-contract-verifier
+
+ visualizer:
+ extends:
+ file: ./services/docker-compose-visualizer.yml
+ service: visualizer
+
+ sig-provider:
+ extends:
+ file: ./services/docker-compose-sig-provider.yml
+ service: sig-provider
+
+ frontend:
+ extends:
+ file: ./services/docker-compose-frontend.yml
+ service: frontend
+
+ stats-db:
+ extends:
+ file: ./services/docker-compose-stats.yml
+ service: stats-db
+
+ stats:
+ depends_on:
+ - stats-db
+ extends:
+ file: ./services/docker-compose-stats.yml
+ service: stats
+
+ proxy:
+ depends_on:
+ - frontend
+ - stats
+ extends:
+ file: ./services/docker-compose-nginx.yml
+ service: proxy
diff --git a/docker-compose/docker-compose-no-build-external-frontend.yml b/docker-compose/docker-compose-no-build-external-frontend.yml
index 35dbc93a81b0..bc96e61f854d 100644
--- a/docker-compose/docker-compose-no-build-external-frontend.yml
+++ b/docker-compose/docker-compose-no-build-external-frontend.yml
@@ -31,6 +31,7 @@ services:
environment:
ETHEREUM_JSONRPC_VARIANT: 'ganache'
ETHEREUM_JSONRPC_HTTP_URL: http://host.docker.internal:8545/
+ ETHEREUM_JSONRPC_TRACE_URL: http://host.docker.internal:8545/
ETHEREUM_JSONRPC_WS_URL: ws://host.docker.internal:8545/
INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER: 'true'
INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER: 'true'
@@ -40,6 +41,7 @@ services:
CHAIN_ID: '1337'
API_V2_ENABLED: 'true'
MIX_ENV: 'prod'
+ ACCOUNT_ENABLED: 'false'
ports:
- 4000:4000
volumes:
diff --git a/docker-compose/docker-compose-no-build-frontend.yml b/docker-compose/docker-compose-no-build-frontend.yml
index 76ae066b383a..663d580398dc 100644
--- a/docker-compose/docker-compose-no-build-frontend.yml
+++ b/docker-compose/docker-compose-no-build-frontend.yml
@@ -31,6 +31,7 @@ services:
environment:
ETHEREUM_JSONRPC_VARIANT: 'ganache'
ETHEREUM_JSONRPC_HTTP_URL: http://host.docker.internal:8545/
+ ETHEREUM_JSONRPC_TRACE_URL: http://host.docker.internal:8545/
ETHEREUM_JSONRPC_WS_URL: ws://host.docker.internal:8545/
INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER: 'true'
INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER: 'true'
diff --git a/docker-compose/docker-compose-no-build-geth-clique-consensus.yml b/docker-compose/docker-compose-no-build-geth-clique-consensus.yml
index bfcb31cb9d27..7ce75af41903 100644
--- a/docker-compose/docker-compose-no-build-geth-clique-consensus.yml
+++ b/docker-compose/docker-compose-no-build-geth-clique-consensus.yml
@@ -32,9 +32,11 @@ services:
ETHEREUM_JSONRPC_VARIANT: 'geth'
BLOCK_TRANSFORMER: 'clique'
ETHEREUM_JSONRPC_HTTP_URL: http://host.docker.internal:8545/
+ ETHEREUM_JSONRPC_TRACE_URL: http://host.docker.internal:8545/
DATABASE_URL: postgresql://postgres:@host.docker.internal:7432/blockscout?ssl=false
ECTO_USE_SSL: 'false'
SECRET_KEY_BASE: '56NtB48ear7+wMSf0IQuWDAAazhpb31qyc7GiyspBP2vh7t5zlCsF5QDv76chXeN'
+ MIX_ENV: 'prod'
ports:
- 4000:4000
volumes:
diff --git a/docker-compose/docker-compose-no-build-geth.yml b/docker-compose/docker-compose-no-build-geth.yml
index d8aa27370019..f163cdb1956a 100644
--- a/docker-compose/docker-compose-no-build-geth.yml
+++ b/docker-compose/docker-compose-no-build-geth.yml
@@ -31,9 +31,11 @@ services:
environment:
ETHEREUM_JSONRPC_VARIANT: 'geth'
ETHEREUM_JSONRPC_HTTP_URL: http://host.docker.internal:8545/
+ ETHEREUM_JSONRPC_TRACE_URL: http://host.docker.internal:8545/
DATABASE_URL: postgresql://postgres:@host.docker.internal:7432/blockscout?ssl=false
ECTO_USE_SSL: 'false'
SECRET_KEY_BASE: '56NtB48ear7+wMSf0IQuWDAAazhpb31qyc7GiyspBP2vh7t5zlCsF5QDv76chXeN'
+ MIX_ENV: 'prod'
ports:
- 4000:4000
volumes:
diff --git a/docker-compose/docker-compose-no-build-nethermind.yml b/docker-compose/docker-compose-no-build-nethermind.yml
index 4aba06749c91..9488dd597798 100644
--- a/docker-compose/docker-compose-no-build-nethermind.yml
+++ b/docker-compose/docker-compose-no-build-nethermind.yml
@@ -35,6 +35,7 @@ services:
DATABASE_URL: postgresql://postgres:@host.docker.internal:7432/blockscout?ssl=false
ECTO_USE_SSL: 'false'
SECRET_KEY_BASE: '56NtB48ear7+wMSf0IQuWDAAazhpb31qyc7GiyspBP2vh7t5zlCsF5QDv76chXeN'
+ MIX_ENV: 'prod'
ports:
- 4000:4000
volumes:
diff --git a/docker-compose/docker-compose-no-build-no-db-container.yml b/docker-compose/docker-compose-no-build-no-db-container.yml
index 39232ea66c1d..ad4c844db6f9 100644
--- a/docker-compose/docker-compose-no-build-no-db-container.yml
+++ b/docker-compose/docker-compose-no-build-no-db-container.yml
@@ -26,6 +26,7 @@ services:
DATABASE_URL: postgresql://postgres:@host.docker.internal:5432/blockscout?ssl=false
ECTO_USE_SSL: 'false'
SECRET_KEY_BASE: '56NtB48ear7+wMSf0IQuWDAAazhpb31qyc7GiyspBP2vh7t5zlCsF5QDv76chXeN'
+ MIX_ENV: 'prod'
ports:
- 4000:4000
volumes:
diff --git a/docker-compose/docker-compose-no-rust-services.yml b/docker-compose/docker-compose-no-rust-services.yml
index a35253cd3279..e6a6336433ff 100644
--- a/docker-compose/docker-compose-no-rust-services.yml
+++ b/docker-compose/docker-compose-no-rust-services.yml
@@ -27,7 +27,8 @@ services:
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED: ""
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL: ""
ADMIN_PANEL_ENABLED: ""
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
+ MIX_ENV: 'prod'
restart: always
stop_grace_period: 5m
container_name: 'blockscout'
diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml
index 9fdb484b9699..93552c9d9cac 100644
--- a/docker-compose/docker-compose.yml
+++ b/docker-compose/docker-compose.yml
@@ -28,7 +28,7 @@ services:
CACHE_TOTAL_GAS_USAGE_COUNTER_ENABLED: ""
CACHE_ADDRESS_WITH_BALANCES_UPDATE_INTERVAL: ""
ADMIN_PANEL_ENABLED: ""
- RELEASE_VERSION: 5.2.1
+ RELEASE_VERSION: 5.2.2
restart: always
stop_grace_period: 5m
container_name: 'blockscout'
diff --git a/docker-compose/envs/common-blockscout.env b/docker-compose/envs/common-blockscout.env
index c7dfa9eae682..a8ae85965cc8 100644
--- a/docker-compose/envs/common-blockscout.env
+++ b/docker-compose/envs/common-blockscout.env
@@ -13,6 +13,7 @@ LOGO=/images/blockscout_logo.svg
ETHEREUM_JSONRPC_TRANSPORT=http
ETHEREUM_JSONRPC_DISABLE_ARCHIVE_BALANCES=false
# ETHEREUM_JSONRPC_HTTP_HEADERS=
+# ETHEREUM_JSONRPC_WAIT_PER_TIMEOUT=
IPC_PATH=
NETWORK_PATH=/
BLOCKSCOUT_HOST=
@@ -31,7 +32,8 @@ EMISSION_FORMAT=DEFAULT
# SUPPLY_MODULE=
COIN=
EXCHANGE_RATES_COIN=
-# EXCHANGE_RATES_SOURCE=
+# EXCHANGE_RATES_MARKET_CAP_SOURCE=
+# EXCHANGE_RATES_PRICE_SOURCE=
# EXCHANGE_RATES_COINGECKO_COIN_ID=
# EXCHANGE_RATES_COINGECKO_API_KEY=
# EXCHANGE_RATES_COINMARKETCAP_API_KEY=
@@ -114,7 +116,9 @@ INDEXER_DISABLE_INTERNAL_TRANSACTIONS_FETCHER=false
# INDEXER_COIN_BALANCES_CONCURRENCY=
# INDEXER_RECEIPTS_BATCH_SIZE=
# INDEXER_RECEIPTS_CONCURRENCY=
+# INDEXER_TOKEN_CONCURRENCY=
# INDEXER_TOKEN_BALANCES_BATCH_SIZE=
+# INDEXER_TOKEN_BALANCES_CONCURRENCY=
# INDEXER_TX_ACTIONS_ENABLE=
# INDEXER_TX_ACTIONS_MAX_TOKEN_CACHE_SIZE=
# INDEXER_TX_ACTIONS_REINDEX_FIRST_BLOCK=
@@ -208,3 +212,6 @@ ACCOUNT_REDIS_URL=redis://redis_db:6379
EIP_1559_ELASTICITY_MULTIPLIER=2
# API_SENSITIVE_ENDPOINTS_KEY=
# ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL=
+# INDEXER_TOKEN_INSTANCE_RETRY_BATCH_SIZE=10
+# INDEXER_TOKEN_INSTANCE_REALTIME_BATCH_SIZE=1
+# INDEXER_TOKEN_INSTANCE_SANITIZE_BATCH_SIZE=10
diff --git a/docker-compose/envs/common-frontend.env b/docker-compose/envs/common-frontend.env
index 84da58952bc6..57e8a6a5f7a2 100644
--- a/docker-compose/envs/common-frontend.env
+++ b/docker-compose/envs/common-frontend.env
@@ -1,26 +1,20 @@
NEXT_PUBLIC_API_HOST=localhost
-NEXT_PUBLIC_API_PORT=81
NEXT_PUBLIC_API_PROTOCOL=http
-NEXT_PUBLIC_STATS_API_HOST=http://localhost:82
+NEXT_PUBLIC_STATS_API_HOST=http://localhost:8080
NEXT_PUBLIC_NETWORK_NAME=Göerli
NEXT_PUBLIC_NETWORK_SHORT_NAME=Göerli
-NEXT_PUBLIC_NETWORK_ASSETS_PATHNAME=ethereum
NEXT_PUBLIC_NETWORK_ID=5
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_FEATURED_NETWORKS=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/featured-networks/eth-goerli.json
-NEXT_PUBLIC_FOOTER_GITHUB_LINK=https://github.com/blockscout/blockscout
-NEXT_PUBLIC_FOOTER_TWITTER_LINK=https://www.twitter.com/blockscoutcom
-NEXT_PUBLIC_APP_ENV=staging
-NEXT_PUBLIC_APP_INSTANCE=eth_goerli
NEXT_PUBLIC_APP_HOST=localhost
-NEXT_PUBLIC_HOMEPAGE_CHARTS="['daily_txs']"
-NEXT_PUBLIC_VISUALIZE_API_HOST=http://visualizer:80
-NEXT_PUBLIC_IS_TESTNET='true'
+NEXT_PUBLIC_APP_PROTOCOL=http
+NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
+NEXT_PUBLIC_VISUALIZE_API_HOST=http://localhost:8081
+NEXT_PUBLIC_IS_TESTNET=true
NEXT_PUBLIC_NETWORK_LOGO=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-logos/goerli.svg
NEXT_PUBLIC_NETWORK_ICON=https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/network-icons/goerli.svg
-NEXT_PUBLIC_HOMEPAGE_PLATE_GRADIENT="radial-gradient(103.03% 103.03% at 0% 0%, rgba(183, 148, 244, 0.8) 0%, rgba(0, 163, 196, 0.8) 100%)"
-NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR="rgb(255, 255, 255)"
-NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL='ws'
+NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR=rgb(255, 255, 255)
+NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
diff --git a/docker-compose/proxy/default.conf.template b/docker-compose/proxy/default.conf.template
index 3967119647c0..0ea0e3bf9fb2 100644
--- a/docker-compose/proxy/default.conf.template
+++ b/docker-compose/proxy/default.conf.template
@@ -1,46 +1,72 @@
+map $http_upgrade $connection_upgrade {
+
+ default upgrade;
+ '' close;
+}
+
server {
listen 80;
server_name localhost;
proxy_http_version 1.1;
+
location / {
- proxy_pass ${FRONT_PROXY_PASS};
+ proxy_pass ${BACK_PROXY_PASS};
+ proxy_http_version 1.1;
+ proxy_set_header Host "$host";
+ proxy_set_header X-Real-IP "$remote_addr";
+ proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
+ proxy_set_header X-Forwarded-Proto "$scheme";
+ proxy_set_header Upgrade "$http_upgrade";
+ proxy_set_header Connection $connection_upgrade;
+ proxy_cache_bypass $http_upgrade;
}
- location /socket/v2 {
- proxy_pass http://backend:4000;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "Upgrade";
- proxy_set_header Host $host;
+ location = / {
+ proxy_pass ${FRONT_PROXY_PASS};
+ proxy_http_version 1.1;
+ proxy_set_header Host "$host";
+ proxy_set_header X-Real-IP "$remote_addr";
+ proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
+ proxy_set_header X-Forwarded-Proto "$scheme";
+ proxy_set_header Upgrade "$http_upgrade";
+ proxy_set_header Connection $connection_upgrade;
+ proxy_cache_bypass $http_upgrade;
}
- location /api/ {
- proxy_pass http://backend:4000/api;
+ location ~ ^/(_next|node-api|apps|account|accounts|favicon|static|auth/profile|auth/unverified-email|txs|tx|blocks|block|login|address|stats|search-results|token|tokens|visualize|api-docs|csv-export|verified-contracts|graphiql|withdrawals) {
+ proxy_pass ${FRONT_PROXY_PASS};
+ proxy_http_version 1.1;
+ proxy_set_header Host "$host";
+ proxy_set_header X-Real-IP "$remote_addr";
+ proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
+ proxy_set_header X-Forwarded-Proto "$scheme";
+ proxy_set_header Upgrade "$http_upgrade";
+ proxy_set_header Connection $connection_upgrade;
+ proxy_cache_bypass $http_upgrade;
}
}
-
server {
- listen 81;
+ listen 8080;
server_name localhost;
proxy_http_version 1.1;
proxy_hide_header Access-Control-Allow-Origin;
proxy_hide_header Access-Control-Allow-Methods;
add_header 'Access-Control-Allow-Origin' 'http://localhost' always;
+ add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always;
location / {
- proxy_pass http://backend:4000;
- }
-
- location /socket {
- proxy_pass http://backend:4000;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "Upgrade";
- proxy_set_header Host $host;
+ proxy_pass http://stats:8050/;
+ proxy_http_version 1.1;
+ proxy_set_header Host "$host";
+ proxy_set_header X-Real-IP "$remote_addr";
+ proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
+ proxy_set_header X-Forwarded-Proto "$scheme";
+ proxy_set_header Upgrade "$http_upgrade";
+ proxy_set_header Connection $connection_upgrade;
+ proxy_cache_bypass $http_upgrade;
}
}
-
server {
- listen 82;
+ listen 8081;
server_name localhost;
proxy_http_version 1.1;
proxy_hide_header Access-Control-Allow-Origin;
@@ -48,15 +74,31 @@ server {
add_header 'Access-Control-Allow-Origin' 'http://localhost' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always;
+ add_header 'Access-Control-Allow-Headers' 'DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,x-csrf-token' always;
location / {
- proxy_pass http://stats:8050;
- }
- location /socket/v2 {
- proxy_pass http://backend:4000;
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection "Upgrade";
- proxy_set_header Host $host;
+ proxy_pass http://visualizer:8050/;
+ proxy_http_version 1.1;
+ proxy_buffering off;
+ proxy_set_header Host "$host";
+ proxy_set_header X-Real-IP "$remote_addr";
+ proxy_connect_timeout 30m;
+ proxy_read_timeout 30m;
+ proxy_send_timeout 30m;
+ proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
+ proxy_set_header X-Forwarded-Proto "$scheme";
+ proxy_set_header Upgrade "$http_upgrade";
+ proxy_set_header Connection $connection_upgrade;
+ proxy_cache_bypass $http_upgrade;
+ if ($request_method = 'OPTIONS') {
+ add_header 'Access-Control-Allow-Origin' 'http://localhost' always;
+ add_header 'Access-Control-Allow-Credentials' 'true' always;
+ add_header 'Access-Control-Allow-Methods' 'PUT, GET, POST, OPTIONS, DELETE, PATCH' always;
+ add_header 'Access-Control-Allow-Headers' 'DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,x-csrf-token' always;
+ add_header 'Access-Control-Max-Age' 1728000;
+ add_header 'Content-Type' 'text/plain charset=UTF-8';
+ add_header 'Content-Length' 0;
+ return 204;
+ }
}
}
\ No newline at end of file
diff --git a/docker-compose/services/docker-compose-nginx.yml b/docker-compose/services/docker-compose-nginx.yml
index 295913b4607b..e54401d3f5ae 100644
--- a/docker-compose/services/docker-compose-nginx.yml
+++ b/docker-compose/services/docker-compose-nginx.yml
@@ -1,14 +1,17 @@
version: '3.8'
-services:
+services:
proxy:
image: nginx
container_name: proxy
+ extra_hosts:
+ - 'host.docker.internal:host-gateway'
volumes:
- "../proxy:/etc/nginx/templates"
environment:
+ BACK_PROXY_PASS: ${BACK_PROXY_PASS:-http://backend:4000}
FRONT_PROXY_PASS: ${FRONT_PROXY_PASS:-http://frontend:3000}
ports:
- 80:80
- - 81:81
- - 82:82
\ No newline at end of file
+ - 8080:8080
+ - 8081:8081
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 9b42fcbe71b2..5a8569a1d0bc 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -37,7 +37,7 @@ RUN mix do deps.get, local.rebar --force, deps.compile
ADD apps ./apps
ADD config ./config
ADD rel ./rel
-ADD *.exs .
+ADD *.exs ./
RUN apk add --update nodejs npm
@@ -70,7 +70,7 @@ ENV RELEASE_VERSION=${RELEASE_VERSION}
ARG BLOCKSCOUT_VERSION
ENV BLOCKSCOUT_VERSION=${BLOCKSCOUT_VERSION}
-RUN apk --no-cache --update add jq
+RUN apk --no-cache --update add jq curl
WORKDIR /app
diff --git a/docker/Makefile b/docker/Makefile
index b9f15c84c0b4..3c5289bc6ac2 100644
--- a/docker/Makefile
+++ b/docker/Makefile
@@ -7,7 +7,7 @@ BS_CONTAINER_NAME := blockscout
PG_CONTAINER_IMAGE := postgres:14
PG_CONTAINER_NAME := db
THIS_FILE = $(lastword $(MAKEFILE_LIST))
-RELEASE_VERSION ?= '5.2.1'
+RELEASE_VERSION ?= '5.2.2'
PORT ?= '4000'
TAG := $(RELEASE_VERSION)-commit-$(shell git log -1 --pretty=format:"%h")
STABLE_TAG := $(RELEASE_VERSION)
@@ -63,6 +63,9 @@ endif
ifdef ETHEREUM_JSONRPC_HTTP_HEADERS
BLOCKSCOUT_CONTAINER_PARAMS += -e 'ETHEREUM_JSONRPC_HTTP_HEADERS=$(ETHEREUM_JSONRPC_HTTP_HEADERS)'
endif
+ifdef ETHEREUM_JSONRPC_WAIT_PER_TIMEOUT
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'ETHEREUM_JSONRPC_WAIT_PER_TIMEOUT=$(ETHEREUM_JSONRPC_WAIT_PER_TIMEOUT)'
+endif
ifdef IPC_PATH
BLOCKSCOUT_CONTAINER_PARAMS += -e 'IPC_PATH=$(IPC_PATH)'
endif
@@ -225,8 +228,11 @@ endif
ifdef EXCHANGE_RATES_COIN
BLOCKSCOUT_CONTAINER_PARAMS += -e 'EXCHANGE_RATES_COIN=$(EXCHANGE_RATES_COIN)'
endif
-ifdef EXCHANGE_RATES_SOURCE
- BLOCKSCOUT_CONTAINER_PARAMS += -e 'EXCHANGE_RATES_SOURCE=$(EXCHANGE_RATES_SOURCE)'
+ifdef EXCHANGE_RATES_MARKET_CAP_SOURCE
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'EXCHANGE_RATES_MARKET_CAP_SOURCE=$(EXCHANGE_RATES_MARKET_CAP_SOURCE)'
+endif
+ifdef EXCHANGE_RATES_PRICE_SOURCE
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'EXCHANGE_RATES_PRICE_SOURCE=$(EXCHANGE_RATES_PRICE_SOURCE)'
endif
ifdef EXCHANGE_RATES_COINGECKO_COIN_ID
BLOCKSCOUT_CONTAINER_PARAMS += -e 'EXCHANGE_RATES_COINGECKO_COIN_ID=$(EXCHANGE_RATES_COINGECKO_COIN_ID)'
@@ -561,9 +567,15 @@ endif
ifdef INDEXER_EMPTY_BLOCKS_SANITIZER_BATCH_SIZE
BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_EMPTY_BLOCKS_SANITIZER_BATCH_SIZE=$(INDEXER_EMPTY_BLOCKS_SANITIZER_BATCH_SIZE)'
endif
+ifdef INDEXER_TOKEN_CONCURRENCY
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_TOKEN_CONCURRENCY=$(INDEXER_TOKEN_CONCURRENCY)'
+endif
ifdef INDEXER_TOKEN_BALANCES_BATCH_SIZE
BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_TOKEN_BALANCES_BATCH_SIZE=$(INDEXER_TOKEN_BALANCES_BATCH_SIZE)'
endif
+ifdef INDEXER_TOKEN_BALANCES_CONCURRENCY
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_TOKEN_BALANCES_CONCURRENCY=$(INDEXER_TOKEN_BALANCES_CONCURRENCY)'
+endif
ifdef INDEXER_REALTIME_FETCHER_MAX_GAP
BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_REALTIME_FETCHER_MAX_GAP=$(INDEXER_REALTIME_FETCHER_MAX_GAP)'
endif
@@ -723,6 +735,15 @@ endif
ifdef ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL
BLOCKSCOUT_CONTAINER_PARAMS += -e 'ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL=$(ACCOUNT_VERIFICATION_EMAIL_RESEND_INTERVAL)'
endif
+ifdef INDEXER_TOKEN_INSTANCE_RETRY_BATCH_SIZE
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_TOKEN_INSTANCE_RETRY_BATCH_SIZE=$(INDEXER_TOKEN_INSTANCE_RETRY_BATCH_SIZE)'
+endif
+ifdef INDEXER_TOKEN_INSTANCE_REALTIME_BATCH_SIZE
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_TOKEN_INSTANCE_REALTIME_BATCH_SIZE=$(INDEXER_TOKEN_INSTANCE_REALTIME_BATCH_SIZE)'
+endif
+ifdef INDEXER_TOKEN_INSTANCE_SANITIZE_BATCH_SIZE
+ BLOCKSCOUT_CONTAINER_PARAMS += -e 'INDEXER_TOKEN_INSTANCE_SANITIZE_BATCH_SIZE=$(INDEXER_TOKEN_INSTANCE_SANITIZE_BATCH_SIZE)'
+endif
HAS_BLOCKSCOUT_IMAGE := $(shell docker images | grep -sw "${BS_CONTAINER_IMAGE} ")
build:
diff --git a/mix.exs b/mix.exs
index 744ac916a089..9983272fe866 100644
--- a/mix.exs
+++ b/mix.exs
@@ -7,7 +7,7 @@ defmodule BlockScout.Mixfile do
[
# app: :block_scout,
# aliases: aliases(config_env()),
- version: "5.2.1",
+ version: "5.2.2",
apps_path: "apps",
deps: deps(),
dialyzer: dialyzer(),
diff --git a/mix.lock b/mix.lock
index c2c9117105d6..962158f0d821 100644
--- a/mix.lock
+++ b/mix.lock
@@ -6,7 +6,7 @@
"accept": {:hex, :accept, "0.3.5", "b33b127abca7cc948bbe6caa4c263369abf1347cfa9d8e699c6d214660f10cd1", [:rebar3], [], "hexpm", "11b18c220bcc2eab63b5470c038ef10eb6783bcb1fcdb11aa4137defa5ac1bb8"},
"b58": {:hex, :b58, "1.0.3", "d300d6ae5a3de956a54b9e8220e924e4fee1a349de983df2340fe61e0e464202", [:mix], [], "hexpm", "af62a98a8661fd89978cf3a3a4b5b2ebe82209de6ac6164f0b112e36af72fc59"},
"bamboo": {:hex, :bamboo, "2.3.0", "d2392a2cabe91edf488553d3c70638b532e8db7b76b84b0a39e3dfe492ffd6fc", [:mix], [{:hackney, ">= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.4 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "dd0037e68e108fd04d0e8773921512c940e35d981e097b5793543e3b2f9cd3f6"},
- "bcrypt_elixir": {:hex, :bcrypt_elixir, "3.0.1", "9be815469e6bfefec40fa74658ecbbe6897acfb57614df1416eeccd4903f602c", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "486bb95efb645d1efc6794c1ddd776a186a9a713abf06f45708a6ce324fb96cf"},
+ "bcrypt_elixir": {:hex, :bcrypt_elixir, "3.1.0", "0b110a9a6c619b19a7f73fa3004aa11d6e719a67e672d1633dc36b6b2290a0f7", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2ad2acb5a8bc049e8d5aa267802631912bb80d5f4110a178ae7999e69dca1bf7"},
"benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"},
"benchee_csv": {:hex, :benchee_csv, "1.0.0", "0b3b9223290bfcb8003552705bec9bcf1a89b4a83b70bd686e45295c264f3d16", [:mix], [{:benchee, ">= 0.99.0 and < 2.0.0", [hex: :benchee, repo: "hexpm", optional: false]}, {:csv, "~> 2.0", [hex: :csv, repo: "hexpm", optional: false]}], "hexpm", "cdefb804c021dcf7a99199492026584be9b5a21d6644ac0d01c81c5d97c520d5"},
"briefly": {:git, "https://github.com/CargoSense/briefly.git", "678a3763e72a7d1f23ac71b209b96bd199bffbbb", []},
@@ -15,13 +15,13 @@
"bypass": {:hex, :bypass, "2.1.0", "909782781bf8e20ee86a9cabde36b259d44af8b9f38756173e8f5e2e1fabb9b1", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "d9b5df8fa5b7a6efa08384e9bbecfe4ce61c77d28a4282f79e02f1ef78d96b80"},
"castore": {:hex, :castore, "1.0.3", "7130ba6d24c8424014194676d608cb989f62ef8039efd50ff4b3f33286d06db8", [:mix], [], "hexpm", "680ab01ef5d15b161ed6a95449fac5c6b8f60055677a8e79acf01b27baa4390b"},
"cbor": {:hex, :cbor, "1.0.1", "39511158e8ea5a57c1fcb9639aaa7efde67129678fee49ebbda780f6f24959b0", [:mix], [], "hexpm", "5431acbe7a7908f17f6a9cd43311002836a34a8ab01876918d8cfb709cd8b6a2"},
- "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
+ "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"cldr_utils": {:hex, :cldr_utils, "2.24.1", "5ff8c8c55f96666228827bcf85a23d632022def200566346545d01d15e4c30dc", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "1820300531b5b849d0bc468e5a87cd64f8f2c5191916f548cbe69b2efc203780"},
"cloak": {:hex, :cloak, "1.1.2", "7e0006c2b0b98d976d4f559080fabefd81f0e0a50a3c4b621f85ceeb563e80bb", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "940d5ac4fcd51b252930fd112e319ea5ae6ab540b722f3ca60a85666759b9585"},
"cloak_ecto": {:hex, :cloak_ecto, "1.2.0", "e86a3df3bf0dc8980f70406bcb0af2858bac247d55494d40bc58a152590bd402", [:mix], [{:cloak, "~> 1.1.1", [hex: :cloak, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "8bcc677185c813fe64b786618bd6689b1707b35cd95acaae0834557b15a0c62f"},
"coerce": {:hex, :coerce, "1.0.1", "211c27386315dc2894ac11bc1f413a0e38505d808153367bd5c6e75a4003d096", [:mix], [], "hexpm", "b44a691700f7a1a15b4b7e2ff1fa30bebd669929ac8aa43cffe9e2f8bf051cf1"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
- "comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"},
+ "comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
"con_cache": {:hex, :con_cache, "1.0.0", "6405e2bd5d5005334af72939432783562a8c35a196c2e63108fe10bb97b366e6", [:mix], [], "hexpm", "4d1f5cb1a67f3c1a468243dc98d10ac83af7f3e33b7e7c15999dc2c9bc0a551e"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cors_plug": {:hex, :cors_plug, "3.0.3", "7c3ac52b39624bc616db2e937c282f3f623f25f8d550068b6710e58d04a0e330", [:mix], [{:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3f2d759e8c272ed3835fab2ef11b46bddab8c1ab9528167bd463b6452edf830d"},
@@ -35,37 +35,37 @@
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"decorator": {:hex, :decorator, "1.4.0", "a57ac32c823ea7e4e67f5af56412d12b33274661bb7640ec7fc882f8d23ac419", [:mix], [], "hexpm", "0a07cedd9083da875c7418dea95b78361197cf2bf3211d743f6f7ce39656597f"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
- "dialyxir": {:hex, :dialyxir, "1.3.0", "fd1672f0922b7648ff9ce7b1b26fcf0ef56dda964a459892ad15f6b4410b5284", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "00b2a4bcd6aa8db9dcb0b38c1225b7277dca9bc370b6438715667071a304696f"},
+ "dialyxir": {:hex, :dialyxir, "1.4.1", "a22ed1e7bd3a3e3f197b68d806ef66acb61ee8f57b3ac85fc5d57354c5482a93", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "84b795d6d7796297cca5a3118444b80c7d94f7ce247d49886e7c291e1ae49801"},
"digital_token": {:hex, :digital_token, "0.6.0", "13e6de581f0b1f6c686f7c7d12ab11a84a7b22fa79adeb4b50eec1a2d278d258", [:mix], [{:cldr_utils, "~> 2.17", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "2455d626e7c61a128b02a4a8caddb092548c3eb613ac6f6a85e4cbb6caddc4d1"},
"earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"},
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
- "ecto_sql": {:hex, :ecto_sql, "3.10.1", "6ea6b3036a0b0ca94c2a02613fd9f742614b5cfe494c41af2e6571bb034dd94c", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6a25bdbbd695f12c8171eaff0851fa4c8e72eec1e98c7364402dda9ce11c56b"},
- "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"},
+ "ecto_sql": {:hex, :ecto_sql, "3.10.2", "6b98b46534b5c2f8b8b5f03f126e75e2a73c64f3c071149d32987a5378b0fdbd", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "68c018debca57cb9235e3889affdaec7a10616a4e3a80c99fa1d01fdafaa9007"},
+ "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
- "ex_abi": {:hex, :ex_abi, "0.6.0", "8cf1fef9490dea0834bc201d399635e72178df05dea87b1c933478762dede142", [:mix], [{:ex_keccak, "~> 0.7.1", [hex: :ex_keccak, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b03e5fe07371db3ceceb2d536cc32658dcba47b79952469e3e71d7690495e8d8"},
+ "ex_abi": {:hex, :ex_abi, "0.6.2", "a33d0df94efd54d6879d20ab8cb6561432f13cbb1e912801d2e97ef50f795e9d", [:mix], [{:ex_keccak, "~> 0.7.3", [hex: :ex_keccak, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e901c580a2491b19a6c27891c6d40cd8fe41d996c8c2ec02d5dd4c5a86239bc6"},
"ex_cldr": {:hex, :ex_cldr, "2.37.2", "c45041534ec60af367c4c1af02a608576118044fe3c441c782fd424061d6b517", [:mix], [{:cldr_utils, "~> 2.21", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "c8467b1d5080716ace6621703b6656cb2f9545572a54b341da900791a0cf92ba"},
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.15.0", "aadd34e91cfac7ef6b03fe8f47f8c6fa8c5daf3f89b5d9fee64ec545ded839cf", [:mix], [{:ex_cldr, "~> 2.34", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "0521316396c66877a2d636219767560bb2397c583341fcb154ecf9f3000e6ff8"},
"ex_cldr_lists": {:hex, :ex_cldr_lists, "2.10.0", "4d4c9877da2d0417fd832907d69974e8328969f75fafc79b05ccf85f549f6281", [:mix], [{:ex_cldr_numbers, "~> 2.25", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "adc040cde7b97f7fd7c0b35dd69ddb6fcf607303ae6355bb1851deae1f8b0652"},
- "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.31.3", "6ec8b18c395c0e8788d46da806f8f2abcbe4b0d809226d2a91363e9ccd85f2f5", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, ">= 2.14.2", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "b519de08ecc4a6402038f3aa75e8654f78ebd6fa714b7e585531504e648588fd"},
+ "ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.32.2", "5e0e3031d3f54b51fe7078a7a94592987b70b06d631bdc88813b222dc5a8b1bd", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, ">= 2.14.2", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "91257684a9c4d6abdf738f0cc5671837de876e69552e8bd4bc5fa1bfd5817713"},
"ex_cldr_units": {:hex, :ex_cldr_units, "3.16.2", "dbad303fba819981c578234e2aaf19d72efca16ea8b1c6ee46b26232cb45e232", [:mix], [{:cldr_utils, "~> 2.24", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.31", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_doc, "~> 0.18", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "851095319fb3205c1549619da742cd53a2804c1d9c204cf84014021e2a6ea7e5"},
- "ex_doc": {:hex, :ex_doc, "0.30.3", "bfca4d340e3b95f2eb26e72e4890da83e2b3a5c5b0e52607333bf5017284b063", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "fbc8702046c1d25edf79de376297e608ac78cdc3a29f075484773ad1718918b6"},
+ "ex_doc": {:hex, :ex_doc, "0.30.6", "5f8b54854b240a2b55c9734c4b1d0dd7bdd41f71a095d42a70445c03cf05a281", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bd48f2ddacf4e482c727f9293d9498e0881597eae6ddc3d9562bd7923375109f"},
"ex_json_schema": {:hex, :ex_json_schema, "0.10.1", "e03b746b6675a750c0bb1a5cc919f61353f7ab8450977e11ceede20e6180c560", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "66a64e60dadad89914d92f89c7e7906c57de75a8b79ac2480d0d53e1b8096fb0"},
- "ex_keccak": {:hex, :ex_keccak, "0.7.1", "0169f4b0c5073c5df61581d6282b12f1a1b764dcfcda4eeb1c819b5194c9ced0", [:mix], [{:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6.1", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "c18c19f66b6545b4b46b0c71c0cc0079de84e30b26365a92961e91697e8724ed"},
+ "ex_keccak": {:hex, :ex_keccak, "0.7.3", "33298f97159f6b0acd28f6e96ce5ea975a0f4a19f85fe615b4f4579b88b24d06", [:mix], [{:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6.1", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "4c5e6d9d5f77b64ab48769a0166a9814180d40ced68ed74ce60a5174ab55b3fc"},
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
"ex_rlp": {:hex, :ex_rlp, "0.6.0", "985391d2356a7cb8712a4a9a2deb93f19f2fbca0323f5c1203fcaf64d077e31e", [:mix], [], "hexpm", "7135db93b861d9e76821039b60b00a6a22d2c4e751bf8c444bffe7a042f1abaf"},
- "ex_secp256k1": {:hex, :ex_secp256k1, "0.7.0", "fa555152e8680c1e2df09ccc2884eccd25d8bc328c630b0b8952abe3745edc8f", [:mix], [{:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "2a8754c7b3d83bbcab4a188ed033254ca5c6ac252188ced0d382ca343096bf73"},
+ "ex_secp256k1": {:hex, :ex_secp256k1, "0.7.2", "33398c172813b90fab9ab75c12b98d16cfab472c6dcbde832b13c45ce1c01947", [:mix], [{:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "f3b1bf56e6992e28b9d86e3bf741a4aca3e641052eb47d13ae4f5f4d4944bdaf"},
"ex_utils": {:hex, :ex_utils, "0.1.7", "2c133e0bcdc49a858cf8dacf893308ebc05bc5fba501dc3d2935e65365ec0bf3", [:mix], [], "hexpm", "66d4fe75285948f2d1e69c2a5ddd651c398c813574f8d36a9eef11dc20356ef6"},
"exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], [], "hexpm", "1222419f706e01bfa1095aec9acf6421367dcfab798a6f67c54cf784733cd6b5"},
"exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"},
"expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"},
- "exvcr": {:hex, :exvcr, "0.14.2", "90830764b7a428c07bb1475628b4e020f34a081605b9484df6b7b3fe7e32ee9c", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:finch, "~> 0.16", [hex: :finch, repo: "hexpm", optional: true]}, {:httpoison, "~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "2ca98dabbfd10215cb2072fc5c83d91f6d1e1a7b5e576300c0ec6825ac97a070"},
+ "exvcr": {:hex, :exvcr, "0.14.4", "1aa5fe7d3f10b117251c158f8d28b39f7fc73d0a7628b2d0b75bf8cfb1111576", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:finch, "~> 0.16", [hex: :finch, repo: "hexpm", optional: true]}, {:httpoison, "~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "4e600568c02ed29d46bc2e2c74927d172ba06658aa8b14705c0207363c44cc94"},
"file_info": {:hex, :file_info, "0.0.4", "2e0e77f211e833f38ead22cb29ce53761d457d80b3ffe0ffe0eb93880b0963b2", [:mix], [{:mimetype_parser, "~> 0.1.2", [hex: :mimetype_parser, repo: "hexpm", optional: false]}], "hexpm", "50e7ad01c2c8b9339010675fe4dc4a113b8d6ca7eddce24d1d74fd0e762781a5"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"floki": {:hex, :floki, "0.34.3", "5e2dcaec5d7c228ce5b1d3501502e308b2d79eb655e4191751a1fe491c37feac", [:mix], [], "hexpm", "9577440eea5b97924b4bf3c7ea55f7b8b6dce589f9b28b096cc294a8dc342341"},
"flow": {:hex, :flow, "1.2.4", "1dd58918287eb286656008777cb32714b5123d3855956f29aa141ebae456922d", [:mix], [{:gen_stage, "~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}], "hexpm", "874adde96368e71870f3510b91e35bc31652291858c86c0e75359cbdd35eb211"},
"gen_stage": {:hex, :gen_stage, "1.2.1", "19d8b5e9a5996d813b8245338a28246307fd8b9c99d1237de199d21efc4c76a1", [:mix], [], "hexpm", "83e8be657fa05b992ffa6ac1e3af6d57aa50aace8f691fcf696ff02f8335b001"},
- "gettext": {:hex, :gettext, "0.22.3", "c8273e78db4a0bb6fba7e9f0fd881112f349a3117f7f7c598fa18c66c888e524", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "935f23447713954a6866f1bb28c3a878c4c011e802bcd68a726f5e558e4b64bd"},
- "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
+ "gettext": {:hex, :gettext, "0.23.1", "821e619a240e6000db2fc16a574ef68b3bd7fe0167ccc264a81563cc93e67a31", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "19d744a36b809d810d610b57c27b934425859d158ebd56561bc41f7eeb8795db"},
+ "hackney": {:hex, :hackney, "1.18.2", "d7ff544ddae5e1cb49e9cf7fa4e356d7f41b283989a1c304bfc47a8cc1cf966f", [:rebar3], [{:certifi, "~>2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "af94d5c9f97857db257090a4a10e5426ecb6f4918aa5cc666798566ae14b65fd"},
"hammer": {:hex, :hammer, "6.1.0", "f263e3c3e9946bd410ea0336b2abe0cb6260af4afb3a221e1027540706e76c55", [:make, :mix], [{:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm", "b47e415a562a6d072392deabcd58090d8a41182cf9044cdd6b0d0faaaf68ba57"},
"hammer_backend_redis": {:hex, :hammer_backend_redis, "6.1.2", "eb296bb4924928e24135308b2afc189201fd09411c870c6bbadea444a49b2f2c", [:mix], [{:hammer, "~> 6.0", [hex: :hammer, repo: "hexpm", optional: false]}, {:redix, "~> 1.1", [hex: :redix, repo: "hexpm", optional: false]}], "hexpm", "217ea066278910543a5e9b577d5bf2425419446b94fe76bdd9f255f39feec9fa"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
@@ -98,7 +98,7 @@
"oauth2": {:hex, :oauth2, "2.0.1", "70729503e05378697b958919bb2d65b002ba6b28c8112328063648a9348aaa3f", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "c64e20d4d105bcdbcbe03170fb530d0eddc3a3e6b135a87528a22c8aecf74c52"},
"optimal": {:hex, :optimal, "0.3.6", "46bbf52fbbbd238cda81e02560caa84f93a53c75620f1fe19e81e4ae7b07d1dd", [:mix], [], "hexpm", "1a06ea6a653120226b35b283a1cd10039550f2c566edcdec22b29316d73640fd"},
"parallel_stream": {:hex, :parallel_stream, "1.1.0", "f52f73eb344bc22de335992377413138405796e0d0ad99d995d9977ac29f1ca9", [:mix], [], "hexpm", "684fd19191aedfaf387bbabbeb8ff3c752f0220c8112eb907d797f4592d6e871"},
- "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
+ "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"phoenix": {:hex, :phoenix, "1.5.14", "2d5db884be496eefa5157505ec0134e66187cb416c072272420c5509d67bf808", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "207f1aa5520320cbb7940d7ff2dde2342162cf513875848f88249ea0ba02fef7"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"},
"phoenix_html": {:hex, :phoenix_html, "3.0.4", "232d41884fe6a9c42d09f48397c175cd6f0d443aaa34c7424da47604201df2e1", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "ce17fd3cf815b2ed874114073e743507704b1f5288bb03c304a77458485efc8b"},
@@ -109,7 +109,7 @@
"plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
"poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm", "ba8836feea4b394bb718a161fc59a288fe0109b5006d6bdf97b6badfcf6f0f25"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
- "postgrex": {:hex, :postgrex, "0.17.2", "a3ec9e3239d9b33f1e5841565c4eb200055c52cc0757a22b63ca2d529bbe764c", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "80a918a9e9531d39f7bd70621422f3ebc93c01618c645f2d91306f50041ed90c"},
+ "postgrex": {:hex, :postgrex, "0.17.3", "c92cda8de2033a7585dae8c61b1d420a1a1322421df84da9a82a6764580c503d", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "946cf46935a4fdca7a81448be76ba3503cff082df42c6ec1ff16a4bdfbfb098d"},
"prometheus": {:hex, :prometheus, "4.10.0", "792adbf0130ff61b5fa8826f013772af24b6e57b984445c8d602c8a0355704a1", [:mix, :rebar3], [{:quantile_estimator, "~> 0.2.1", [hex: :quantile_estimator, repo: "hexpm", optional: false]}], "hexpm", "2a99bb6dce85e238c7236fde6b0064f9834dc420ddbd962aac4ea2a3c3d59384"},
"prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"},
"prometheus_ex": {:git, "https://github.com/lanodan/prometheus.ex", "31f7fbe4b71b79ba27efc2a5085746c4011ceb8f", [branch: "fix/elixir-1.14"]},
@@ -123,10 +123,10 @@
"ratio": {:hex, :ratio, "2.4.2", "c8518f3536d49b1b00d88dd20d49f8b11abb7819638093314a6348139f14f9f9", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:numbers, "~> 5.2.0", [hex: :numbers, repo: "hexpm", optional: false]}], "hexpm", "441ef6f73172a3503de65ccf1769030997b0d533b1039422f1e5e0e0b4cbf89e"},
"redix": {:hex, :redix, "1.2.3", "3036e7c6080c42e1bbaa9168d1e28e367b01e8960a640a899b8ef8067273cb5e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:nimble_options, "~> 0.5.0 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "14e2bca8a03fad297a78a3d201032df260ee5f0e0ef9c173c0f9ca5b3e0331b7"},
"remote_ip": {:hex, :remote_ip, "1.1.0", "cb308841595d15df3f9073b7c39243a1dd6ca56e5020295cb012c76fbec50f2d", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "616ffdf66aaad6a72fc546dabf42eed87e2a99e97b09cbd92b10cc180d02ed74"},
- "rustler_precompiled": {:hex, :rustler_precompiled, "0.6.1", "160b545bce8bf9a3f1b436b2c10f53574036a0db628e40f393328cbbe593602f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "0dd269fa261c4e3df290b12031c575fff07a542749f7b0e8b744d72d66c43600"},
- "sobelow": {:hex, :sobelow, "0.12.2", "45f4d500e09f95fdb5a7b94c2838d6b26625828751d9f1127174055a78542cf5", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "2f0b617dce551db651145662b84c8da4f158e7abe049a76daaaae2282df01c5d"},
+ "rustler_precompiled": {:hex, :rustler_precompiled, "0.6.3", "f838d94bc35e1844973ee7266127b156fdc962e9e8b7ff666c8fb4fed7964d23", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "e18ecca3669a7454b3a2be75ae6c3ef01d550bc9a8cf5fbddcfff843b881d7c6"},
+ "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"},
"spandex": {:hex, :spandex, "3.2.0", "f8cd40146ea988c87f3c14054150c9a47ba17e53cd4515c00e1f93c29c45404d", [:mix], [{:decorator, "~> 1.2", [hex: :decorator, repo: "hexpm", optional: true]}, {:optimal, "~> 0.3.3", [hex: :optimal, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d0a7d5aef4c5af9cf5467f2003e8a5d8d2bdae3823a6cc95d776b9a2251d4d03"},
- "spandex_datadog": {:hex, :spandex_datadog, "1.3.0", "cabe82980f55612a8befa6c12904b1a429bf17faf7271a94b9aae278af6362cf", [:mix], [{:msgpax, "~> 2.2.1 or ~> 2.3", [hex: :msgpax, repo: "hexpm", optional: false]}, {:spandex, "~> 3.0", [hex: :spandex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c826e4e29d1612e866b2c7bae2df3beeee84fc57351968c2772672afe59b789c"},
+ "spandex_datadog": {:hex, :spandex_datadog, "1.4.0", "0594b9655b0af00ab9137122616bc0208b68ceec01e9916ab13d6fbb33dcce35", [:mix], [{:msgpax, "~> 2.2.1 or ~> 2.3", [hex: :msgpax, repo: "hexpm", optional: false]}, {:spandex, "~> 3.2", [hex: :spandex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "360f8e1b4db238c1749c4872b1697b096429927fa42b8858d0bb782067380123"},
"spandex_ecto": {:hex, :spandex_ecto, "0.7.0", "259ad2feb7c834e774ec623f99c0fbacca8d60a73be212f92b75e37f853c81be", [:mix], [{:spandex, "~> 2.2 or ~> 3.0", [hex: :spandex, repo: "hexpm", optional: false]}], "hexpm", "c64784be79d95538013b7c60828830411c5c7aff1f4e8d66dfe564b3c83b500e"},
"spandex_phoenix": {:hex, :spandex_phoenix, "1.1.0", "9cff829d05258dd49a227c56711b19b69a8fd5d4873d8e9a92a4f4097e7322ab", [:mix], [{:phoenix, "~> 1.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.3", [hex: :plug, repo: "hexpm", optional: false]}, {:spandex, "~> 2.2 or ~> 3.0", [hex: :spandex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "265fe05c1736485fbb75d66ef7576682ebf6428c391dd54d22217f612fd4ddad"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
@@ -139,7 +139,7 @@
"ueberauth": {:hex, :ueberauth, "0.10.5", "806adb703df87e55b5615cf365e809f84c20c68aa8c08ff8a416a5a6644c4b02", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3efd1f31d490a125c7ed453b926f7c31d78b97b8a854c755f5c40064bf3ac9e1"},
"ueberauth_auth0": {:hex, :ueberauth_auth0, "2.1.0", "0632d5844049fa2f26823f15e1120aa32f27df6f27ce515a4b04641736594bf4", [:mix], [{:oauth2, "~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "8d3b30fa27c95c9e82c30c4afb016251405706d2e9627e603c3c9787fd1314fc"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
- "wallaby": {:hex, :wallaby, "0.30.5", "c6a8dbb6f3195dbfe080b50ba707973983e32446f6f9fac514a43918682696bb", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "d759711983c90aaa5338b8b9dcff0c9eb0609ac0a45071f4ef9cbb298bb54077"},
+ "wallaby": {:hex, :wallaby, "0.30.6", "7dc4c1213f3b52c4152581d126632bc7e06892336d3a0f582853efeeabd45a71", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "50950c1d968549b54c20e16175c68c7fc0824138e2bb93feb11ef6add8eb23d4"},
"web_driver_client": {:hex, :web_driver_client, "0.2.0", "63b76cd9eb3b0716ec5467a0f8bead73d3d9612e63f7560d21357f03ad86e31a", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.3", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "83cc6092bc3e74926d1c8455f0ce927d5d1d36707b74d9a65e38c084aab0350f"},
"websocket_client": {:git, "https://github.com/blockscout/websocket_client.git", "0b4ecc5b1fb8a0bd1c8352728da787c20add53aa", [branch: "master"]},
}
diff --git a/rel/config.exs b/rel/config.exs
index 7d4f453589ca..3782a1b80d82 100644
--- a/rel/config.exs
+++ b/rel/config.exs
@@ -71,7 +71,7 @@ end
# will be used by default
release :blockscout do
- set version: "5.2.1-beta"
+ set version: "5.2.2-beta"
set applications: [
:runtime_tools,
block_scout_web: :permanent,