From 4afe4be5e505c7ba150b56215711380d8c328640 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Fri, 28 Nov 2025 19:38:05 -0800 Subject: [PATCH 01/56] Add a workflow to build and test Docker images --- .github/workflows/docker.yml | 167 ++++++++++++++++++++++++++++++++++- 1 file changed, 163 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 22a86db56..52f893bb9 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -18,10 +18,10 @@ permissions: jobs: build: - # Run on tag pushes OR on PRs that have the "docker" label + # Run on tag pushes OR on PRs that have the "docker" or "docker-test" label if: | github.event_name == 'push' || - (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'docker')) + (github.event_name == 'pull_request' && (contains(github.event.pull_request.labels.*.name, 'docker') || contains(github.event.pull_request.labels.*.name, 'docker-test'))) strategy: matrix: service: @@ -33,6 +33,7 @@ jobs: outputs: image-digest-frontend: ${{ matrix.service == 'frontend' && steps.docker-build.outputs.digest || '' }} image-digest-backend: ${{ matrix.service == 'backend' && steps.docker-build.outputs.digest || '' }} + tag: ${{ matrix.service == 'frontend' && (steps.set-tag-push.outputs.tag || steps.set-tag-pr.outputs.tag) || '' }} steps: - name: Replace the current swap file shell: bash @@ -65,7 +66,11 @@ jobs: # Only for tag pushes: use the Git tag as TAG - name: Set TAG from pushed tag if: github.event_name == 'push' - run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV + id: set-tag-push + run: | + TAG="${GITHUB_REF/refs\/tags\//}" + echo "TAG=${TAG}" >> $GITHUB_ENV + echo "tag=${TAG}" >> $GITHUB_OUTPUT - name: Add SHORT_SHA env property with commit short sha run: | @@ -86,13 +91,16 @@ jobs: # For PRs: use package.json version + short sha as TAG - name: Set TAG from service package.json for pull requests if: github.event_name == 'pull_request' + id: set-tag-pr run: | if [ "${{ matrix.service }}" = "frontend" ]; then VERSION=$(jq -r '.version' frontend/package.json) else VERSION=$(jq -r '.version' backend/package.json) fi - echo "TAG=v${VERSION}-${SHORT_SHA}" >> $GITHUB_ENV + TAG="v${VERSION}-${SHORT_SHA}" + echo "TAG=${TAG}" >> $GITHUB_ENV + echo "tag=${TAG}" >> $GITHUB_OUTPUT - name: Show set environment variables run: | @@ -178,3 +186,154 @@ jobs: docker buildx imagetools create \ --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:latest \ ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG + + test-images: + needs: build + # Only run for PRs with "docker-test" label + if: ${{ needs.build.result == 'success' && github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'docker-test') }} + runs-on: ubuntu-latest + timeout-minutes: 30 + name: Test built Docker images + steps: + - name: Checkout project + uses: actions/checkout@v4 + + - name: Add SHORT_SHA env property with commit short sha + run: | + SHA="${{ github.event.pull_request.head.sha }}" + echo "SHORT_SHA=${SHA:0:8}" >> $GITHUB_ENV + + - name: Set TAG from frontend package.json + run: | + VERSION=$(jq -r '.version' frontend/package.json) + echo "TAG=v${VERSION}-${SHORT_SHA}" >> $GITHUB_ENV + + - name: Show set environment variables + run: | + printf " TAG: %s\n" "$TAG" + printf " SHORT_SHA: %s\n" "$SHORT_SHA" + + - name: Init repo for Dockerization + run: docker/init.sh "$TAG" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build frontend image locally + run: | + docker buildx build \ + --tag test-frontend:$TAG \ + --build-arg commitHash=$SHORT_SHA \ + --load \ + --platform linux/amd64 \ + ./frontend/ + + - name: Build backend image locally + run: | + docker buildx build \ + --tag test-backend:$TAG \ + --build-context rustgbt=./rust \ + --build-context backend=./backend \ + --build-arg commitHash=$SHORT_SHA \ + --load \ + --platform linux/amd64 \ + ./backend/ + + - name: Generate docker-compose test file + run: | + cat > docker-compose.test.yml </dev/null; then + echo "Database is ready!" + break + fi + sleep 2 + elapsed=$((elapsed + 2)) + done + if [ $elapsed -ge $timeout ]; then + echo "Database did not become ready in time" + docker compose -f docker-compose.test.yml logs + exit 1 + fi + + - name: Verify containers are running + run: | + echo "Checking container status..." + docker compose -f docker-compose.test.yml ps + if ! docker compose -f docker-compose.test.yml ps | grep -q "Up"; then + echo "Some containers are not running" + docker compose -f docker-compose.test.yml logs + exit 1 + fi + echo "All containers are running successfully!" + + - name: Show container logs + if: failure() + run: | + docker compose -f docker-compose.test.yml logs + + - name: Clean up containers + if: always() + run: | + docker compose -f docker-compose.test.yml down -v From 1205d1592069c4b966fa0a61ed3b3f2bca51f8c3 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Fri, 28 Nov 2025 20:26:46 -0800 Subject: [PATCH 02/56] Login only if needed --- .github/workflows/docker.yml | 45 ++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 52f893bb9..50eee9d35 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -83,6 +83,9 @@ jobs: - name: Login to Docker for building + if: | + github.event_name == 'push' || + (github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'docker-test')) run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin - name: Checkout project @@ -139,16 +142,38 @@ jobs: - name: Run Docker buildx for ${{ matrix.service }} against tag id: docker-build run: | - docker buildx build \ - --cache-from "type=local,src=/tmp/.buildx-cache" \ - --cache-to "type=local,dest=/tmp/.buildx-cache,mode=max" \ - --platform linux/amd64,linux/arm64 \ - --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ - --build-context rustgbt=./rust \ - --build-context backend=./backend \ - --output "type=registry,push=true" \ - --build-arg commitHash=$SHORT_SHA \ - ./${{ matrix.service }}/ + # For docker-test label PRs, build locally without pushing + IS_DOCKER_TEST=false + if [ "${{ github.event_name }}" = "pull_request" ]; then + LABELS="${{ join(github.event.pull_request.labels.*.name, ' ') }}" + if echo "$LABELS" | grep -q "docker-test"; then + IS_DOCKER_TEST=true + fi + fi + + if [ "$IS_DOCKER_TEST" = "true" ]; then + docker buildx build \ + --cache-from "type=local,src=/tmp/.buildx-cache" \ + --cache-to "type=local,dest=/tmp/.buildx-cache,mode=max" \ + --platform linux/amd64,linux/arm64 \ + --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ + --build-context rustgbt=./rust \ + --build-context backend=./backend \ + --output "type=image,push=false" \ + --build-arg commitHash=$SHORT_SHA \ + ./${{ matrix.service }}/ + else + docker buildx build \ + --cache-from "type=local,src=/tmp/.buildx-cache" \ + --cache-to "type=local,dest=/tmp/.buildx-cache,mode=max" \ + --platform linux/amd64,linux/arm64 \ + --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ + --build-context rustgbt=./rust \ + --build-context backend=./backend \ + --output "type=registry,push=true" \ + --build-arg commitHash=$SHORT_SHA \ + ./${{ matrix.service }}/ + fi tag-latest: needs: build From f3311382e4cebcd08b9ba46f2b995ade6fcd3f44 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Fri, 28 Nov 2025 22:04:45 -0800 Subject: [PATCH 03/56] Skip building with tags --- .github/workflows/docker.yml | 46 +++++++++++------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 50eee9d35..2e5a7a2aa 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -141,39 +141,21 @@ jobs: - name: Run Docker buildx for ${{ matrix.service }} against tag id: docker-build + # Skip building/pushing images when this is a docker-test label PR + if: | + github.event_name == 'push' || + (github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'docker-test')) run: | - # For docker-test label PRs, build locally without pushing - IS_DOCKER_TEST=false - if [ "${{ github.event_name }}" = "pull_request" ]; then - LABELS="${{ join(github.event.pull_request.labels.*.name, ' ') }}" - if echo "$LABELS" | grep -q "docker-test"; then - IS_DOCKER_TEST=true - fi - fi - - if [ "$IS_DOCKER_TEST" = "true" ]; then - docker buildx build \ - --cache-from "type=local,src=/tmp/.buildx-cache" \ - --cache-to "type=local,dest=/tmp/.buildx-cache,mode=max" \ - --platform linux/amd64,linux/arm64 \ - --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ - --build-context rustgbt=./rust \ - --build-context backend=./backend \ - --output "type=image,push=false" \ - --build-arg commitHash=$SHORT_SHA \ - ./${{ matrix.service }}/ - else - docker buildx build \ - --cache-from "type=local,src=/tmp/.buildx-cache" \ - --cache-to "type=local,dest=/tmp/.buildx-cache,mode=max" \ - --platform linux/amd64,linux/arm64 \ - --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ - --build-context rustgbt=./rust \ - --build-context backend=./backend \ - --output "type=registry,push=true" \ - --build-arg commitHash=$SHORT_SHA \ - ./${{ matrix.service }}/ - fi + docker buildx build \ + --cache-from "type=local,src=/tmp/.buildx-cache" \ + --cache-to "type=local,dest=/tmp/.buildx-cache,mode=max" \ + --platform linux/amd64,linux/arm64 \ + --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ + --build-context rustgbt=./rust \ + --build-context backend=./backend \ + --output "type=registry,push=true" \ + --build-arg commitHash=$SHORT_SHA \ + ./${{ matrix.service }}/ tag-latest: needs: build From f1d831b8dd2dcb5cfec00ca218c8ff242d559836 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Fri, 28 Nov 2025 22:13:50 -0800 Subject: [PATCH 04/56] Fix empty prefix --- .github/workflows/docker.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2e5a7a2aa..c75b16491 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -18,10 +18,10 @@ permissions: jobs: build: - # Run on tag pushes OR on PRs that have the "docker" or "docker-test" label + # Run on tag pushes OR on PRs that have the "docker" label (but not "docker-test") if: | github.event_name == 'push' || - (github.event_name == 'pull_request' && (contains(github.event.pull_request.labels.*.name, 'docker') || contains(github.event.pull_request.labels.*.name, 'docker-test'))) + (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'docker') && !contains(github.event.pull_request.labels.*.name, 'docker-test')) strategy: matrix: service: @@ -83,9 +83,6 @@ jobs: - name: Login to Docker for building - if: | - github.event_name == 'push' || - (github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'docker-test')) run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin - name: Checkout project @@ -141,10 +138,6 @@ jobs: - name: Run Docker buildx for ${{ matrix.service }} against tag id: docker-build - # Skip building/pushing images when this is a docker-test label PR - if: | - github.event_name == 'push' || - (github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'docker-test')) run: | docker buildx build \ --cache-from "type=local,src=/tmp/.buildx-cache" \ @@ -195,9 +188,8 @@ jobs: ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG test-images: - needs: build - # Only run for PRs with "docker-test" label - if: ${{ needs.build.result == 'success' && github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'docker-test') }} + # Only run for PRs with "docker-test" label (independent of build job) + if: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'docker-test') }} runs-on: ubuntu-latest timeout-minutes: 30 name: Test built Docker images From 893d0deb1048a1d1de14283e832a71359feed1a3 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Fri, 28 Nov 2025 22:22:36 -0800 Subject: [PATCH 05/56] Change database user --- .github/workflows/docker.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c75b16491..18f95b340 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -285,11 +285,15 @@ jobs: MYSQL_PASSWORD: "mempool" MYSQL_ROOT_PASSWORD: "admin" image: mariadb:10.5.21 - user: "1000:1000" restart: on-failure stop_grace_period: 1m tmpfs: - /var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "mempool", "-pmempool"] + interval: 5s + timeout: 5s + retries: 10 EOF cat docker-compose.test.yml From f7a27174f8608c221cc37718b9ef60a55467dd26 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Sat, 29 Nov 2025 18:42:37 -0800 Subject: [PATCH 06/56] Reuse example docker-compose file --- .github/workflows/docker.yml | 119 ++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 18f95b340..c1aeb6d3c 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -238,63 +238,70 @@ jobs: --platform linux/amd64 \ ./backend/ - - name: Generate docker-compose test file + - name: Prepare docker-compose test file run: | - cat > docker-compose.test.yml < /tmp/modify_compose.py << 'SCRIPT_END' + import re + import os + import sys + + # Read the base docker-compose file + with open('docker/docker-compose.yml', 'r') as f: + content = f.read() + + # Get TAG from environment + tag = os.environ.get('TAG', '') + + # Replace image names with locally built test images + content = content.replace('image: mempool/frontend:latest', f'image: test-frontend:{tag}') + content = content.replace('image: mempool/backend:latest', f'image: test-backend:{tag}') + + # Change web port mapping from 80:8080 to 8080:8080 + content = content.replace('- 80:8080', '- 8080:8080') + + # Remove volumes from api service + content = re.sub(r' volumes:\n - \.\/data:\/backend\/cache\n', '', content) + + # For db service: remove user and volumes, add tmpfs and healthcheck + # Remove user line from db service (only the one in db service) + lines = content.split('\n') + in_db_service = False + new_lines = [] + for i, line in enumerate(lines): + if line.strip().startswith('db:'): + in_db_service = True + elif line.strip() and not line.startswith(' ') and not line.startswith('\t'): + in_db_service = False + if in_db_service and line.strip() == 'user: "1000:1000"': + continue + new_lines.append(line) + content = '\n'.join(new_lines) + + # Remove volumes section from db service + content = re.sub(r' volumes:\n - \.\/mysql\/data:\/var\/lib\/mysql\n', '', content) + + # Add tmpfs and healthcheck after stop_grace_period in db service + db_stop_grace = ' stop_grace_period: 1m' + db_additions = ' stop_grace_period: 1m\n tmpfs:\n - /var/lib/mysql\n healthcheck:\n test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "mempool", "-pmempool"]\n interval: 5s\n timeout: 5s\n retries: 10' + content = content.replace(db_stop_grace, db_additions, 1) + + # Add depends_on to web service after ports + web_ports = ' ports:\n - 8080:8080' + web_with_depends = ' ports:\n - 8080:8080\n depends_on:\n - api\n - db' + content = content.replace(web_ports, web_with_depends, 1) + + # Add depends_on to api service after command + api_command = ' command: "./wait-for-it.sh db:3306 --timeout=720 --strict -- ./start.sh"' + api_with_depends = ' command: "./wait-for-it.sh db:3306 --timeout=720 --strict -- ./start.sh"\n depends_on:\n - db' + content = content.replace(api_command, api_with_depends, 1) + + # Write the modified content + with open('docker-compose.test.yml', 'w') as f: + f.write(content) + + print("Generated docker-compose.test.yml") + SCRIPT_END + python3 /tmp/modify_compose.py cat docker-compose.test.yml - name: Start containers From a073003a1166e9a81b5b97e41288ea8dadb89da0 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Sat, 29 Nov 2025 19:27:16 -0800 Subject: [PATCH 07/56] Use proper health checks --- .github/workflows/docker.yml | 53 ++++++++++++++++++++++++++++-------- docker/docker-compose.yml | 17 ++++++++++++ 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c1aeb6d3c..54b6dd552 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -280,9 +280,9 @@ jobs: # Remove volumes section from db service content = re.sub(r' volumes:\n - \.\/mysql\/data:\/var\/lib\/mysql\n', '', content) - # Add tmpfs and healthcheck after stop_grace_period in db service + # Add tmpfs after stop_grace_period in db service (healthcheck already exists in base file) db_stop_grace = ' stop_grace_period: 1m' - db_additions = ' stop_grace_period: 1m\n tmpfs:\n - /var/lib/mysql\n healthcheck:\n test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "mempool", "-pmempool"]\n interval: 5s\n timeout: 5s\n retries: 10' + db_additions = ' stop_grace_period: 1m\n tmpfs:\n - /var/lib/mysql' content = content.replace(db_stop_grace, db_additions, 1) # Add depends_on to web service after ports @@ -310,33 +310,62 @@ jobs: - name: Wait for services to be ready run: | - echo "Waiting for database to be ready..." + echo "Waiting for all services (web, api, db) to be healthy..." timeout=120 elapsed=0 while [ $elapsed -lt $timeout ]; do - if docker compose -f docker-compose.test.yml exec -T db mysqladmin ping -h localhost -u mempool -pmempool --silent 2>/dev/null; then - echo "Database is ready!" + # Check health status for all services + PS_OUTPUT=$(docker compose -f docker-compose.test.yml ps) + HEALTHY_COUNT=$(echo "$PS_OUTPUT" | grep -c "(healthy)" || true) + if [ "$HEALTHY_COUNT" -ge 3 ]; then + echo "All services are healthy!" + echo "$PS_OUTPUT" break fi + echo "Waiting for services to be healthy... (${elapsed}s/${timeout}s)" + echo "$PS_OUTPUT" sleep 2 elapsed=$((elapsed + 2)) done if [ $elapsed -ge $timeout ]; then - echo "Database did not become ready in time" + echo "Services did not become healthy in time" + docker compose -f docker-compose.test.yml ps docker compose -f docker-compose.test.yml logs exit 1 fi - - name: Verify containers are running + - name: Verify containers are healthy run: | - echo "Checking container status..." - docker compose -f docker-compose.test.yml ps - if ! docker compose -f docker-compose.test.yml ps | grep -q "Up"; then - echo "Some containers are not running" + echo "Checking container health status..." + PS_OUTPUT=$(docker compose -f docker-compose.test.yml ps) + echo "$PS_OUTPUT" + + # Check that all three services (web, api, db) are healthy + HEALTHY_COUNT=$(echo "$PS_OUTPUT" | grep -c "(healthy)" || true) + if [ "$HEALTHY_COUNT" -lt 3 ]; then + echo "Not all containers are healthy. Expected 3 healthy services, found $HEALTHY_COUNT" docker compose -f docker-compose.test.yml logs exit 1 fi - echo "All containers are running successfully!" + + # Verify each service individually for better error messages + if ! echo "$PS_OUTPUT" | grep -q "web.*(healthy)"; then + echo "Web service is not healthy" + docker compose -f docker-compose.test.yml logs web + exit 1 + fi + if ! echo "$PS_OUTPUT" | grep -q "api.*(healthy)"; then + echo "API service is not healthy" + docker compose -f docker-compose.test.yml logs api + exit 1 + fi + if ! echo "$PS_OUTPUT" | grep -q "db.*(healthy)"; then + echo "Database service is not healthy" + docker compose -f docker-compose.test.yml logs db + exit 1 + fi + + echo "All containers are healthy!" - name: Show container logs if: failure() diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 4e1094306..663af98e1 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -12,6 +12,12 @@ services: command: "./wait-for db:3306 --timeout=720 -- nginx -g 'daemon off;'" ports: - 80:8080 + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8080/ | grep -q ' Date: Sun, 30 Nov 2025 10:20:36 -0800 Subject: [PATCH 08/56] Refactor Docker workflows for PRs and tag pushes --- .github/workflows/docker.yml | 361 ++++++++++++++++++----------------- 1 file changed, 188 insertions(+), 173 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 54b6dd552..4eaa918b0 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,60 +17,14 @@ permissions: contents: read jobs: - build: - # Run on tag pushes OR on PRs that have the "docker" label (but not "docker-test") - if: | - github.event_name == 'push' || - (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'docker') && !contains(github.event.pull_request.labels.*.name, 'docker-test')) - strategy: - matrix: - service: - - frontend - - backend + test-images: + # Always run on tag pushes and all pull requests runs-on: ubuntu-latest - timeout-minutes: 120 - name: Build and push to DockerHub - outputs: - image-digest-frontend: ${{ matrix.service == 'frontend' && steps.docker-build.outputs.digest || '' }} - image-digest-backend: ${{ matrix.service == 'backend' && steps.docker-build.outputs.digest || '' }} - tag: ${{ matrix.service == 'frontend' && (steps.set-tag-push.outputs.tag || steps.set-tag-pr.outputs.tag) || '' }} + timeout-minutes: 30 + name: Test built Docker images steps: - - name: Replace the current swap file - shell: bash - run: | - sudo swapoff /mnt/swapfile || true - sudo rm -f /mnt/swapfile - sudo fallocate -l 16G /mnt/swapfile - sudo chmod 600 /mnt/swapfile - sudo mkswap /mnt/swapfile - sudo swapon /mnt/swapfile - - - name: Show current memory and swap status - shell: bash - run: | - sudo free -h - echo - sudo swapon --show - - - name: Mount a tmpfs over /var/lib/docker - shell: bash - run: | - if [ ! -d "/var/lib/docker" ]; then - echo "Directory '/var/lib/docker' not found" - exit 1 - fi - sudo mount -t tmpfs -o size=12G tmpfs /var/lib/docker - sudo systemctl restart docker - sudo df -h | grep docker - - # Only for tag pushes: use the Git tag as TAG - - name: Set TAG from pushed tag - if: github.event_name == 'push' - id: set-tag-push - run: | - TAG="${GITHUB_REF/refs\/tags\//}" - echo "TAG=${TAG}" >> $GITHUB_ENV - echo "tag=${TAG}" >> $GITHUB_OUTPUT + - name: Checkout project + uses: actions/checkout@v4 - name: Add SHORT_SHA env property with commit short sha run: | @@ -81,131 +35,20 @@ jobs: fi echo "SHORT_SHA=${SHA:0:8}" >> $GITHUB_ENV - - - name: Login to Docker for building - run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin - - - name: Checkout project - uses: actions/checkout@v4 - - # For PRs: use package.json version + short sha as TAG - - name: Set TAG from service package.json for pull requests - if: github.event_name == 'pull_request' - id: set-tag-pr + - name: Set TAG from pushed tag or package.json run: | - if [ "${{ matrix.service }}" = "frontend" ]; then - VERSION=$(jq -r '.version' frontend/package.json) + if [ "${{ github.event_name }}" = "push" ]; then + TAG="${GITHUB_REF/refs\/tags\//}" else - VERSION=$(jq -r '.version' backend/package.json) + FRONTEND_VERSION=$(jq -r '.version' frontend/package.json) + BACKEND_VERSION=$(jq -r '.version' backend/package.json) + if [ "$FRONTEND_VERSION" != "$BACKEND_VERSION" ]; then + echo "Error: Frontend version ($FRONTEND_VERSION) and backend version ($BACKEND_VERSION) do not match" + exit 1 + fi + TAG="v${FRONTEND_VERSION}-${SHORT_SHA}" fi - TAG="v${VERSION}-${SHORT_SHA}" echo "TAG=${TAG}" >> $GITHUB_ENV - echo "tag=${TAG}" >> $GITHUB_OUTPUT - - - name: Show set environment variables - run: | - printf " TAG: %s\n" "$TAG" - printf " SHORT_SHA: %s\n" "$SHORT_SHA" - - - name: Init repo for Dockerization - run: docker/init.sh "$TAG" - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - with: - platforms: linux/amd64,linux/arm64 - id: qemu - - - name: Setup Docker buildx action - uses: docker/setup-buildx-action@v3 - with: - platforms: linux/amd64,linux/arm64 - driver-opts: | - network=host - id: buildx - - - name: Available platforms - run: echo ${{ steps.buildx.outputs.platforms }} - - - name: Cache Docker layers - uses: actions/cache@v3 - id: cache - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ matrix.service }}-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx-${{ matrix.service }}- - - - name: Run Docker buildx for ${{ matrix.service }} against tag - id: docker-build - run: | - docker buildx build \ - --cache-from "type=local,src=/tmp/.buildx-cache" \ - --cache-to "type=local,dest=/tmp/.buildx-cache,mode=max" \ - --platform linux/amd64,linux/arm64 \ - --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ - --build-context rustgbt=./rust \ - --build-context backend=./backend \ - --output "type=registry,push=true" \ - --build-arg commitHash=$SHORT_SHA \ - ./${{ matrix.service }}/ - - tag-latest: - needs: build - # Only for successful *tag pushes* and only for "plain" versions (no '-') - if: ${{ needs.build.result == 'success' && github.event_name == 'push' && !contains(github.ref_name, '-') }} - runs-on: ubuntu-latest - timeout-minutes: 30 - name: Tag release build as latest - strategy: - matrix: - service: - - frontend - - backend - steps: - - name: Set env variables - run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - with: - platforms: linux/amd64,linux/arm64 - - - name: Setup Docker buildx action - uses: docker/setup-buildx-action@v3 - with: - platforms: linux/amd64,linux/arm64 - driver-opts: | - network=host - - - name: Login to Docker Hub - run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin - - - name: Tag as latest for ${{ matrix.service }} - run: | - docker buildx imagetools create \ - --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:latest \ - ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG - - test-images: - # Only run for PRs with "docker-test" label (independent of build job) - if: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'docker-test') }} - runs-on: ubuntu-latest - timeout-minutes: 30 - name: Test built Docker images - steps: - - name: Checkout project - uses: actions/checkout@v4 - - - name: Add SHORT_SHA env property with commit short sha - run: | - SHA="${{ github.event.pull_request.head.sha }}" - echo "SHORT_SHA=${SHA:0:8}" >> $GITHUB_ENV - - - name: Set TAG from frontend package.json - run: | - VERSION=$(jq -r '.version' frontend/package.json) - echo "TAG=v${VERSION}-${SHORT_SHA}" >> $GITHUB_ENV - name: Show set environment variables run: | @@ -376,3 +219,175 @@ jobs: if: always() run: | docker compose -f docker-compose.test.yml down -v + + build: + needs: test-images + # Run on tag pushes OR on PRs with "docker-push" label (after test-images passes) + if: | + needs.test-images.result == 'success' && + (github.event_name == 'push' || + (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'docker-push'))) + strategy: + matrix: + service: + - frontend + - backend + runs-on: ubuntu-latest + timeout-minutes: 120 + name: Build and push to DockerHub + outputs: + image-digest-frontend: ${{ matrix.service == 'frontend' && steps.docker-build.outputs.digest || '' }} + image-digest-backend: ${{ matrix.service == 'backend' && steps.docker-build.outputs.digest || '' }} + tag: ${{ matrix.service == 'frontend' && (steps.set-tag-push.outputs.tag || steps.set-tag-pr.outputs.tag) || '' }} + steps: + - name: Replace the current swap file + shell: bash + run: | + sudo swapoff /mnt/swapfile || true + sudo rm -f /mnt/swapfile + sudo fallocate -l 16G /mnt/swapfile + sudo chmod 600 /mnt/swapfile + sudo mkswap /mnt/swapfile + sudo swapon /mnt/swapfile + + - name: Show current memory and swap status + shell: bash + run: | + sudo free -h + echo + sudo swapon --show + + - name: Mount a tmpfs over /var/lib/docker + shell: bash + run: | + if [ ! -d "/var/lib/docker" ]; then + echo "Directory '/var/lib/docker' not found" + exit 1 + fi + sudo mount -t tmpfs -o size=12G tmpfs /var/lib/docker + sudo systemctl restart docker + sudo df -h | grep docker + + # Only for tag pushes: use the Git tag as TAG + - name: Set TAG from pushed tag + if: github.event_name == 'push' + id: set-tag-push + run: | + TAG="${GITHUB_REF/refs\/tags\//}" + echo "TAG=${TAG}" >> $GITHUB_ENV + echo "tag=${TAG}" >> $GITHUB_OUTPUT + + - name: Add SHORT_SHA env property with commit short sha + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + SHA="${{ github.event.pull_request.head.sha }}" + else + SHA="${GITHUB_SHA}" + fi + echo "SHORT_SHA=${SHA:0:8}" >> $GITHUB_ENV + + + - name: Login to Docker for building + run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin + + - name: Checkout project + uses: actions/checkout@v4 + + # For PRs: use package.json version + short sha as TAG + - name: Set TAG from service package.json for pull requests + if: github.event_name == 'pull_request' + id: set-tag-pr + run: | + if [ "${{ matrix.service }}" = "frontend" ]; then + VERSION=$(jq -r '.version' frontend/package.json) + else + VERSION=$(jq -r '.version' backend/package.json) + fi + TAG="v${VERSION}-${SHORT_SHA}" + echo "TAG=${TAG}" >> $GITHUB_ENV + echo "tag=${TAG}" >> $GITHUB_OUTPUT + + - name: Show set environment variables + run: | + printf " TAG: %s\n" "$TAG" + printf " SHORT_SHA: %s\n" "$SHORT_SHA" + + - name: Init repo for Dockerization + run: docker/init.sh "$TAG" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: linux/amd64,linux/arm64 + id: qemu + + - name: Setup Docker buildx action + uses: docker/setup-buildx-action@v3 + with: + platforms: linux/amd64,linux/arm64 + driver-opts: | + network=host + id: buildx + + - name: Available platforms + run: echo ${{ steps.buildx.outputs.platforms }} + + - name: Cache Docker layers + uses: actions/cache@v3 + id: cache + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ matrix.service }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx-${{ matrix.service }}- + + - name: Run Docker buildx for ${{ matrix.service }} against tag + id: docker-build + run: | + docker buildx build \ + --cache-from "type=local,src=/tmp/.buildx-cache" \ + --cache-to "type=local,dest=/tmp/.buildx-cache,mode=max" \ + --platform linux/amd64,linux/arm64 \ + --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ + --build-context rustgbt=./rust \ + --build-context backend=./backend \ + --output "type=registry,push=true" \ + --build-arg commitHash=$SHORT_SHA \ + ./${{ matrix.service }}/ + + tag-latest: + needs: build + # Only for successful tag pushes (not PRs with docker-push label) and only for "plain" versions (no '-') + if: ${{ needs.build.result == 'success' && github.event_name == 'push' && !contains(github.ref_name, '-') }} + runs-on: ubuntu-latest + timeout-minutes: 30 + name: Tag release build as latest + strategy: + matrix: + service: + - frontend + - backend + steps: + - name: Set env variables + run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: linux/amd64,linux/arm64 + + - name: Setup Docker buildx action + uses: docker/setup-buildx-action@v3 + with: + platforms: linux/amd64,linux/arm64 + driver-opts: | + network=host + + - name: Login to Docker Hub + run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin + + - name: Tag as latest for ${{ matrix.service }} + run: | + docker buildx imagetools create \ + --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:latest \ + ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG From 171df606463662dbd965875540ad8c27f5252b72 Mon Sep 17 00:00:00 2001 From: natsoni Date: Tue, 23 Dec 2025 11:39:10 +0100 Subject: [PATCH 09/56] Migrate bootstrap import and Sass color usage --- frontend/src/styles.scss | 46 ++++++++++++++++++++++++++----- frontend/src/theme-bukele.scss | 4 ++- frontend/src/theme-contrast.scss | 4 ++- frontend/src/theme-softsimon.scss | 4 ++- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 8ef7dd82a..2f0eb182a 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -1,3 +1,5 @@ +@use "sass:color"; + /* Theme */ $bg: #11131f; $active-bg: #000000; @@ -38,14 +40,9 @@ $pagination-disabled-bg: $bg; $custom-select-indicator-color: $fg; -.input-group-text { - background-color: #1c2031 !important; - border: 1px solid #20263e !important; -} - $link-color: $info; $link-decoration: none !default; -$link-hover-color: darken($link-color, 15%) !default; +$link-hover-color: color.adjust($link-color, $lightness: -15%) !default; $link-hover-decoration: underline !default; $dropdown-bg: $bg; @@ -57,7 +54,42 @@ $dropdown-link-hover-bg: $active-bg; $dropdown-link-active-color: $fg; $dropdown-link-active-bg: $active-bg; -@import "bootstrap/scss/bootstrap"; +@use "bootstrap/scss/bootstrap" with ( + $body-bg: $body-bg, + $body-color: $body-color, + $gray-800: $gray-800, + $gray-700: $gray-700, + $nav-tabs-link-active-bg: $nav-tabs-link-active-bg, + $primary: $primary, + $secondary: $secondary, + $success: $success, + $info: $info, + $h5-font-size: $h5-font-size, + $pagination-bg: $pagination-bg, + $pagination-border-color: $pagination-border-color, + $pagination-disabled-bg: $pagination-disabled-bg, + $pagination-disabled-border-color: $pagination-disabled-border-color, + $pagination-active-color: $pagination-active-color, + $pagination-active-bg: $pagination-active-bg, + $pagination-hover-bg: $pagination-hover-bg, + $pagination-hover-border-color: $pagination-hover-border-color, + $custom-select-indicator-color: $custom-select-indicator-color, + $link-color: $link-color, + $link-decoration: $link-decoration, + $link-hover-color: $link-hover-color, + $link-hover-decoration: $link-hover-decoration, + $dropdown-bg: $dropdown-bg, + $dropdown-link-color: $dropdown-link-color, + $dropdown-link-hover-color: $dropdown-link-hover-color, + $dropdown-link-hover-bg: $dropdown-link-hover-bg, + $dropdown-link-active-color: $dropdown-link-active-color, + $dropdown-link-active-bg: $dropdown-link-active-bg +); + +.input-group-text { + background-color: #1c2031 !important; + border: 1px solid #20263e !important; +} :root { --bg: #{$bg}; diff --git a/frontend/src/theme-bukele.scss b/frontend/src/theme-bukele.scss index afb2d2e76..0046771b9 100644 --- a/frontend/src/theme-bukele.scss +++ b/frontend/src/theme-bukele.scss @@ -1,3 +1,5 @@ +@use "sass:color"; + /* Theme */ $bg: #11131f; $active-bg: #000000; @@ -45,7 +47,7 @@ $custom-select-indicator-color: $fg; $link-color: $info; $link-decoration: none !default; -$link-hover-color: darken($link-color, 15%) !default; +$link-hover-color: color.adjust($link-color, $lightness: -15%) !default; $link-hover-decoration: underline !default; $dropdown-bg: $bg; diff --git a/frontend/src/theme-contrast.scss b/frontend/src/theme-contrast.scss index 6d80f1edb..de7e9dec9 100644 --- a/frontend/src/theme-contrast.scss +++ b/frontend/src/theme-contrast.scss @@ -1,3 +1,5 @@ +@use "sass:color"; + /* Theme */ $bg: #11131f; $active-bg: #000000; @@ -45,7 +47,7 @@ $custom-select-indicator-color: $fg; $link-color: $info; $link-decoration: none !default; -$link-hover-color: darken($link-color, 15%) !default; +$link-hover-color: color.adjust($link-color, $lightness: -15%) !default; $link-hover-decoration: underline !default; $dropdown-bg: $bg; diff --git a/frontend/src/theme-softsimon.scss b/frontend/src/theme-softsimon.scss index 4e9b3e782..b366b753a 100644 --- a/frontend/src/theme-softsimon.scss +++ b/frontend/src/theme-softsimon.scss @@ -1,3 +1,5 @@ +@use "sass:color"; + /* Theme */ $bg: #1d1f31; $active-bg: #11131f; @@ -45,7 +47,7 @@ $custom-select-indicator-color: $fg; $link-color: $info; $link-decoration: none !default; -$link-hover-color: darken($link-color, 15%) !default; +$link-hover-color: color.adjust($link-color, $lightness: -15%) !default; $link-hover-decoration: underline !default; $dropdown-bg: $bg; From 65fb3c25fcdb2f5b911b39558ab30f219b7505ef Mon Sep 17 00:00:00 2001 From: natsoni Date: Tue, 23 Dec 2025 11:41:25 +0100 Subject: [PATCH 10/56] Fix nested rules warnings in SCSS files --- .../blocks-list/blocks-list.component.scss | 22 +++++++++---------- .../fees-box/fees-box.component.scss | 16 +++++++------- .../master-page/master-page.component.scss | 2 +- .../pool-ranking/pool-ranking.component.scss | 2 +- .../app/components/pool/pool.component.scss | 8 +++---- .../treasuries-pie.component.scss | 2 +- .../justice-list/justice-list.component.scss | 6 ++--- .../nodes-per-isp-chart.component.scss | 2 +- .../top-nodes-per-capacity.component.scss | 6 ++--- .../top-nodes-per-channels.component.scss | 8 +++---- frontend/src/styles.scss | 4 ++-- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.scss b/frontend/src/app/components/blocks-list/blocks-list.component.scss index 9e4465cf1..6c47eb0bf 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.scss +++ b/frontend/src/app/components/blocks-list/blocks-list.component.scss @@ -53,13 +53,13 @@ tr, td, th { .pool { width: 17%; - @media (max-width: 576px) { - width: 34%; - } overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; + @media (max-width: 576px) { + width: 34%; + } } .pool.widget { width: 40%; @@ -138,16 +138,16 @@ tr, td, th { .txs { padding-right: 20px; width: 6%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 100px; @media (max-width: 1100px) { padding-right: 10px; } @media (max-width: 875px) { display: none; } - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - max-width: 100px; } .txs.widget { padding-right: 0; @@ -186,14 +186,14 @@ tr, td, th { .reward { width: 8%; - @media (max-width: 576px) { - width: 7%; - padding-right: 30px; - } overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 130px; + @media (max-width: 576px) { + width: 7%; + padding-right: 30px; + } } .reward.widget { width: 20%; diff --git a/frontend/src/app/components/fees-box/fees-box.component.scss b/frontend/src/app/components/fees-box/fees-box.component.scss index c5843f58b..d1a5b4fff 100644 --- a/frontend/src/app/components/fees-box/fees-box.component.scss +++ b/frontend/src/app/components/fees-box/fees-box.component.scss @@ -26,12 +26,12 @@ width: 100px; margin: 0; width: -webkit-fill-available; + margin: 0 auto 0px; &:first-child { @media (767px < width < 992px), (width < 576px) { display: none } } - margin: 0 auto 0px; &:last-child { margin-bottom: 0; } @@ -81,11 +81,11 @@ transition: background-color 1s; color: #fff; &.priority { + width: 75%; + border-radius: 0px 10px 10px 0px; @media (767px < width < 992px), (width < 576px) { width: 100%; } - width: 75%; - border-radius: 0px 10px 10px 0px; } &:first-child { @media (767px < width < 992px), (width < 576px) { @@ -115,15 +115,15 @@ padding-top: 2px; font-size: 12px; width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-left: 5px; + padding-right: 5px; @media (767px < width < 992px), (width < 576px) { width: 33%; } &.prority { width: 33%; } - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - padding-left: 5px; - padding-right: 5px; } \ No newline at end of file diff --git a/frontend/src/app/components/master-page/master-page.component.scss b/frontend/src/app/components/master-page/master-page.component.scss index 798609998..44f63dd89 100644 --- a/frontend/src/app/components/master-page/master-page.component.scss +++ b/frontend/src/app/components/master-page/master-page.component.scss @@ -107,10 +107,10 @@ li.nav-item { .navbar-collapse { + justify-content: flex-end; @media (min-width: 564px) { flex-basis: auto; } - justify-content: flex-end; } @media (min-width: 992px) { diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.scss b/frontend/src/app/components/pool-ranking/pool-ranking.component.scss index cf53ebe14..786e0ce39 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.scss +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.scss @@ -21,10 +21,10 @@ .chart { max-height: 400px; + margin-bottom: 20px; @media (max-width: 767.98px) { max-height: 230px; } - margin-bottom: 20px; } .chart-widget { width: 100%; diff --git a/frontend/src/app/components/pool/pool.component.scss b/frontend/src/app/components/pool/pool.component.scss index f09ac0d65..7789a5630 100644 --- a/frontend/src/app/components/pool/pool.component.scss +++ b/frontend/src/app/components/pool/pool.component.scss @@ -34,10 +34,10 @@ .chart { margin-top: 10px; margin-bottom: 20px; + height: 400px; @media (max-width: 768px) { margin-bottom: 10px; } - height: 400px; } div.scrollable { @@ -121,9 +121,6 @@ div.scrollable { } .txs { - @media (max-width: 938px) { - display: none; - } padding-right: 40px; @media (max-width: 1100px) { padding-right: 10px; @@ -134,6 +131,9 @@ div.scrollable { @media (max-width: 567px) { padding-right: 10px; } + @media (max-width: 938px) { + display: none; + } } .size { diff --git a/frontend/src/app/components/treasuries/treasuries-pie/treasuries-pie.component.scss b/frontend/src/app/components/treasuries/treasuries-pie/treasuries-pie.component.scss index cf53ebe14..786e0ce39 100644 --- a/frontend/src/app/components/treasuries/treasuries-pie/treasuries-pie.component.scss +++ b/frontend/src/app/components/treasuries/treasuries-pie/treasuries-pie.component.scss @@ -21,10 +21,10 @@ .chart { max-height: 400px; + margin-bottom: 20px; @media (max-width: 767.98px) { max-height: 230px; } - margin-bottom: 20px; } .chart-widget { width: 100%; diff --git a/frontend/src/app/lightning/justice-list/justice-list.component.scss b/frontend/src/app/lightning/justice-list/justice-list.component.scss index 3547c447f..a368dd48d 100644 --- a/frontend/src/app/lightning/justice-list/justice-list.component.scss +++ b/frontend/src/app/lightning/justice-list/justice-list.component.scss @@ -19,13 +19,13 @@ tr, td, th { .pool { width: 15%; - @media (max-width: 575px) { - width: 75%; - } overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; + @media (max-width: 575px) { + width: 75%; + } } .pool-name { display: inline-block; diff --git a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.scss b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.scss index e1b66cc2b..a2c0e5e21 100644 --- a/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.scss +++ b/frontend/src/app/lightning/nodes-per-isp-chart/nodes-per-isp-chart.component.scss @@ -10,13 +10,13 @@ padding: 0px 15px; width: 100%; height: calc(100% - 140px); + margin-bottom: 25px; @media (max-width: 992px) { height: calc(100% - 190px); }; @media (max-width: 575px) { height: calc(100% - 230px); }; - margin-bottom: 25px; } .chart { diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.scss b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.scss index 89f144135..aa72d3f46 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.scss +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.scss @@ -19,13 +19,13 @@ tr, td, th { .pool { width: 15%; - @media (max-width: 575px) { - width: 75%; - } overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; + @media (max-width: 575px) { + width: 75%; + } } .pool-name { display: inline-block; diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.scss b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.scss index 63d65bcf8..759173f9d 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.scss +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.scss @@ -19,13 +19,13 @@ tr, td, th { .pool { width: 15%; - @media (max-width: 576px) { - width: 75%; - } overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; + @media (max-width: 576px) { + width: 75%; + } } .pool-name { display: inline-block; @@ -56,4 +56,4 @@ tr, td, th { @media (max-width: 575px) { display: none !important; } -} \ No newline at end of file +} diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 2f0eb182a..634ec823a 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -1130,11 +1130,11 @@ th { .fee-progress-bar { @extend .fee-progress-bar; &.priority { + width: 75%; + border-radius: 10px 0px 0px 10px !important; @media (767px < width < 992px), (width < 576px) { width: 100%; } - width: 75%; - border-radius: 10px 0px 0px 10px !important; } } From e75db8d7451caa46fe2b8d81810497bc7b2c7d9d Mon Sep 17 00:00:00 2001 From: natsoni Date: Tue, 23 Dec 2025 11:41:44 +0100 Subject: [PATCH 11/56] Allow qrcode CommonJS dependency --- frontend/angular.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/angular.json b/frontend/angular.json index 2bf92c67c..d7acbeeaa 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -197,7 +197,10 @@ "buildOptimizer": false, "sourceMap": true, "optimization": false, - "namedChunks": true + "namedChunks": true, + "allowedCommonJsDependencies": [ + "qrcode" + ] }, "configurations": { "production": { From 15fb272144a4f5632d6a674d70d09380d23382db Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 28 Dec 2025 20:35:24 +0000 Subject: [PATCH 12/56] fix logger jest mock to unbork backend tests --- backend/testSetup.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/testSetup.ts b/backend/testSetup.ts index ca51bbbe6..d66c3e142 100644 --- a/backend/testSetup.ts +++ b/backend/testSetup.ts @@ -1,5 +1,14 @@ jest.mock('./mempool-config.json', () => ({}), { virtual: true }); -jest.mock('./src/logger.ts', () => ({}), { virtual: true }); +jest.mock('./src/logger.ts', () => ({ + emerg: jest.fn(), + alert: jest.fn(), + crit: jest.fn(), + err: jest.fn(), + warn: jest.fn(), + notice: jest.fn(), + info: jest.fn(), + debug: jest.fn(), +}), { virtual: true }); jest.mock('./src/api/rbf-cache.ts', () => ({}), { virtual: true }); jest.mock('./src/api/mempool.ts', () => ({}), { virtual: true }); jest.mock('./src/api/memory-cache.ts', () => ({}), { virtual: true }); From 402012fbe09a1de288554562de5efc77738e1e83 Mon Sep 17 00:00:00 2001 From: mononaut <83316221+mononaut@users.noreply.github.com> Date: Sun, 28 Dec 2025 20:40:43 +0000 Subject: [PATCH 13/56] Update backend/testSetup.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- backend/testSetup.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/testSetup.ts b/backend/testSetup.ts index d66c3e142..12cf5bdb8 100644 --- a/backend/testSetup.ts +++ b/backend/testSetup.ts @@ -8,6 +8,11 @@ jest.mock('./src/logger.ts', () => ({ notice: jest.fn(), info: jest.fn(), debug: jest.fn(), + tags: { + mining: 'mining', + ln: 'ln', + goggles: 'goggles', + }, }), { virtual: true }); jest.mock('./src/api/rbf-cache.ts', () => ({}), { virtual: true }); jest.mock('./src/api/mempool.ts', () => ({}), { virtual: true }); From 3a6bbdd14293aca01d906a62f19e93ca77036cdc Mon Sep 17 00:00:00 2001 From: mononaut <83316221+mononaut@users.noreply.github.com> Date: Sun, 28 Dec 2025 20:40:50 +0000 Subject: [PATCH 14/56] Update backend/testSetup.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- backend/testSetup.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/testSetup.ts b/backend/testSetup.ts index 12cf5bdb8..24d42dd3c 100644 --- a/backend/testSetup.ts +++ b/backend/testSetup.ts @@ -8,6 +8,7 @@ jest.mock('./src/logger.ts', () => ({ notice: jest.fn(), info: jest.fn(), debug: jest.fn(), + updateNetwork: jest.fn(), tags: { mining: 'mining', ln: 'ln', From 0a8733eaf7a82e3d6dac3ed67d85f7a171a249b5 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 31 Dec 2025 08:48:43 +0000 Subject: [PATCH 15/56] fix subdomain customization --- frontend/src/app/graphs/graphs.routing.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/graphs/graphs.routing.module.ts b/frontend/src/app/graphs/graphs.routing.module.ts index 8655de8d5..7414ed077 100644 --- a/frontend/src/app/graphs/graphs.routing.module.ts +++ b/frontend/src/app/graphs/graphs.routing.module.ts @@ -28,7 +28,7 @@ import { WalletComponent } from '@components/wallet/wallet.component'; const browserWindow = window || {}; // @ts-ignore const browserWindowEnv = browserWindow.__env || {}; -const isCustomized = browserWindowEnv?.customize; +const isCustomized = browserWindowEnv?.customize?.dashboard; const routes: Routes = [ { From df11a3c80c875787e5f676b3de7fd1aee875a51a Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 4 Jan 2026 03:36:31 +0000 Subject: [PATCH 16/56] remove unnecessary og:image:type tags --- frontend/src/app/services/opengraph.service.ts | 3 --- frontend/src/index.liquid.html | 1 - frontend/src/index.mempool.html | 1 - 3 files changed, 5 deletions(-) diff --git a/frontend/src/app/services/opengraph.service.ts b/frontend/src/app/services/opengraph.service.ts index 47b9d87d4..d66602737 100644 --- a/frontend/src/app/services/opengraph.service.ts +++ b/frontend/src/app/services/opengraph.service.ts @@ -55,7 +55,6 @@ export class OpenGraphService { const ogImageUrl = `${window.location.protocol}//${window.location.host}/render/${lang}/preview${this.router.url}`; this.metaService.updateTag({ property: 'og:image', content: ogImageUrl }); this.metaService.updateTag({ name: 'twitter:image', content: ogImageUrl }); - this.metaService.updateTag({ property: 'og:image:type', content: 'image/png' }); this.metaService.updateTag({ property: 'og:image:width', content: '1200' }); this.metaService.updateTag({ property: 'og:image:height', content: '600' }); } @@ -63,7 +62,6 @@ export class OpenGraphService { clearOgImage() { this.metaService.updateTag({ property: 'og:image', content: this.defaultImageUrl }); this.metaService.updateTag({ name: 'twitter:image', content: this.defaultImageUrl }); - this.metaService.updateTag({ property: 'og:image:type', content: 'image/png' }); this.metaService.updateTag({ property: 'og:image:width', content: '1000' }); this.metaService.updateTag({ property: 'og:image:height', content: '500' }); } @@ -71,7 +69,6 @@ export class OpenGraphService { setManualOgImage(imageFilename) { const ogImage = `${window.location.protocol}//${window.location.host}/resources/previews/${imageFilename}`; this.metaService.updateTag({ property: 'og:image', content: ogImage }); - this.metaService.updateTag({ property: 'og:image:type', content: 'image/jpeg' }); this.metaService.updateTag({ property: 'og:image:width', content: '2000' }); this.metaService.updateTag({ property: 'og:image:height', content: '1000' }); this.metaService.updateTag({ name: 'twitter:image', content: ogImage }); diff --git a/frontend/src/index.liquid.html b/frontend/src/index.liquid.html index 5aa14cd2d..caaf5f01c 100644 --- a/frontend/src/index.liquid.html +++ b/frontend/src/index.liquid.html @@ -9,7 +9,6 @@ - diff --git a/frontend/src/index.mempool.html b/frontend/src/index.mempool.html index 14dc8dcc5..cde210665 100644 --- a/frontend/src/index.mempool.html +++ b/frontend/src/index.mempool.html @@ -20,7 +20,6 @@ - From b1d76a8e3f99a38b7ebb597c9e292cdf959fbbab Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Sat, 3 Jan 2026 20:29:45 -0800 Subject: [PATCH 17/56] Fix a few lint errors --- frontend/cypress.config.ts | 2 +- frontend/cypress/e2e/liquid/liquid.spec.ts | 2 +- .../e2e/liquidtestnet/liquidtestnet.spec.ts | 4 +- frontend/cypress/e2e/mainnet/mainnet.spec.ts | 10 +- frontend/cypress/support/PageIdleDetector.ts | 16 +- frontend/cypress/support/commands.ts | 60 +- frontend/cypress/support/index.d.ts | 2 +- frontend/cypress/support/websocket.ts | 12 +- frontend/src/app/app-routing.module.ts | 2 +- frontend/src/app/app.constants.ts | 78 +- frontend/src/app/app.preloading-strategy.ts | 2 +- .../app/components/about/about.component.ts | 4 +- .../accelerate-checkout.component.ts | 8 +- .../accelerate-fee-graph.component.ts | 6 +- .../acceleration-timeline.component.ts | 2 +- .../acceleration-fees-graph.component.ts | 6 +- .../acceleration-stats.component.ts | 2 +- .../address-graph/address-graph.component.ts | 4 +- .../address-group/address-group.component.ts | 2 +- .../address-transactions-widget.component.ts | 2 +- .../addresses-treemap.component.ts | 2 +- .../src/app/components/app/app.component.ts | 2 +- .../assets/assets-nav/assets-nav.component.ts | 4 +- .../balance-widget.component.ts | 2 +- .../block-fee-rates-graph.component.ts | 2 +- .../block-fees-subsidy-graph.component.ts | 18 +- .../block-filters/block-filters.component.ts | 2 +- .../components/block-overview-graph/utils.ts | 4 +- .../block-overview-tooltip.component.ts | 2 +- .../blockchain-blocks.component.ts | 10 +- .../blockchain/blockchain.component.ts | 6 +- .../blocks-list/blocks-list.component.ts | 4 +- .../calculator/calculator.component.ts | 4 +- .../app/components/clock/clock.component.ts | 2 +- .../custom-dashboard.component.ts | 4 +- .../difficulty-tooltip.component.ts | 4 +- .../difficulty/difficulty.component.ts | 2 +- .../app/components/faucet/faucet.component.ts | 4 +- .../fee-distribution-graph.component.ts | 2 +- .../components/fees-box/fees-box.component.ts | 2 +- .../app/components/footer/footer.component.ts | 6 +- .../hashrate-chart.component.ts | 6 +- .../hashrate-chart-pools.component.ts | 4 +- .../incoming-transactions-graph.component.ts | 4 +- .../federation-addresses-stats.component.ts | 4 +- .../federation-utxos-list.component.ts | 8 +- .../reserves-ratio-stats.component.ts | 8 +- .../reserves-ratio.component.ts | 6 +- .../master-page/master-page.component.ts | 4 +- .../mempool-blocks.component.ts | 2 +- .../mempool-graph/mempool-graph.component.ts | 2 +- .../src/app/components/menu/menu.component.ts | 4 +- .../ngx-bootstrap-multiselect.component.ts | 2 +- .../off-click.directive.ts | 4 +- .../src/app/components/pool/pool.component.ts | 6 +- .../push-transaction.component.ts | 4 +- .../rbf-timeline/rbf-timeline.component.ts | 2 +- .../search-form/search-form.component.ts | 8 +- .../app/components/start/start.component.ts | 4 +- .../statistics/statistics.component.ts | 2 +- .../timezone-selector.component.ts | 2 +- .../tracker/tracker-bar.component.ts | 6 +- .../components/tracker/tracker.component.ts | 4 +- .../transaction/liquid-ublinding.ts | 2 +- .../transaction/transaction.component.ts | 14 +- .../transactions-list.component.ts | 8 +- .../treasuries-graph.component.ts | 10 +- .../twitter-widget.component.ts | 2 +- .../tx-bowtie-graph-tooltip.component.ts | 4 +- .../tx-bowtie-graph.component.ts | 2 +- .../src/app/dashboard/dashboard.component.ts | 20 +- .../src/app/docs/api-docs/api-docs-data.ts | 1886 ++++++++--------- .../app/docs/api-docs/api-docs.component.ts | 56 +- .../code-template/code-template.component.ts | 16 +- frontend/src/app/docs/docs/docs.component.ts | 10 +- .../src/app/interfaces/node-api.interface.ts | 22 +- .../src/app/interfaces/services.interface.ts | 2 +- .../lightning/channel/channel.component.ts | 2 +- .../closing-type/closing-type.component.ts | 2 +- .../channels-list/channels-list.component.ts | 2 +- .../app/lightning/group/group.component.ts | 2 +- .../app/lightning/lightning-api.service.ts | 2 +- .../src/app/lightning/node/liquidity-ad.ts | 2 +- .../lightning/node/node-preview.component.ts | 2 +- .../nodes-channels/node-channels.component.ts | 2 +- .../nodes-per-country.component.ts | 2 +- .../nodes-per-isp/nodes-per-isp.component.ts | 2 +- .../oldest-nodes/oldest-nodes.component.ts | 2 +- .../top-nodes-per-capacity.component.ts | 4 +- .../top-nodes-per-channels.component.ts | 10 +- .../app/liquid/liquid-master-page.module.ts | 2 +- frontend/src/app/master-page.module.ts | 2 +- frontend/src/app/services/api.service.ts | 6 +- frontend/src/app/services/assets.service.ts | 6 +- frontend/src/app/services/cache.service.ts | 4 +- frontend/src/app/services/eta.service.ts | 2 +- .../app/services/http-cache.interceptor.ts | 2 +- .../src/app/services/opengraph.service.ts | 12 +- frontend/src/app/services/ord-api.service.ts | 2 +- frontend/src/app/services/price.service.ts | 6 +- frontend/src/app/services/seo.service.ts | 12 +- .../src/app/services/services-api.service.ts | 4 +- frontend/src/app/services/state.service.ts | 4 +- frontend/src/app/shared/common.utils.ts | 20 +- .../shared/components/asm/asm.component.ts | 2 +- .../shared/components/btc/btc.component.ts | 4 +- .../geolocation/geolocation.component.ts | 2 +- .../global-footer/global-footer.component.ts | 2 +- .../mempool-error/mempool-error.component.ts | 2 +- .../components/toggle/toggle.component.ts | 2 +- frontend/src/app/shared/i18n/dates.ts | 4 +- .../src/app/shared/ord/inscription.utils.ts | 10 +- .../app/shared/pipes/bytes-pipe/bytes.pipe.ts | 2 +- .../pipes/fee-rounding/fee-rounding.pipe.ts | 6 +- .../app/shared/pipes/fiat-shortener.pipe.ts | 2 +- .../shared/pipes/math-ceil/math-ceil.pipe.ts | 2 +- .../pipes/relative-url/relative-url.pipe.ts | 2 +- frontend/src/app/shared/regex.utils.ts | 8 +- frontend/src/app/shared/script.utils.ts | 8 +- frontend/src/app/shared/sha256.ts | 6 +- frontend/src/app/shared/transaction.utils.ts | 46 +- 121 files changed, 1347 insertions(+), 1347 deletions(-) diff --git a/frontend/cypress.config.ts b/frontend/cypress.config.ts index 4bdbd257d..2e0507379 100644 --- a/frontend/cypress.config.ts +++ b/frontend/cypress.config.ts @@ -16,7 +16,7 @@ export default defineConfig({ const fs = require('fs'); const CONFIG_FILE = 'mempool-frontend-config.json'; if (fs.existsSync(CONFIG_FILE)) { - let contents = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); + const contents = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); config.env.BASE_MODULE = contents.BASE_MODULE ? contents.BASE_MODULE : 'mempool'; } else { config.env.BASE_MODULE = 'mempool'; diff --git a/frontend/cypress/e2e/liquid/liquid.spec.ts b/frontend/cypress/e2e/liquid/liquid.spec.ts index 2da3c41f5..20f983844 100644 --- a/frontend/cypress/e2e/liquid/liquid.spec.ts +++ b/frontend/cypress/e2e/liquid/liquid.spec.ts @@ -58,7 +58,7 @@ describe('Liquid', () => { }); it('loads the graphs page - mobile', () => { - cy.visit(`${basePath}`) + cy.visit(`${basePath}`); cy.waitForSkeletonGone(); cy.get('#btn-graphs').click().then(() => { cy.viewport('iphone-6'); diff --git a/frontend/cypress/e2e/liquidtestnet/liquidtestnet.spec.ts b/frontend/cypress/e2e/liquidtestnet/liquidtestnet.spec.ts index b5038f89b..aef6dc51d 100644 --- a/frontend/cypress/e2e/liquidtestnet/liquidtestnet.spec.ts +++ b/frontend/cypress/e2e/liquidtestnet/liquidtestnet.spec.ts @@ -40,7 +40,7 @@ describe('Liquid Testnet', () => { }); it('loads the blocks page', () => { - cy.visit(`${basePath}`) + cy.visit(`${basePath}`); cy.get('#btn-blocks'); cy.waitForSkeletonGone(); }); @@ -58,7 +58,7 @@ describe('Liquid Testnet', () => { }); it('loads the graphs page - mobile', () => { - cy.visit(`${basePath}`) + cy.visit(`${basePath}`); cy.waitForSkeletonGone(); cy.viewport('iphone-6'); cy.get('.tv-only').should('not.exist'); diff --git a/frontend/cypress/e2e/mainnet/mainnet.spec.ts b/frontend/cypress/e2e/mainnet/mainnet.spec.ts index a664f333c..a04803ca0 100644 --- a/frontend/cypress/e2e/mainnet/mainnet.spec.ts +++ b/frontend/cypress/e2e/mainnet/mainnet.spec.ts @@ -14,17 +14,17 @@ const baseModule = Cypress.env('BASE_MODULE'); const areOverlapping = (rect1, rect2) => { // if one rectangle is on the left side of the other if (rect1.right < rect2.left || rect2.right < rect1.left) { - return false + return false; } // if one rectangle is above the other if (rect1.bottom < rect2.top || rect2.bottom < rect1.top) { - return false + return false; } // the rectangles must overlap - return true -} + return true; +}; /** * Returns the bounding rectangle of the first DOM @@ -134,7 +134,7 @@ describe('Mainnet', () => { cy.get('.search-box-container > .form-control').type('A').then(() => { cy.wait('@search-1wizSA'); - cy.get('app-search-results button.dropdown-item').should('have.length', 1) + cy.get('app-search-results button.dropdown-item').should('have.length', 1); }); cy.get('app-search-results button.dropdown-item.active').click().then(() => { diff --git a/frontend/cypress/support/PageIdleDetector.ts b/frontend/cypress/support/PageIdleDetector.ts index ba0cd222f..44a83a73a 100644 --- a/frontend/cypress/support/PageIdleDetector.ts +++ b/frontend/cypress/support/PageIdleDetector.ts @@ -1,6 +1,6 @@ // source: chrisp_68 @ https://stackoverflow.com/questions/50525143/how-do-you-reliably-wait-for-page-idle-in-cypress-io-test export class PageIdleDetector -{ +{ defaultOptions: object = { timeout: 60000 }; public WaitForPageToBeIdle(): void @@ -15,7 +15,7 @@ export class PageIdleDetector { cy.document(options).should((myDocument: any) => { - expect(myDocument.readyState, "WaitForPageToLoad").to.be.oneOf(["interactive", "complete"]); + expect(myDocument.readyState, 'WaitForPageToLoad').to.be.oneOf(['interactive', 'complete']); }); } @@ -23,9 +23,9 @@ export class PageIdleDetector { cy.window(options).should((myWindow: any) => { - if (!!myWindow.angular) + if (myWindow.angular) { - expect(this.NumberOfPendingAngularRequests(myWindow), "WaitForAngularRequestsToComplete").to.have.length(0); + expect(this.NumberOfPendingAngularRequests(myWindow), 'WaitForAngularRequestsToComplete').to.have.length(0); } }); } @@ -34,16 +34,16 @@ export class PageIdleDetector { cy.window(options).should((myWindow: any) => { - if (!!myWindow.angular) + if (myWindow.angular) { - expect(this.AngularRootScopePhase(myWindow), "WaitForAngularDigestCycleToComplete").to.be.null; + expect(this.AngularRootScopePhase(myWindow), 'WaitForAngularDigestCycleToComplete').to.be.null; } }); } public WaitForAnimationsToStop(options: object = this.defaultOptions): void { - cy.get(":animated", options).should("not.exist"); + cy.get(':animated', options).should('not.exist'); } private getInjector(myWindow: any) @@ -58,6 +58,6 @@ export class PageIdleDetector private AngularRootScopePhase(myWindow: any) { - return this.getInjector(myWindow).get("$rootScope").$$phase; + return this.getInjector(myWindow).get('$rootScope').$$phase; } } diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index 2ce198241..99bc5c4d2 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -52,18 +52,18 @@ const codes = { ArrowUp: 38, ArrowRight: 39, ArrowDown: 40 -} +}; Cypress.Commands.add('waitForSkeletonGone', () => { cy.waitUntil(() => { return Cypress.$('.skeleton-loader').length === 0; - }, { verbose: true, description: "waitForSkeletonGone", errorMsg: "skeleton loaders never went away", timeout: 15000, interval: 50 }); + }, { verbose: true, description: 'waitForSkeletonGone', errorMsg: 'skeleton loaders never went away', timeout: 15000, interval: 50 }); }); Cypress.Commands.add( - "waitForPageIdle", + 'waitForPageIdle', () => { - console.warn("Waiting for page idle state"); + console.warn('Waiting for page idle state'); const pageIdleDetector = new PageIdleDetector(); pageIdleDetector.WaitForPageToBeIdle(); } @@ -77,7 +77,7 @@ Cypress.Commands.add('mockMempoolSocketV2', () => { mockWebSocketV2(); }); -Cypress.Commands.add('changeNetwork', (network: "testnet" | "testnet4" | "signet" | "liquid" | "mainnet") => { +Cypress.Commands.add('changeNetwork', (network: 'testnet' | 'testnet4' | 'signet' | 'liquid' | 'mainnet') => { cy.get('.dropdown-toggle').click().then(() => { cy.get(`a.${network}`).click().then(() => { cy.waitForPageIdle(); @@ -88,60 +88,60 @@ Cypress.Commands.add('changeNetwork', (network: "testnet" | "testnet4" | "signet // https://github.com/bahmutov/cypress-arrows/blob/8f0303842a343550fbeaf01528d01d1ff213b70c/src/index.js function keydownCommand($el, key) { - const message = `sending the "${key}" keydown event` + const message = `sending the "${key}" keydown event`; const log = Cypress.log({ name: `keydown: ${key}`, message: message, consoleProps: function () { return { Subject: $el - } + }; } - }) + }); - const e = $el.createEvent('KeyboardEvent') + const e = $el.createEvent('KeyboardEvent'); Object.defineProperty(e, 'key', { get: function () { - return key + return key; } - }) + }); Object.defineProperty(e, 'keyCode', { get: function () { - return this.keyCodeVal + return this.keyCodeVal; } - }) + }); Object.defineProperty(e, 'which', { get: function () { - return this.keyCodeVal + return this.keyCodeVal; } - }) - var metaKey = false + }); + const metaKey = false; Object.defineProperty(e, 'metaKey', { get: function () { - return metaKey + return metaKey; } - }) + }); Object.defineProperty(e, 'shiftKey', { get: function () { - return false + return false; } - }) - e.keyCodeVal = codes[key] + }); + e.keyCodeVal = codes[key]; e.initKeyboardEvent('keydown', true, true, - $el.defaultView, false, false, false, false, e.keyCodeVal, e.keyCodeVal) + $el.defaultView, false, false, false, false, e.keyCodeVal, e.keyCodeVal); - $el.dispatchEvent(e) - log.snapshot().end() - return $el + $el.dispatchEvent(e); + log.snapshot().end(); + return $el; } -Cypress.Commands.add('keydown', { prevSubject: "dom" }, keydownCommand) -Cypress.Commands.add('left', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowLeft')) -Cypress.Commands.add('right', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowRight')) -Cypress.Commands.add('up', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowUp')) -Cypress.Commands.add('down', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowDown')) +Cypress.Commands.add('keydown', { prevSubject: 'dom' }, keydownCommand); +Cypress.Commands.add('left', { prevSubject: 'dom' }, $el => keydownCommand($el, 'ArrowLeft')); +Cypress.Commands.add('right', { prevSubject: 'dom' }, $el => keydownCommand($el, 'ArrowRight')); +Cypress.Commands.add('up', { prevSubject: 'dom' }, $el => keydownCommand($el, 'ArrowUp')); +Cypress.Commands.add('down', { prevSubject: 'dom' }, $el => keydownCommand($el, 'ArrowDown')); diff --git a/frontend/cypress/support/index.d.ts b/frontend/cypress/support/index.d.ts index 21ffe6a2d..122ce5ed5 100644 --- a/frontend/cypress/support/index.d.ts +++ b/frontend/cypress/support/index.d.ts @@ -6,6 +6,6 @@ declare namespace Cypress { waitForPageIdle(): Chainable mockMempoolSocket(): Chainable mockMempoolSocketV2(): Chainable - changeNetwork(network: "testnet"|"testnet4"|"signet"|"liquid"|"mainnet"): Chainable + changeNetwork(network: 'testnet'|'testnet4'|'signet'|'liquid'|'mainnet'): Chainable } } \ No newline at end of file diff --git a/frontend/cypress/support/websocket.ts b/frontend/cypress/support/websocket.ts index b067cc6e8..7bdaff725 100644 --- a/frontend/cypress/support/websocket.ts +++ b/frontend/cypress/support/websocket.ts @@ -124,15 +124,15 @@ export const emitMempoolInfo = ({ //TODO: Refactor to take into account different parameterized mocking scenarios switch (params.network) { //TODO: Use network specific mocks - case "signet": - case "testnet": - case "mainnet": + case 'signet': + case 'testnet': + case 'mainnet': default: break; } switch (params.command) { - case "init": { + case 'init': { win.mockSocket.send('{"conversions":{"USD":32365.338815782445}}'); cy.readFile('cypress/fixtures/mainnet_live2hchart.json', 'utf-8').then((fixture) => { win.mockSocket.send(JSON.stringify(fixture)); @@ -142,7 +142,7 @@ export const emitMempoolInfo = ({ }); break; } - case "rbfTransaction": { + case 'rbfTransaction': { cy.readFile('cypress/fixtures/mainnet_rbf.json', 'utf-8').then((fixture) => { win.mockSocket.send(JSON.stringify(fixture)); }); @@ -164,7 +164,7 @@ export const emitMempoolInfo = ({ export const dropWebSocket = (() => { cy.window().then((win) => { - win.mockServer.simulate("error"); + win.mockServer.simulate('error'); }); return cy.wait(500); }); diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 5f69b55cf..8caba9582 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -1,6 +1,6 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -import { AppPreloadingStrategy } from '@app/app.preloading-strategy' +import { AppPreloadingStrategy } from '@app/app.preloading-strategy'; import { BlockViewComponent } from '@components/block-view/block-view.component'; import { EightBlocksComponent } from '@components/eight-blocks/eight-blocks.component'; import { MempoolBlockViewComponent } from '@components/mempool-block-view/mempool-block-view.component'; diff --git a/frontend/src/app/app.constants.ts b/frontend/src/app/app.constants.ts index 2b6661fcc..730da5a81 100644 --- a/frontend/src/app/app.constants.ts +++ b/frontend/src/app/app.constants.ts @@ -83,45 +83,45 @@ export const contrastMempoolFeeColors = [ ]; export const chartColors = [ - "#A81524", - "#D81B60", - "#8E24AA", - "#5E35B1", - "#3949AB", - "#1E88E5", - "#039BE5", - "#00ACC1", - "#00897B", - "#43A047", - "#7CB342", - "#C0CA33", - "#FDD835", - "#FFB300", - "#FB8C00", - "#F4511E", - "#6D4C41", - "#757575", - "#546E7A", - "#b71c1c", - "#880E4F", - "#4A148C", - "#311B92", - "#1A237E", - "#0D47A1", - "#01579B", - "#006064", - "#004D40", - "#1B5E20", - "#33691E", - "#827717", - "#F57F17", - "#FF6F00", - "#E65100", - "#BF360C", - "#3E2723", - "#212121", - "#263238", - "#801313", + '#A81524', + '#D81B60', + '#8E24AA', + '#5E35B1', + '#3949AB', + '#1E88E5', + '#039BE5', + '#00ACC1', + '#00897B', + '#43A047', + '#7CB342', + '#C0CA33', + '#FDD835', + '#FFB300', + '#FB8C00', + '#F4511E', + '#6D4C41', + '#757575', + '#546E7A', + '#b71c1c', + '#880E4F', + '#4A148C', + '#311B92', + '#1A237E', + '#0D47A1', + '#01579B', + '#006064', + '#004D40', + '#1B5E20', + '#33691E', + '#827717', + '#F57F17', + '#FF6F00', + '#E65100', + '#BF360C', + '#3E2723', + '#212121', + '#263238', + '#801313', ]; export const originalChartColors = chartColors.slice(1); diff --git a/frontend/src/app/app.preloading-strategy.ts b/frontend/src/app/app.preloading-strategy.ts index f62d072da..dc8c56232 100644 --- a/frontend/src/app/app.preloading-strategy.ts +++ b/frontend/src/app/app.preloading-strategy.ts @@ -3,7 +3,7 @@ import { Observable, timer, mergeMap, of } from 'rxjs'; export class AppPreloadingStrategy implements PreloadingStrategy { preload(route: Route, load: Function): Observable { - return route.data && route.data.preload + return route.data && route.data.preload ? timer(1500).pipe(mergeMap(() => load())) : of(null); } diff --git a/frontend/src/app/components/about/about.component.ts b/frontend/src/app/components/about/about.component.ts index 01d496c04..8b5a21bd2 100644 --- a/frontend/src/app/components/about/about.component.ts +++ b/frontend/src/app/components/about/about.component.ts @@ -58,11 +58,11 @@ export class AboutComponent implements OnInit { if (scrollToSponsors && !profiles?.whales?.length && !profiles?.chads?.length) { return; } else { - this.goToAnchor(scrollToSponsors) + this.goToAnchor(scrollToSponsors); } }), share(), - ) + ); this.translators$ = this.apiService.getTranslators$() .pipe( diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts index 0240fe00c..1b9bdb14d 100644 --- a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts +++ b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts @@ -591,7 +591,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy { if (this.processing) { return; } - + this.processing = true; if (this.googlePay) { @@ -709,7 +709,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy { if (this.processing) { return; } - + this.processing = true; const costUSD = this.cost / 100_000_000 * this.conversions.USD; @@ -722,11 +722,11 @@ export class AccelerateCheckout implements OnInit, OnDestroy { return; } this.loadingCardOnFile = false; - + try { this.isCheckoutLocked += 2; this.isTokenizing += 2; - + const nameParts = cardOnFile.card.name.split(' '); const assumedGivenName = nameParts[0]; const assumedFamilyName = nameParts.length > 1 ? nameParts[1] : undefined; diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.ts b/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.ts index ebad9c1e4..e0d0d1a2b 100644 --- a/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.ts +++ b/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.ts @@ -93,8 +93,8 @@ export class AccelerateFeeGraphComponent implements OnInit, AfterViewInit, OnCha active: option.index === this.maxRateIndex, rateIndex: option.index, fee: option.fee, - }) - }) + }); + }); bars.reverse(); @@ -121,7 +121,7 @@ export class AccelerateFeeGraphComponent implements OnInit, AfterViewInit, OnCha return { height: `${height}px`, bottom: base ? `${base}px` : '0', - } + }; } onClick(event, bar): void { diff --git a/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts index 31f8706bc..139b37206 100644 --- a/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts +++ b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts @@ -52,7 +52,7 @@ export class AccelerationTimelineComponent implements OnInit, OnChanges { this.firstSeenToAccelerated = Math.max(0, this.acceleratedAt - this.transactionTime); this.acceleratedToMined = Math.max(0, this.tx.status.block_time - this.acceleratedAt); } - + onHover(event, status: string): void { if (status === 'seen') { this.hoverInfo = { diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts index e8a1e3ee2..2ce1d2002 100644 --- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts @@ -187,7 +187,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest } } else if (tick && tick.seriesName === 'Accelerated') { tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.0-0')}
`; - } + } } tooltip += `` + $localize`Around block: ${ticks[0].data[2]}` + ``; @@ -287,7 +287,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest { name: 'Total bid boost', data: data.map(h => { - return [h.timestamp * 1000, h.sumBidBoost, h.avgHeight] + return [h.timestamp * 1000, h.sumBidBoost, h.avgHeight]; }), type: 'line', symbol: 'none', @@ -300,7 +300,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest name: 'Accelerated', yAxisIndex: 1, data: data.map(h => { - return [h.timestamp * 1000, h.count, h.avgHeight] + return [h.timestamp * 1000, h.count, h.avgHeight]; }), type: 'bar', barWidth: '90%', diff --git a/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts index f964fcc6b..c1a48ea20 100644 --- a/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts +++ b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts @@ -44,7 +44,7 @@ export class AccelerationStatsComponent implements OnInit, OnChanges { break; case '1y': this.blocksInPeriod = 30.5 * 144 * 365; - break; + break; case 'all': this.blocksInPeriod = Infinity; break; diff --git a/frontend/src/app/components/address-graph/address-graph.component.ts b/frontend/src/app/components/address-graph/address-graph.component.ts index 0af7e2937..c117e8fc0 100644 --- a/frontend/src/app/components/address-graph/address-graph.component.ts +++ b/frontend/src/app/components/address-graph/address-graph.component.ts @@ -131,7 +131,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy { } }), map(() => [redraw, extendedSummary, conversions]) - ) + ); } else { return of([redraw, addressSummary, conversions]); } @@ -324,7 +324,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy { show: this.showYAxis, color: 'rgb(110, 112, 121)', formatter: (val): string => { - let valSpan = maxValue - (this.period === 'all' ? 0 : minValue); + const valSpan = maxValue - (this.period === 'all' ? 0 : minValue); if (valSpan > 100_000_000_000) { return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 0, undefined, true)} BTC`; } diff --git a/frontend/src/app/components/address-group/address-group.component.ts b/frontend/src/app/components/address-group/address-group.component.ts index c810ed339..13f42a056 100644 --- a/frontend/src/app/components/address-group/address-group.component.ts +++ b/frontend/src/app/components/address-group/address-group.component.ts @@ -63,7 +63,7 @@ export class AddressGroupComponent implements OnInit, OnDestroy { this.addresses = {}; this.addressInfo = {}; this.balance = 0; - + this.addressStrings = params.get('addresses').split(',').map(address => { if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(address)) { return address.toLowerCase(); diff --git a/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.ts b/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.ts index 01bcad565..5705a7a81 100644 --- a/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.ts +++ b/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.ts @@ -16,7 +16,7 @@ export class AddressTransactionsWidgetComponent implements OnInit, OnChanges, On @Input() addressInfo: Address; @Input() addressSummary$: Observable | null; @Input() isPubkey: boolean = false; - + currencySubscription: Subscription; currency: string; diff --git a/frontend/src/app/components/addresses-treemap/addresses-treemap.component.ts b/frontend/src/app/components/addresses-treemap/addresses-treemap.component.ts index ccc58e9c2..0ae1c9bcb 100644 --- a/frontend/src/app/components/addresses-treemap/addresses-treemap.component.ts +++ b/frontend/src/app/components/addresses-treemap/addresses-treemap.component.ts @@ -122,7 +122,7 @@ export class AddressesTreemap implements OnChanges { } } ] - }; + }; } formatValue(sats: number): string { diff --git a/frontend/src/app/components/app/app.component.ts b/frontend/src/app/components/app/app.component.ts index d0384b322..d6fd9a2b0 100644 --- a/frontend/src/app/components/app/app.component.ts +++ b/frontend/src/app/components/app/app.component.ts @@ -46,7 +46,7 @@ export class AppComponent implements OnInit { return; } // prevent arrow key horizontal scrolling - if(["ArrowLeft","ArrowRight"].indexOf(event.code) > -1) { + if(['ArrowLeft','ArrowRight'].indexOf(event.code) > -1) { event.preventDefault(); } this.stateService.keyNavigation$.next(event); diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts index 90bcea9ad..bc5c40f3f 100644 --- a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts @@ -73,10 +73,10 @@ export class AssetsNavComponent implements OnInit { return assets.array.slice(0, this.itemsPerPage); } }) - ) + ); }), ); - } + }; itemSelected() { setTimeout(() => this.search()); diff --git a/frontend/src/app/components/balance-widget/balance-widget.component.ts b/frontend/src/app/components/balance-widget/balance-widget.component.ts index 82ebde8ee..c9ac28d59 100644 --- a/frontend/src/app/components/balance-widget/balance-widget.component.ts +++ b/frontend/src/app/components/balance-widget/balance-widget.component.ts @@ -31,7 +31,7 @@ export class BalanceWidgetComponent implements OnInit, OnChanges { ) { } ngOnInit(): void { - + } ngOnChanges(changes: SimpleChanges): void { diff --git a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts index 85dfb9b8a..8394ce608 100644 --- a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts +++ b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts @@ -165,7 +165,7 @@ export class BlockFeeRatesGraphComponent implements OnInit { } if (this.widget) { - let maResolution = 30; + const maResolution = 30; const medianMa = []; for (let i = maResolution - 1; i < seriesData['Median'].length; ++i) { let avg = 0; diff --git a/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.ts b/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.ts index 2c03f999e..ec3c98262 100644 --- a/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.ts +++ b/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.ts @@ -112,7 +112,7 @@ export class BlockFeesSubsidyGraphComponent implements OnInit { blockSubsidyFiat: response.body.filter(val => val['USD'] > 0).map(val => this.subsidyAt(val.avgHeight) / 100_000_000 * val['USD']), blockSubsidyPercent: response.body.map(val => this.subsidyAt(val.avgHeight) / (val.avgFees + this.subsidyAt(val.avgHeight)) * 100), }; - + this.prepareChartOptions(); this.isLoading = false; }), @@ -176,12 +176,12 @@ export class BlockFeesSubsidyGraphComponent implements OnInit { for (let i = data.length - 1; i >= 0; i--) { const tick = data[i]; tooltip += `${tick.marker} ${tick.seriesName.split(' ')[0]}: `; - if (this.displayMode === 'normal') tooltip += `${formatNumber(tick.data, this.locale, '1.0-3')} BTC
`; - else if (this.displayMode === 'fiat') tooltip += `${this.fiatCurrencyPipe.transform(tick.data, null, 'USD') }
`; - else tooltip += `${formatNumber(tick.data, this.locale, '1.0-2')}%
`; + if (this.displayMode === 'normal') {tooltip += `${formatNumber(tick.data, this.locale, '1.0-3')} BTC
`;} + else if (this.displayMode === 'fiat') {tooltip += `${this.fiatCurrencyPipe.transform(tick.data, null, 'USD') }
`;} + else {tooltip += `${formatNumber(tick.data, this.locale, '1.0-2')}%
`;} } - if (this.displayMode === 'normal') tooltip += `
${formatNumber(data.reduce((acc, val) => acc + val.data, 0), this.locale, '1.0-3')} BTC
`; - else if (this.displayMode === 'fiat') tooltip += `
${this.fiatCurrencyPipe.transform(data.reduce((acc, val) => acc + val.data, 0), null, 'USD')}
`; + if (this.displayMode === 'normal') {tooltip += `
${formatNumber(data.reduce((acc, val) => acc + val.data, 0), this.locale, '1.0-3')} BTC
`;} + else if (this.displayMode === 'fiat') {tooltip += `
${this.fiatCurrencyPipe.transform(data.reduce((acc, val) => acc + val.data, 0), null, 'USD')}
`;} if (['24h', '3d'].includes(this.zoomTimeSpan)) { tooltip += `` + $localize`At block ${'' + data[0].axisValue}` + ``; } else { @@ -410,7 +410,7 @@ export class BlockFeesSubsidyGraphComponent implements OnInit { mode = 'normal'; } - if (this.displayMode === mode) return; + if (this.displayMode === mode) {return;} const isActivation = params.selected[params.name]; @@ -486,7 +486,7 @@ export class BlockFeesSubsidyGraphComponent implements OnInit { tap((response) => { const startIndex = option.dataZoom[0].startValue; const endIndex = option.dataZoom[0].endValue; - + // Update series with more granular data const lengthBefore = this.data.timestamp.length; this.data.timestamp.splice(startIndex, endIndex - startIndex, ...response.body.map(val => val.timestamp * 1000)); @@ -537,7 +537,7 @@ export class BlockFeesSubsidyGraphComponent implements OnInit { } getTimeRangeFromTimespan(from: number, to: number): string { - const timespan = to - from; + const timespan = to - from; switch (true) { case timespan >= 3600 * 24 * 365 * 4: return 'all'; case timespan >= 3600 * 24 * 365 * 3: return '4y'; diff --git a/frontend/src/app/components/block-filters/block-filters.component.ts b/frontend/src/app/components/block-filters/block-filters.component.ts index 143ce4fd0..d71e01ab9 100644 --- a/frontend/src/app/components/block-filters/block-filters.component.ts +++ b/frontend/src/app/components/block-filters/block-filters.component.ts @@ -93,7 +93,7 @@ export class BlockFiltersComponent implements OnInit, OnChanges, OnDestroy { this.onFilterChanged.emit({ mode: this.filterMode, filters: this.activeFilters, gradient: this.gradientMode }); this.stateService.activeGoggles$.next({ mode: this.filterMode, filters: [...this.activeFilters], gradient: this.gradientMode }); } - + getBooleanFlags(): bigint | null { let flags = 0n; for (const key of Object.keys(this.filterFlags)) { diff --git a/frontend/src/app/components/block-overview-graph/utils.ts b/frontend/src/app/components/block-overview-graph/utils.ts index 47677c4f1..05fb9931f 100644 --- a/frontend/src/app/components/block-overview-graph/utils.ts +++ b/frontend/src/app/components/block-overview-graph/utils.ts @@ -67,7 +67,7 @@ const defaultColors: { [key: string]: ColorPalette } = { marginal: [], baseLevel: (tx: TxView, rate: number) => feeLevels.findIndex((feeLvl) => Math.max(0, rate) < feeLvl) - 1 }, -} +}; for (const key in defaultColors) { const base = defaultColors[key].base; defaultColors[key].audit = base.map((color) => darken(desaturate(color, 0.3), 0.9)); @@ -98,7 +98,7 @@ const contrastColors: { [key: string]: ColorPalette } = { marginal: [], baseLevel: (tx: TxView, rate: number) => feeLevels.findIndex((feeLvl) => Math.max(0, rate) < feeLvl) - 1 }, -} +}; for (const key in contrastColors) { const base = contrastColors[key].base; contrastColors[key].audit = base.map((color) => darken(desaturate(color, 0.3), 0.9)); diff --git a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts index e76d6be97..08f7bc7d8 100644 --- a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts +++ b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts @@ -72,7 +72,7 @@ export class BlockOverviewTooltipComponent implements OnChanges { this.hasEffectiveRate = this.tx.acc || !(Math.abs((this.fee / this.vsize) - this.effectiveRate) <= 0.1 && Math.abs((this.fee / Math.ceil(this.vsize)) - this.effectiveRate) <= 0.1) || (txFlags && (txFlags & (TransactionFlags.cpfp_child | TransactionFlags.cpfp_parent)) > 0n); this.filters = this.tx.flags ? toFilters(txFlags).filter(f => f.tooltip) : []; - this.activeFilters = {} + this.activeFilters = {}; for (const filter of this.filters) { if (this.filterFlags && (this.filterFlags & BigInt(filter.flag))) { this.activeFilters[filter.key] = true; diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index be63af042..e6b75d408 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -30,7 +30,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { @Input() spotlight: number = 0; @Input() showPools: boolean = true; @Input() getHref?: (index, block) => string = (index, block) => `/block/${block.id}`; - + specialBlocks = specialBlocks; network = ''; blocks: BlockchainBlock[] = []; @@ -174,7 +174,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { } else { this.moveArrowToPosition(true, false); } - }) + }); } else { this.blockPageSubscription = this.cacheService.loadedBlocks$.subscribe((block) => { if (block.height <= this.height && block.height > this.height - this.count) { @@ -363,7 +363,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { convertStyleForLoadingBlock(style) { return { ...style, - background: "var(--secondary)", + background: 'var(--secondary)', }; } @@ -372,7 +372,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { return { left: addLeft + (this.blockOffset * index) + 'px', - background: "var(--secondary)", + background: 'var(--secondary)', }; } @@ -388,7 +388,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { return { left: addLeft + this.blockOffset * this.emptyBlocks.indexOf(block) + 'px', - background: "var(--secondary)", + background: 'var(--secondary)', }; } diff --git a/frontend/src/app/components/blockchain/blockchain.component.ts b/frontend/src/app/components/blockchain/blockchain.component.ts index 757bfee7f..8ac128844 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.ts +++ b/frontend/src/app/components/blockchain/blockchain.component.ts @@ -33,7 +33,7 @@ export class BlockchainComponent implements OnInit, OnDestroy, OnChanges { dividerOffset: number | null = null; mempoolOffset: number | null = null; positionStyle = { - transform: "translateX(1280px)", + transform: 'translateX(1280px)', }; blockDisplayToggleStyle = {}; @@ -91,8 +91,8 @@ export class BlockchainComponent implements OnInit, OnDestroy, OnChanges { } toggleBlockDisplayMode(): void { - if (this.blockDisplayMode === 'size') this.blockDisplayMode = 'fees'; - else this.blockDisplayMode = 'size'; + if (this.blockDisplayMode === 'size') {this.blockDisplayMode = 'fees';} + else {this.blockDisplayMode = 'size';} this.StorageService.setValue('block-display-mode-preference', this.blockDisplayMode); this.stateService.blockDisplayMode$.next(this.blockDisplayMode); } diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.ts b/frontend/src/app/components/blocks-list/blocks-list.component.ts index 43469d179..be9660081 100644 --- a/frontend/src/app/components/blocks-list/blocks-list.component.ts +++ b/frontend/src/app/components/blocks-list/blocks-list.component.ts @@ -67,7 +67,7 @@ export class BlocksList implements OnInit { if (!this.widget) { this.websocketService.want(['blocks']); - + this.seoService.setTitle($localize`:@@8a7b4bd44c0ac71b2e72de0398b303257f7d2f54:Blocks`); this.ogService.setManualOgImage('recent-blocks.jpg'); if( this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet' ) { @@ -110,7 +110,7 @@ export class BlocksList implements OnInit { this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()]; this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5; - + this.blocks$ = combineLatest([ this.fromHeightSubject.pipe( filter(fromBlockHeight => fromBlockHeight !== this.lastBlockHeightFetched), diff --git a/frontend/src/app/components/calculator/calculator.component.ts b/frontend/src/app/components/calculator/calculator.component.ts index 1beadeed5..94732f86e 100644 --- a/frontend/src/app/components/calculator/calculator.component.ts +++ b/frontend/src/app/components/calculator/calculator.component.ts @@ -41,7 +41,7 @@ export class CalculatorComponent implements OnInit { let currency; this.price$ = this.currency$.pipe( switchMap((result) => { - currency = result; + currency = result; return this.stateService.conversions$.asObservable(); }), map((conversions) => { @@ -124,7 +124,7 @@ export class CalculatorComponent implements OnInit { countDecimals(numberString: string): number { const decimalPos = numberString.indexOf('.'); - if (decimalPos === -1) return 0; + if (decimalPos === -1) {return 0;} return numberString.length - decimalPos - 1; } diff --git a/frontend/src/app/components/clock/clock.component.ts b/frontend/src/app/components/clock/clock.component.ts index 8b7db9f5f..592e5bd64 100644 --- a/frontend/src/app/components/clock/clock.component.ts +++ b/frontend/src/app/components/clock/clock.component.ts @@ -108,7 +108,7 @@ export class ClockComponent implements OnInit { )`, }; } - + @HostListener('window:resize', ['$event']) resizeCanvas(): void { const windowWidth = this.limitWidth || window.innerWidth || 800; diff --git a/frontend/src/app/components/custom-dashboard/custom-dashboard.component.ts b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.ts index ba955c21c..587763a59 100644 --- a/frontend/src/app/components/custom-dashboard/custom-dashboard.component.ts +++ b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.ts @@ -286,7 +286,7 @@ export class CustomDashboardComponent implements OnInit, OnDestroy, AfterViewIni getArrayFromNumber(num: number): number[] { return Array.from({ length: num }, (_, i) => i + 1); } - + setFilter(index): void { const selected = this.goggleCycle[index]; this.stateService.activeGoggles$.next(selected); @@ -296,7 +296,7 @@ export class CustomDashboardComponent implements OnInit, OnDestroy, AfterViewIni if (this.stateService.env.customize && this.stateService.env.customize.dashboard.widgets.some(w => w.props?.address)) { let addressString = this.stateService.env.customize.dashboard.widgets.find(w => w.props?.address).props.address; addressString = (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(addressString)) ? addressString.toLowerCase() : addressString; - + this.addressSubscription = ( addressString.match(/04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}/) ? this.electrsApiService.getPubKeyAddress$(addressString) diff --git a/frontend/src/app/components/difficulty/difficulty-tooltip.component.ts b/frontend/src/app/components/difficulty/difficulty-tooltip.component.ts index 9ad44a629..f889c68e1 100644 --- a/frontend/src/app/components/difficulty/difficulty-tooltip.component.ts +++ b/frontend/src/app/components/difficulty/difficulty-tooltip.component.ts @@ -26,7 +26,7 @@ const EPOCH_BLOCK_LENGTH = 2016; // Bitcoin mainnet }) export class DifficultyTooltipComponent implements OnChanges { @Input() status: string | void; - @Input() progress: EpochProgress | void = null; + @Input() progress: EpochProgress | void = null; @Input() cursorPosition: { x: number, y: number }; mined: number; @@ -49,7 +49,7 @@ export class DifficultyTooltipComponent implements OnChanges { ngOnChanges(changes): void { if (changes.cursorPosition && changes.cursorPosition.currentValue) { let x = changes.cursorPosition.currentValue.x; - let y = changes.cursorPosition.currentValue.y - 50; + const y = changes.cursorPosition.currentValue.y - 50; if (this.tooltipElement) { const elementBounds = this.tooltipElement.nativeElement.getBoundingClientRect(); x -= elementBounds.width / 2; diff --git a/frontend/src/app/components/difficulty/difficulty.component.ts b/frontend/src/app/components/difficulty/difficulty.component.ts index 229b9194b..74347d6f0 100644 --- a/frontend/src/app/components/difficulty/difficulty.component.ts +++ b/frontend/src/app/components/difficulty/difficulty.component.ts @@ -48,7 +48,7 @@ export class DifficultyComponent implements OnInit { @Input() showTitle = true; @ViewChild('epochSvg') epochSvgElement: ElementRef; - + isLoadingWebSocket$: Observable; difficultyEpoch$: Observable; diff --git a/frontend/src/app/components/faucet/faucet.component.ts b/frontend/src/app/components/faucet/faucet.component.ts index 6b4881176..25a239330 100644 --- a/frontend/src/app/components/faucet/faucet.component.ts +++ b/frontend/src/app/components/faucet/faucet.component.ts @@ -174,12 +174,12 @@ export class FaucetComponent implements OnInit, OnDestroy { get amount() { return this.faucetForm.get('satoshis')!; } get invalidAmount() { const amount = this.faucetForm.get('satoshis')!; - return amount?.invalid && (amount.dirty || amount.touched) + return amount?.invalid && (amount.dirty || amount.touched); } get address() { return this.faucetForm.get('address')!; } get invalidAddress() { const address = this.faucetForm.get('address')!; - return address?.invalid && (address.dirty || address.touched) + return address?.invalid && (address.dirty || address.touched); } } diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts index 1bc5aaa1d..34d2c6d66 100644 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts +++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts @@ -145,7 +145,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr const unitValue = this.weightMode ? value / 4 : value; const selectedPowerOfTen = selectPowerOfTen(unitValue); const scaledValue = unitValue / selectedPowerOfTen.divider; - let newVal = ''; + const newVal = ''; switch (true) { case scaledValue >= 100: return Math.round(scaledValue).toString(); diff --git a/frontend/src/app/components/fees-box/fees-box.component.ts b/frontend/src/app/components/fees-box/fees-box.component.ts index a1c8e7698..1a2d5c8cf 100644 --- a/frontend/src/app/components/fees-box/fees-box.component.ts +++ b/frontend/src/app/components/fees-box/fees-box.component.ts @@ -44,7 +44,7 @@ export class FeesBoxComponent implements OnInit, OnDestroy { ); this.themeSubscription = this.themeService.themeChanged$.subscribe(() => { this.setFeeGradient(); - }) + }); } setFeeGradient() { diff --git a/frontend/src/app/components/footer/footer.component.ts b/frontend/src/app/components/footer/footer.component.ts index 1df81bc62..191726da4 100644 --- a/frontend/src/app/components/footer/footer.component.ts +++ b/frontend/src/app/components/footer/footer.component.ts @@ -50,7 +50,7 @@ export class FooterComponent implements OnInit { .pipe( map(([mempoolInfo, vbytesPerSecond]) => { const percent = Math.round((Math.min(vbytesPerSecond, this.vBytesPerSecondLimit) / this.vBytesPerSecondLimit) * 100); - + let progressColor = '#7CB342'; if (vbytesPerSecond > 1667) { progressColor = '#FDD835'; @@ -67,7 +67,7 @@ export class FooterComponent implements OnInit { if (vbytesPerSecond > 3500) { progressColor = '#D81B60'; } - + const mempoolSizePercentage = (mempoolInfo.usage / mempoolInfo.maxmempool * 100); let mempoolSizeProgress = 'bg-danger'; if (mempoolSizePercentage <= 50) { @@ -75,7 +75,7 @@ export class FooterComponent implements OnInit { } else if (mempoolSizePercentage <= 75) { mempoolSizeProgress = 'bg-warning'; } - + return { memPoolInfo: mempoolInfo, vBytesPerSecond: vbytesPerSecond, diff --git a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts index d72800aa2..ca3a42bd2 100644 --- a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts +++ b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts @@ -164,7 +164,7 @@ export class HashrateChartComponent implements OnInit { diffIndex++; } - let maResolution = 15; + const maResolution = 15; const hashrateMa = []; for (let i = maResolution - 1; i < data.hashrates.length; ++i) { let avg = 0; @@ -258,7 +258,7 @@ export class HashrateChartComponent implements OnInit { if (tick.seriesIndex === 0) { // Hashrate hashrateString = `${tick.marker} ${tick.seriesName}: ${this.amountShortenerPipe.transform(tick.data[1], 3, 'H/s', false, true)}
`; } else if (tick.seriesIndex === 1) { // Difficulty - let difficulty = tick.data[1]; + const difficulty = tick.data[1]; if (difficulty === null) { difficultyString = `${tick.marker} ${tick.seriesName}: No data
`; } else { @@ -361,7 +361,7 @@ export class HashrateChartComponent implements OnInit { return value.min; } const selectedPowerOfTen: any = selectPowerOfTen(firstYAxisMin); - const newMin = Math.floor(firstYAxisMin / selectedPowerOfTen.divider / 10) + const newMin = Math.floor(firstYAxisMin / selectedPowerOfTen.divider / 10); return 600 / 2 ** 32 * newMin * selectedPowerOfTen.divider * 10; }, max: (value) => { diff --git a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts index f7bc7607b..53dc0e54d 100644 --- a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts +++ b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.ts @@ -110,7 +110,7 @@ export class HashrateChartPoolsComponent implements OnInit { map((response) => { return { blockCount: parseInt(response.headers.get('x-total-count'), 10), - } + }; }), retryWhen((errors) => errors.pipe( delay(60000) @@ -178,7 +178,7 @@ export class HashrateChartPoolsComponent implements OnInit { }, icon: 'roundRect', itemStyle: { - color: poolsColor[name.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()], + color: poolsColor[name.replace(/[^a-zA-Z0-9]/g, '').toLowerCase()], }, }); } diff --git a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts index 1aff1fb1c..eaf588527 100644 --- a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts +++ b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts @@ -76,7 +76,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On rendered() { if (!this.data) { - return; + return; } } @@ -161,7 +161,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On symbol: 'none', lineStyle: { width: 2, - color: "white", + color: 'white', } }); } diff --git a/frontend/src/app/components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component.ts b/frontend/src/app/components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component.ts index 9e88c3ce3..ab7ec7ad7 100644 --- a/frontend/src/app/components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component.ts +++ b/frontend/src/app/components/liquid-reserves-audit/federation-addresses-stats/federation-addresses-stats.component.ts @@ -24,9 +24,9 @@ export class FederationAddressesStatsComponent implements OnInit { if (address_count === undefined || utxo_count === undefined) { return undefined; } - return { address_count, utxo_count} + return { address_count, utxo_count}; }) - ) + ); } } diff --git a/frontend/src/app/components/liquid-reserves-audit/federation-utxos-list/federation-utxos-list.component.ts b/frontend/src/app/components/liquid-reserves-audit/federation-utxos-list/federation-utxos-list.component.ts index 25440b942..baa26def4 100644 --- a/frontend/src/app/components/liquid-reserves-audit/federation-utxos-list/federation-utxos-list.component.ts +++ b/frontend/src/app/components/liquid-reserves-audit/federation-utxos-list/federation-utxos-list.component.ts @@ -36,7 +36,7 @@ export class FederationUtxosListComponent implements OnInit { isLoad: boolean = true; private destroy$ = new Subject(); - + constructor( private apiService: ApiService, public stateService: StateService, @@ -125,7 +125,7 @@ export class FederationUtxosListComponent implements OnInit { const distanceToGreen = Math.abs(4032 - value); const green = '#3bcc49'; const red = '#dc3545'; - + if (value < 0) { return red; } else if (value >= 4032) { @@ -135,11 +135,11 @@ export class FederationUtxosListComponent implements OnInit { const r = parseInt(red.slice(1, 3), 16); const g = parseInt(green.slice(1, 3), 16); const b = parseInt(red.slice(5, 7), 16); - + const newR = Math.floor(r + (g - r) * scaleFactor); const newG = Math.floor(g - (g - r) * scaleFactor); const newB = b; - + return '#' + this.componentToHex(newR) + this.componentToHex(newG) + this.componentToHex(newB); } } diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio-stats/reserves-ratio-stats.component.ts b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio-stats/reserves-ratio-stats.component.ts index 0c59e7174..a6449def1 100644 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio-stats/reserves-ratio-stats.component.ts +++ b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio-stats/reserves-ratio-stats.component.ts @@ -11,7 +11,7 @@ import { Observable, map } from 'rxjs'; export class ReservesRatioStatsComponent implements OnInit { @Input() fullHistory$: Observable; @Input() emergencyUtxosStats$: Observable; - unbackedMonths$: Observable + unbackedMonths$: Observable; constructor() { } @@ -24,13 +24,13 @@ export class ReservesRatioStatsComponent implements OnInit { map((fullHistory) => { if (fullHistory.liquidPegs.series.length !== fullHistory.liquidReserves.series.length) { return { - historyComplete: false, + historyComplete: false, total: null }; } // Only check the last 3 years let ratioSeries = fullHistory.liquidReserves.series.map((value: number, index: number) => value / fullHistory.liquidPegs.series[index]); - ratioSeries = ratioSeries.slice(Math.max(ratioSeries.length - 36, 0)); + ratioSeries = ratioSeries.slice(Math.max(ratioSeries.length - 36, 0)); let total = 0; let avg = 0; for (let i = 0; i < ratioSeries.length; i++) { @@ -41,7 +41,7 @@ export class ReservesRatioStatsComponent implements OnInit { } avg = avg / ratioSeries.length; return { - historyComplete: true, + historyComplete: true, total: total, avg: avg, }; diff --git a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.ts b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.ts index 554521c16..95dd66caf 100644 --- a/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.ts +++ b/frontend/src/app/components/liquid-reserves-audit/reserves-ratio/reserves-ratio.component.ts @@ -103,9 +103,9 @@ export class ReservesRatioComponent implements OnInit, OnChanges { } }, axisLabel: { - color: 'inherit', - fontFamily: 'inherit', - fontSize: axisFontSize, + color: 'inherit', + fontFamily: 'inherit', + fontSize: axisFontSize, formatter: function (value) { if (value === 0.999) { return hideMinAxisLabels ? '' : '99.9%'; diff --git a/frontend/src/app/components/master-page/master-page.component.ts b/frontend/src/app/components/master-page/master-page.component.ts index 12fbc295d..268853356 100644 --- a/frontend/src/app/components/master-page/master-page.component.ts +++ b/frontend/src/app/components/master-page/master-page.component.ts @@ -34,7 +34,7 @@ export class MasterPageComponent implements OnInit, OnDestroy { servicesEnabled = false; menuOpen = false; isDropdownVisible: boolean; - + enterpriseInfo: any; enterpriseInfo$: Subscription; @@ -71,7 +71,7 @@ export class MasterPageComponent implements OnInit, OnDestroy { this.enterpriseInfo$ = this.enterpriseService.info$.subscribe(info => { this.enterpriseInfo = info; }); - + this.servicesEnabled = this.officialMempoolSpace && this.stateService.env.ACCELERATOR === true && this.stateService.network === ''; this.refreshAuth(); diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 8617a4bb1..e4eeaf8a2 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -452,7 +452,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { } else { const estimatedPosition = this.etaService.mempoolPositionFromFees(this.txFeePerVSize, this.mempoolBlocks); this.rightPosition = estimatedPosition.block * (this.blockWidth + this.blockPadding) - + ((estimatedPosition.vsize / this.stateService.blockVSize) * this.blockWidth) + + ((estimatedPosition.vsize / this.stateService.blockVSize) * this.blockWidth); } this.rightPosition = Math.min(this.maxArrowPosition, this.rightPosition); } diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts index 68c5fb9f9..b1db6b96b 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -467,7 +467,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { totalValue: totalValueTemp, totalValueArray: totalValueArray.reverse(), }; - } + }; orderLevels() { this.feeLevelsOrdered = []; diff --git a/frontend/src/app/components/menu/menu.component.ts b/frontend/src/app/components/menu/menu.component.ts index dadf15ecc..1e7142943 100644 --- a/frontend/src/app/components/menu/menu.component.ts +++ b/frontend/src/app/components/menu/menu.component.ts @@ -18,7 +18,7 @@ export class MenuComponent implements OnInit, OnDestroy { @Input() navOpen: boolean = false; @Output() loggedOut = new EventEmitter(); @Output() menuToggled = new EventEmitter(); - + userMenuGroups$: Observable | undefined; user$: Observable; userAuth: any | undefined; @@ -34,7 +34,7 @@ export class MenuComponent implements OnInit, OnDestroy { ngOnInit(): void { this.userAuth = this.storageService.getAuth(); - + if (this.stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE) { this.userMenuGroups$ = this.servicesApiServices.getUserMenuGroups$(); this.user$ = this.servicesApiServices.userSubject$; diff --git a/frontend/src/app/components/ngx-bootstrap-multiselect/ngx-bootstrap-multiselect.component.ts b/frontend/src/app/components/ngx-bootstrap-multiselect/ngx-bootstrap-multiselect.component.ts index 766813247..41d00d043 100644 --- a/frontend/src/app/components/ngx-bootstrap-multiselect/ngx-bootstrap-multiselect.component.ts +++ b/frontend/src/app/components/ngx-bootstrap-multiselect/ngx-bootstrap-multiselect.component.ts @@ -464,7 +464,7 @@ export class NgxDropdownMultiselectComponent implements OnInit, this.model = this.model.slice(); this.fireModelChange(); - }, 0) + }, 0); } updateNumSelected() { diff --git a/frontend/src/app/components/ngx-bootstrap-multiselect/off-click.directive.ts b/frontend/src/app/components/ngx-bootstrap-multiselect/off-click.directive.ts index bbb18a312..bf1124c18 100644 --- a/frontend/src/app/components/ngx-bootstrap-multiselect/off-click.directive.ts +++ b/frontend/src/app/components/ngx-bootstrap-multiselect/off-click.directive.ts @@ -14,7 +14,7 @@ export class OffClickDirective { private _clickEvent: MouseEvent; private _touchEvent: TouchEvent; - @HostListener('click', ['$event']) + @HostListener('click', ['$event']) public onClick(event: MouseEvent): void { this._clickEvent = event; } @@ -24,7 +24,7 @@ export class OffClickDirective { this._touchEvent = event; } - @HostListener('document:click', ['$event']) + @HostListener('document:click', ['$event']) public onDocumentClick(event: MouseEvent): void { if (event !== this._clickEvent) { this.onOffClick.emit(event); diff --git a/frontend/src/app/components/pool/pool.component.ts b/frontend/src/app/components/pool/pool.component.ts index 7035d7c0f..65f82b160 100644 --- a/frontend/src/app/components/pool/pool.component.ts +++ b/frontend/src/app/components/pool/pool.component.ts @@ -222,9 +222,9 @@ export class PoolComponent implements OnInit { hashrateString = `${tick.marker} ${tick.seriesName}: ${this.amountShortenerPipe.transform(tick.data[1], 3, 'H/s', false, true)}
`; } else if (tick.seriesIndex === 1) { dominanceString = `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.0-2')}%`; - } + } } - + return ` ${ticks[0].axisValueLabel}
${hashrateString} @@ -283,7 +283,7 @@ export class PoolComponent implements OnInit { axisLabel: { color: 'rgb(110, 112, 121)', formatter: (val) => { - return `${val}%` + return `${val}%`; } }, splitLine: { diff --git a/frontend/src/app/components/push-transaction/push-transaction.component.ts b/frontend/src/app/components/push-transaction/push-transaction.component.ts index 05ab8bd30..d716ee47c 100644 --- a/frontend/src/app/components/push-transaction/push-transaction.component.ts +++ b/frontend/src/app/components/push-transaction/push-transaction.component.ts @@ -134,7 +134,7 @@ export class PushTransactionComponent implements OnInit { this.isLoadingPackage = false; this.packageMessage = result['package_msg']; - for (let wtxid in result['tx-results']) { + for (const wtxid in result['tx-results']) { this.results.push(result['tx-results'][wtxid]); } @@ -178,7 +178,7 @@ export class PushTransactionComponent implements OnInit { return false; } const rawCheck = this.base64UrlToU8Array(fragmentParams.get('c')); - + // check checksum const hashTx = await crypto.subtle.digest('SHA-256', rawTx); diff --git a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts index 909d57549..ec1b1a6ed 100644 --- a/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts +++ b/frontend/src/app/components/rbf-timeline/rbf-timeline.component.ts @@ -59,7 +59,7 @@ export class RbfTimelineComponent implements OnInit, OnChanges { // converts a tree of RBF events into a format that can be more easily rendered in HTML buildTimelines(tree: RbfTree): TimelineCell[][] { - if (!tree) return []; + if (!tree) {return [];} this.flagFullRbf(tree); const split = this.splitTimelines(tree); diff --git a/frontend/src/app/components/search-form/search-form.component.ts b/frontend/src/app/components/search-form/search-form.component.ts index 4e3656df3..5f2896b66 100644 --- a/frontend/src/app/components/search-form/search-form.component.ts +++ b/frontend/src/app/components/search-form/search-form.component.ts @@ -199,8 +199,8 @@ export class SearchFormComponent implements OnInit { const publicKey = matchesAddress && searchText.startsWith('0'); const otherNetworks = findOtherNetworks(searchText, this.network as any || 'mainnet', this.env); const liquidAsset = this.assets ? (this.assets[searchText] || []) : []; - const pools = this.pools.filter(pool => pool["name"].toLowerCase().includes(searchText.toLowerCase())).slice(0, 10); - + const pools = this.pools.filter(pool => pool['name'].toLowerCase().includes(searchText.toLowerCase())).slice(0, 10); + if (matchesDateTime && searchText.indexOf('/') !== -1) { searchText = searchText.replace(/\//g, '-'); } @@ -338,8 +338,8 @@ export class SearchFormComponent implements OnInit { })) // Sort: active pools first, then alphabetically .sort((a, b) => { - if (a.active && !b.active) return -1; - if (!a.active && b.active) return 1; + if (a.active && !b.active) {return -1;} + if (!a.active && b.active) {return 1;} return a.slug < b.slug ? -1 : 1; }); diff --git a/frontend/src/app/components/start/start.component.ts b/frontend/src/app/components/start/start.component.ts index 0bc0fd212..347a826dd 100644 --- a/frontend/src/app/components/start/start.component.ts +++ b/frontend/src/app/components/start/start.component.ts @@ -165,7 +165,7 @@ export class StartComponent implements OnInit, AfterViewChecked, OnDestroy { if (reset) { this.resetScroll(); this.stateService.resetScroll$.next(false); - } + } }); } @@ -311,7 +311,7 @@ export class StartComponent implements OnInit, AfterViewChecked, OnDestroy { updateVelocity(x: number) { const now = performance.now(); - let dt = now - this.lastUpdate; + const dt = now - this.lastUpdate; if (dt > 0) { this.lastUpdate = now; const velocity = (x - this.lastMouseX) / dt; diff --git a/frontend/src/app/components/statistics/statistics.component.ts b/frontend/src/app/components/statistics/statistics.component.ts index b63b9191c..af486970e 100644 --- a/frontend/src/app/components/statistics/statistics.component.ts +++ b/frontend/src/app/components/statistics/statistics.component.ts @@ -209,7 +209,7 @@ export class StatisticsComponent implements OnInit { } }); } - + onOutlierToggleChange(e): void { this.outlierCappingEnabled = e.target.checked; this.storageService.setValue('cap-outliers', e.target.checked); diff --git a/frontend/src/app/components/timezone-selector/timezone-selector.component.ts b/frontend/src/app/components/timezone-selector/timezone-selector.component.ts index 4aeae09bb..fee05bd69 100644 --- a/frontend/src/app/components/timezone-selector/timezone-selector.component.ts +++ b/frontend/src/app/components/timezone-selector/timezone-selector.component.ts @@ -42,7 +42,7 @@ export class TimezoneSelectorComponent implements OnInit { setLocalTimezone() { const offset = new Date().getTimezoneOffset(); - const sign = offset <= 0 ? "+" : "-"; + const sign = offset <= 0 ? '+' : '-'; const absOffset = Math.abs(offset); const hours = String(Math.floor(absOffset / 60)); const minutes = String(absOffset % 60).padStart(2, '0'); diff --git a/frontend/src/app/components/tracker/tracker-bar.component.ts b/frontend/src/app/components/tracker/tracker-bar.component.ts index 4aa3f4e99..64200ec09 100644 --- a/frontend/src/app/components/tracker/tracker-bar.component.ts +++ b/frontend/src/app/components/tracker/tracker-bar.component.ts @@ -13,7 +13,7 @@ export class TrackerBarComponent implements OnInit, OnChanges { @Input() stage: TrackerStage = 'waiting'; transitionsEnabled: boolean = false; - + stages = { waiting: { state: 'blank', @@ -41,7 +41,7 @@ export class TrackerBarComponent implements OnInit, OnChanges { this.setStage(); setTimeout(() => { this.transitionsEnabled = true; - }, 100) + }, 100); } ngOnChanges(changes: SimpleChanges): void { @@ -52,7 +52,7 @@ export class TrackerBarComponent implements OnInit, OnChanges { setStage() { let matched = 0; - for (let stage of this.stageOrder) { + for (const stage of this.stageOrder) { if (stage === this.stage) { this.stages[stage].state = 'current'; matched = 1; diff --git a/frontend/src/app/components/tracker/tracker.component.ts b/frontend/src/app/components/tracker/tracker.component.ts index 3c7ac3911..1356ac5b5 100644 --- a/frontend/src/app/components/tracker/tracker.component.ts +++ b/frontend/src/app/components/tracker/tracker.component.ts @@ -642,7 +642,7 @@ export class TrackerComponent implements OnInit, OnDestroy { }), tap(eta => { if (this.replaced) { - this.trackerStage = 'replaced' + this.trackerStage = 'replaced'; } else if (eta?.blocks === 0) { this.trackerStage = 'next'; } else if (eta?.blocks < 3){ @@ -651,7 +651,7 @@ export class TrackerComponent implements OnInit, OnDestroy { this.trackerStage = 'pending'; } }) - ) + ); } handleLoadElectrsTransactionError(error: any): Observable { diff --git a/frontend/src/app/components/transaction/liquid-ublinding.ts b/frontend/src/app/components/transaction/liquid-ublinding.ts index 259b06a0b..e6aac46f5 100644 --- a/frontend/src/app/components/transaction/liquid-ublinding.ts +++ b/frontend/src/app/components/transaction/liquid-ublinding.ts @@ -68,7 +68,7 @@ export class LiquidUnblinding { tx._unblinded = { matched, total: this.commitments.size }; this.deduceBlinded(tx); if (matched < this.commitments.size) { - throw new Error(`Invalid blinding data.`) + throw new Error(`Invalid blinding data.`); } tx._deduced = false; // invalidate cache so deduction is attempted again return tx; diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 7b471a391..86856910a 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -174,7 +174,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { setTimeout(() => { this.applyFragment(); }, 0); } } - + @ViewChild('accelerate') set accelerateAnchor(element: ElementRef | null | undefined) { if (element) { @@ -483,7 +483,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { catchError(() => { return of({ audit: null }); }) - ) + ); } else { return this.apiService.getBlockTxAudit$(hash, txid).pipe( retry({ count: 3, delay: 2000 }), @@ -491,7 +491,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { catchError(() => { return of({ audit: null }); }) - ) + ); } } else { const audit = isCoinbase ? { coinbase: true } : null; @@ -906,7 +906,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.accelerationCanceled = true; this.setIsAccelerated(firstCpfp); } - + if (this.notAcceleratedOnLoad === null) { this.notAcceleratedOnLoad = !this.isAcceleration; } @@ -923,11 +923,11 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { } setIsAccelerated(initialState: boolean = false) { - this.isAcceleration = + this.isAcceleration = ( - (this.tx.acceleration && (!this.tx.status.confirmed || this.waitingForAccelerationInfo)) || + (this.tx.acceleration && (!this.tx.status.confirmed || this.waitingForAccelerationInfo)) || (this.accelerationInfo && this.pool && this.accelerationInfo.pools.some(pool => (pool === this.pool.id))) - ) && + ) && !this.accelerationCanceled; if (this.isAcceleration) { if (initialState) { diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.ts b/frontend/src/app/components/transactions-list/transactions-list.component.ts index 1c2935f62..1a0d4b729 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.ts +++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts @@ -225,7 +225,7 @@ export class TransactionsListComponent implements OnInit, OnChanges, OnDestroy { setTimeout(() => { const assetBoxElements = document.getElementsByClassName('assetBox'); if (assetBoxElements && assetBoxElements[0]) { - assetBoxElements[0].scrollIntoView({block: "center"}); + assetBoxElements[0].scrollIntoView({block: 'center'}); } }, 10); } @@ -422,8 +422,8 @@ export class TransactionsListComponent implements OnInit, OnChanges, OnDestroy { const similarity = checkedCompareAddressStrings(address, compareAddr.scriptpubkey_address, addressType as AddressType, this.stateService.network); if (similarity?.status === 'comparable' && similarity.score > adjustedThreshold) { // Get or create group numbers for both addresses - let group1 = similarityGroups.get(address); - let group2 = similarityGroups.get(compareAddr.scriptpubkey_address); + const group1 = similarityGroups.get(address); + const group2 = similarityGroups.get(compareAddr.scriptpubkey_address); let group: number; if (group1 !== undefined && group2 !== undefined) { @@ -537,7 +537,7 @@ export class TransactionsListComponent implements OnInit, OnChanges, OnDestroy { this.electrsApiService.getTransaction$(tx.txid) .subscribe((newTx) => { tx['@vinLoaded'] = true; - let temp = tx.vin; + const temp = tx.vin; tx.vin = newTx.vin; tx.fee = newTx.fee; for (const [index, vin] of temp.entries()) { diff --git a/frontend/src/app/components/treasuries/treasuries-graph/treasuries-graph.component.ts b/frontend/src/app/components/treasuries/treasuries-graph/treasuries-graph.component.ts index a040a85b8..f62bbd2f0 100644 --- a/frontend/src/app/components/treasuries/treasuries-graph/treasuries-graph.component.ts +++ b/frontend/src/app/components/treasuries/treasuries-graph/treasuries-graph.component.ts @@ -119,7 +119,7 @@ export class TreasuriesGraphComponent implements OnInit, OnChanges, OnDestroy { this.walletData = {}; this.treasuries.forEach(treasury => { - if (!walletSummaries[treasury.wallet] || !walletSummaries[treasury.wallet].length) return; + if (!walletSummaries[treasury.wallet] || !walletSummaries[treasury.wallet].length) {return;} const total = this.walletStats[treasury.wallet] ? this.walletStats[treasury.wallet].balance : walletSummaries[treasury.wallet].reduce((acc, tx) => acc + tx.value, 0); @@ -267,8 +267,8 @@ export class TreasuriesGraphComponent implements OnInit, OnChanges, OnDestroy { const tooltipTime = data[0].data[0]; let tooltip = '
'; - const date = new Date(tooltipTime).toLocaleTimeString(this.locale, { - year: 'numeric', month: 'short', day: 'numeric' + const date = new Date(tooltipTime).toLocaleTimeString(this.locale, { + year: 'numeric', month: 'short', day: 'numeric' }); tooltip += `
${date}
`; @@ -304,7 +304,7 @@ export class TreasuriesGraphComponent implements OnInit, OnChanges, OnDestroy { if (mostRecentPoint) { // Extract balance from the point - const balance = Array.isArray(mostRecentPoint) ? mostRecentPoint[1] : + const balance = Array.isArray(mostRecentPoint) ? mostRecentPoint[1] : (mostRecentPoint && typeof mostRecentPoint === 'object' && 'value' in mostRecentPoint ? mostRecentPoint.value[1] : null); if (balance !== null && !isNaN(balance)) { @@ -339,7 +339,7 @@ export class TreasuriesGraphComponent implements OnInit, OnChanges, OnDestroy { show: this.showYAxis, color: 'rgb(110, 112, 121)', formatter: (val): string => { - let valSpan = maxValue - (this.period === 'all' ? 0 : minValue); + const valSpan = maxValue - (this.period === 'all' ? 0 : minValue); if (valSpan > 100_000_000_000) { return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 0, undefined, true)} BTC`; } diff --git a/frontend/src/app/components/twitter-widget/twitter-widget.component.ts b/frontend/src/app/components/twitter-widget/twitter-widget.component.ts index 361fb49fa..502d67b96 100644 --- a/frontend/src/app/components/twitter-widget/twitter-widget.component.ts +++ b/frontend/src/app/components/twitter-widget/twitter-widget.component.ts @@ -38,7 +38,7 @@ export class TwitterWidgetComponent implements OnChanges { if (!this.handle) { return; } - let url = `/api/v1/services/x/${this.handle}`; + const url = `/api/v1/services/x/${this.handle}`; this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(this.sanitizer.sanitize(SecurityContext.URL, url)); } diff --git a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.ts b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.ts index cf3daa61c..5eadb222d 100644 --- a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.ts +++ b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.ts @@ -108,7 +108,7 @@ export class TxBowtieGraphTooltipComponent implements OnChanges { } fetchPrices(changes: any) { - if (!this.currency || !this.viewFiat) return; + if (!this.currency || !this.viewFiat) {return;} if (this.isConnector) { // If the tooltip is on a connector, we fetch prices at the time of the input / output if (['input', 'output'].includes(changes.line.currentValue.type) && changes.line.currentValue?.status?.block_time && !this.blockConversions?.[changes.line.currentValue?.status.block_time]) { this.priceService.getBlockPrice$(changes.line.currentValue?.status.block_time, true, this.currency).pipe( @@ -122,7 +122,7 @@ export class TxBowtieGraphTooltipComponent implements OnChanges { tap((price) => this.blockConversions[changes.line.currentValue.timestamp] = price), ).subscribe(); } - } + } } } diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts index aa5fe80a2..946d463cf 100644 --- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts +++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts @@ -239,7 +239,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { } calcTotalValue(tx: Transaction): number { - let totalOutput = this.tx.vout.reduce((acc, v) => (this.getOutputValue(v) || 0) + acc, 0); + const totalOutput = this.tx.vout.reduce((acc, v) => (this.getOutputValue(v) || 0) + acc, 0); // simple sum of outputs + fee for bitcoin if (!this.isLiquid) { return this.tx.fee ? totalOutput + this.tx.fee : totalOutput; diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index 2e57e6f81..18bcf9cf0 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -315,21 +315,21 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { switchMap(_ => this.apiService.recentPegsList$()), share() ); - + this.pegsVolume$ = this.auditUpdated$.pipe( filter(auditUpdated => auditUpdated === true), throttleTime(40000), switchMap(_ => this.apiService.pegsVolume$()), share() ); - + this.federationAddresses$ = this.auditUpdated$.pipe( filter(auditUpdated => auditUpdated === true), throttleTime(40000), switchMap(_ => this.apiService.federationAddresses$()), share() ); - + this.federationAddressesNumber$ = this.auditUpdated$.pipe( filter(auditUpdated => auditUpdated === true), throttleTime(40000), @@ -337,7 +337,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { map(count => count.address_count), share() ); - + this.federationUtxosNumber$ = this.auditUpdated$.pipe( filter(auditUpdated => auditUpdated === true), throttleTime(40000), @@ -359,7 +359,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { switchMap(_ => this.apiService.emergencySpentUtxosStats$()), share() ); - + this.liquidPegsMonth$ = interval(60 * 60 * 1000) .pipe( startWith(0), @@ -375,7 +375,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { }), share(), ); - + this.liquidReservesMonth$ = interval(60 * 60 * 1000).pipe( startWith(0), switchMap(() => this.apiService.listLiquidReservesMonth$()), @@ -389,12 +389,12 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { }), share() ); - + this.fullHistory$ = combineLatest([this.liquidPegsMonth$, this.currentPeg$, this.liquidReservesMonth$, this.currentReserves$]) .pipe( map(([liquidPegs, currentPeg, liquidReserves, currentReserves]) => { liquidPegs.series[liquidPegs.series.length - 1] = parseFloat(currentPeg.amount) / 100000000; - + if (liquidPegs.series.length === liquidReserves?.series.length) { liquidReserves.series[liquidReserves.series.length - 1] = parseFloat(currentReserves?.amount) / 100000000; } else if (liquidPegs.series.length === liquidReserves?.series.length + 1) { @@ -406,7 +406,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { labels: [] }; } - + return { liquidPegs, liquidReserves @@ -438,7 +438,7 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit { getArrayFromNumber(num: number): number[] { return Array.from({ length: num }, (_, i) => i + 1); } - + setFilter(index): void { const selected = this.goggleCycle[index]; this.stateService.activeGoggles$.next(selected); diff --git a/frontend/src/app/docs/api-docs/api-docs-data.ts b/frontend/src/app/docs/api-docs/api-docs-data.ts index fd365c43e..0b19fc348 100644 --- a/frontend/src/app/docs/api-docs/api-docs-data.ts +++ b/frontend/src/app/docs/api-docs/api-docs-data.ts @@ -1,7 +1,7 @@ -const bitcoinNetworks = ["", "testnet", "testnet4", "signet"]; -const liquidNetworks = ["liquid", "liquidtestnet"]; -const lightningNetworks = ["", "testnet", "signet"]; -const miningTimeIntervals = "24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y"; +const bitcoinNetworks = ['', 'testnet', 'testnet4', 'signet']; +const liquidNetworks = ['liquid', 'liquidtestnet']; +const lightningNetworks = ['', 'testnet', 'signet']; +const miningTimeIntervals = '24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y'; const emptyCodeSample = { esModule: [], @@ -10,24 +10,24 @@ const emptyCodeSample = { response: `` }; -const showJsExamplesDefault = { "": true, "testnet": true, "signet": true, "liquid": true, "liquidtestnet": false }; -const showJsExamplesDefaultFalse = { "": false, "testnet": false, "signet": false, "liquid": false, "liquidtestnet": false }; +const showJsExamplesDefault = { '': true, 'testnet': true, 'signet': true, 'liquid': true, 'liquidtestnet': false }; +const showJsExamplesDefaultFalse = { '': false, 'testnet': false, 'signet': false, 'liquid': false, 'liquidtestnet': false }; export const wsApiDocsData = [ { - type: "category", - category: "general", - fragment: "general", - title: "General", + type: 'category', + category: 'general', + fragment: 'general', + title: 'General', showConditions: bitcoinNetworks.concat(liquidNetworks) }, { - type: "endpoint", - category: "general", - fragment: "live-data", - title: "Live Data", + type: 'endpoint', + category: 'general', + fragment: 'live-data', + title: 'Live Data', description: { - default: "Subscribe to live data. Available: blocks, mempool-block, live-2h-chart, and stats." + default: 'Subscribe to live data. Available: blocks, mempool-block, live-2h-chart, and stats.' }, payload: '{ "action": "want", "data": ["mempool-blocks", "stats"] }', showConditions: bitcoinNetworks.concat(liquidNetworks), @@ -300,19 +300,19 @@ export const wsApiDocsData = [ } }, { - type: "category", - category: "addresses", - fragment: "addresses", - title: "Addresses", + type: 'category', + category: 'addresses', + fragment: 'addresses', + title: 'Addresses', showConditions: bitcoinNetworks.concat(liquidNetworks) }, { - type: "endpoint", - category: "addresses", - fragment: "track-address", - title: "Track Address", + type: 'endpoint', + category: 'addresses', + fragment: 'track-address', + title: 'Track Address', description: { - default: "Subscribe to a single address to receive live updates on new transactions having that address in input or output. address-transactions field contains new mempool transactions, and block-transactions contains new confirmed transactions." + default: 'Subscribe to a single address to receive live updates on new transactions having that address in input or output. address-transactions field contains new mempool transactions, and block-transactions contains new confirmed transactions.' }, payload: '{ "track-address": "bc1qeldw4mqns26wew8swgpkt3fs364w3ehs046w2f" }', showConditions: bitcoinNetworks.concat(liquidNetworks), @@ -697,12 +697,12 @@ export const wsApiDocsData = [ } }, { - type: "endpoint", - category: "addresses", - fragment: "track-addresses", - title: "Track Addresses", + type: 'endpoint', + category: 'addresses', + fragment: 'track-addresses', + title: 'Track Addresses', description: { - default: "Subscribe to multiple addresses to receive live updates on new transactions having these addresses in input or output. Limits on the maximum number of tracked addresses apply. For higher tracking limits, consider upgrading to an enterprise sponsorship." + default: 'Subscribe to multiple addresses to receive live updates on new transactions having these addresses in input or output. Limits on the maximum number of tracked addresses apply. For higher tracking limits, consider upgrading to an enterprise sponsorship.' }, payload: `{ "track-addresses": [ @@ -1122,19 +1122,19 @@ export const wsApiDocsData = [ } }, { - type: "category", - category: "transactions", - fragment: "transactions", - title: "Transactions", + type: 'category', + category: 'transactions', + fragment: 'transactions', + title: 'Transactions', showConditions: bitcoinNetworks.concat(liquidNetworks) }, { - type: "endpoint", - category: "transactions", - fragment: "track-tx", - title: "Track Transaction", + type: 'endpoint', + category: 'transactions', + fragment: 'track-tx', + title: 'Track Transaction', description: { - default: "Subscribe to a transaction to receive live updates on its confirmation status and position in the mempool." + default: 'Subscribe to a transaction to receive live updates on its confirmation status and position in the mempool.' }, payload: '{ "track-tx": "8a4666c6d22ce74fa47e1c4fdb09af556a234cc6a606539a75caf66ba44a2d07" }', showConditions: bitcoinNetworks.concat(liquidNetworks), @@ -1291,12 +1291,12 @@ export const wsApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - fragment: "track-txs", - title: "Track Transactions", + type: 'endpoint', + category: 'transactions', + fragment: 'track-txs', + title: 'Track Transactions', description: { - default: "Subscribe to multiple transactions to receive live updates on their status and position in the mempool. Limits on the maximum number of tracked addresses apply. For higher tracking limits, consider upgrading to an enterprise sponsorship." + default: 'Subscribe to multiple transactions to receive live updates on their status and position in the mempool. Limits on the maximum number of tracked addresses apply. For higher tracking limits, consider upgrading to an enterprise sponsorship.' }, payload: `{ "track-txs": [ @@ -1477,19 +1477,19 @@ export const wsApiDocsData = [ } }, { - type: "category", - category: "mempool", - fragment: "mempool", - title: "Mempool", + type: 'category', + category: 'mempool', + fragment: 'mempool', + title: 'Mempool', showConditions: bitcoinNetworks.concat(liquidNetworks) }, { - type: "endpoint", - category: "mempool", - fragment: "track-mempool", - title: "Track Mempool", + type: 'endpoint', + category: 'mempool', + fragment: 'track-mempool', + title: 'Track Mempool', description: { - default: "Subscribe to new mempool events, such as new transactions entering the mempool. Available fields: added, removed, mined, replaced.
Because this is potentially a lot of data, consider using the track-mempool-txids endpoint described below instead, or upgrade to an enterprise sponsorship." + default: 'Subscribe to new mempool events, such as new transactions entering the mempool. Available fields: added, removed, mined, replaced.
Because this is potentially a lot of data, consider using the track-mempool-txids endpoint described below instead, or upgrade to an enterprise sponsorship.' }, payload: '{ "track-mempool": true }', showConditions: bitcoinNetworks.concat(liquidNetworks), @@ -1818,12 +1818,12 @@ export const wsApiDocsData = [ } }, { - type: "endpoint", - category: "mempool", - fragment: "track-mempool-txids", - title: "Track Mempool Txids", + type: 'endpoint', + category: 'mempool', + fragment: 'track-mempool-txids', + title: 'Track Mempool Txids', description: { - default: "Low-bandwith substitute to the above command track-mempool: subscribe to new mempool events, such as new transactions entering the mempool, but only transaction IDs are returned to save bandwith. Available fields: added, removed, mined, replaced." + default: 'Low-bandwith substitute to the above command track-mempool: subscribe to new mempool events, such as new transactions entering the mempool, but only transaction IDs are returned to save bandwith. Available fields: added, removed, mined, replaced.' }, payload: '{ "track-mempool-txids": true }', showConditions: bitcoinNetworks.concat(liquidNetworks), @@ -1924,12 +1924,12 @@ export const wsApiDocsData = [ } }, { - type: "endpoint", - category: "mempool", - fragment: "track-mempool-block", - title: "Track Mempool Block", + type: 'endpoint', + category: 'mempool', + fragment: 'track-mempool-block', + title: 'Track Mempool Block', description: { - default: "Subscribe to live mempool projected block template, index 0 being the first mempool block.
A full set of stripped transactions in that block is returned when the subscription starts, and deltas (removed and added transactions) are then sent every time the mempool changes." + default: 'Subscribe to live mempool projected block template, index 0 being the first mempool block.
A full set of stripped transactions in that block is returned when the subscription starts, and deltas (removed and added transactions) are then sent every time the mempool changes.' }, payload: '{ "track-mempool-block": 0 }', showConditions: bitcoinNetworks.concat(liquidNetworks), @@ -2062,12 +2062,12 @@ export const wsApiDocsData = [ } }, { - type: "endpoint", - category: "mempool", - fragment: "track-rbf", - title: "Track Mempool RBF Transactions", + type: 'endpoint', + category: 'mempool', + fragment: 'track-rbf', + title: 'Track Mempool RBF Transactions', description: { - default: "Subscribe to new RBF events." + default: 'Subscribe to new RBF events.' }, payload: '{ "track-rbf": "all" }', showConditions: bitcoinNetworks, @@ -2255,12 +2255,12 @@ export const wsApiDocsData = [ } }, { - type: "endpoint", - category: "mempool", - fragment: "track-full-rbf", - title: "Track Mempool Full RBF Transactions", + type: 'endpoint', + category: 'mempool', + fragment: 'track-full-rbf', + title: 'Track Mempool Full RBF Transactions', description: { - default: "Subscribe to new Full RBF events." + default: 'Subscribe to new Full RBF events.' }, payload: '{ "track-rbf": "fullRbf" }', showConditions: bitcoinNetworks, @@ -2452,22 +2452,22 @@ export const wsApiDocsData = [ export const restApiDocsData = [ { - type: "category", - category: "general", - fragment: "general", - title: "General", + type: 'category', + category: 'general', + fragment: 'general', + title: 'General', showConditions: bitcoinNetworks, }, { - type: "endpoint", - category: "general", - httpRequestMethod: "GET", - fragment: "get-difficulty-adjustment", - title: "GET Difficulty Adjustment", + type: 'endpoint', + category: 'general', + httpRequestMethod: 'GET', + fragment: 'get-difficulty-adjustment', + title: 'GET Difficulty Adjustment', description: { - default: "Returns details about difficulty adjustment." + default: 'Returns details about difficulty adjustment.' }, - urlString: "/v1/difficulty-adjustment", + urlString: '/v1/difficulty-adjustment', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -2560,16 +2560,16 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "general", - httpRequestMethod: "GET", - fragment: "get-price", - title: "GET Price", + type: 'endpoint', + category: 'general', + httpRequestMethod: 'GET', + fragment: 'get-price', + title: 'GET Price', description: { - default: "Returns bitcoin latest price denominated in main currencies." + default: 'Returns bitcoin latest price denominated in main currencies.' }, - urlString: "/v1/prices", - showConditions: [""], + urlString: '/v1/prices', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -2601,16 +2601,16 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "general", - httpRequestMethod: "GET", - fragment: "get-historical-price", - title: "GET Historical Price", + type: 'endpoint', + category: 'general', + httpRequestMethod: 'GET', + fragment: 'get-historical-price', + title: 'GET Historical Price', description: { - default: "Returns bitcoin historical price denominated in main currencies. Available query parameters: currency, timestamp. If no parameter is provided, the full price history for all currencies is returned." + default: 'Returns bitcoin historical price denominated in main currencies. Available query parameters: currency, timestamp. If no parameter is provided, the full price history for all currencies is returned.' }, - urlString: "/v1/historical-price?currency=EUR×tamp=1500000000", - showConditions: [""], + urlString: '/v1/historical-price?currency=EUR×tamp=1500000000', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -2650,22 +2650,22 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "addresses", - fragment: "addresses", - title: "Addresses", + type: 'category', + category: 'addresses', + fragment: 'addresses', + title: 'Addresses', showConditions: bitcoinNetworks.concat(liquidNetworks) }, { - type: "endpoint", - category: "addresses", - httpRequestMethod: "GET", - fragment: "get-address", - title: "GET Address", + type: 'endpoint', + category: 'addresses', + httpRequestMethod: 'GET', + fragment: 'get-address', + title: 'GET Address', description: { - default: "Returns details about an address. Available fields: address, chain_stats, and mempool_stats. chain_stats and mempool_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count, and spent_txo_sum." + default: 'Returns details about an address. Available fields: address, chain_stats, and mempool_stats. chain_stats and mempool_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count, and spent_txo_sum.' }, - urlString: "/address/:address", + urlString: '/address/:address', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -2794,15 +2794,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "addresses", - httpRequestMethod: "GET", - fragment: "get-address-transactions", - title: "GET Address Transactions", + type: 'endpoint', + category: 'addresses', + httpRequestMethod: 'GET', + fragment: 'get-address-transactions', + title: 'GET Address Transactions', description: { - default: "Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using an after_txid query parameter." + default: 'Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using an after_txid query parameter.' }, - urlString: "/address/:address/txs", + urlString: '/address/:address/txs', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -2947,15 +2947,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "addresses", - httpRequestMethod: "GET", - fragment: "get-address-transactions-chain", - title: "GET Address Transactions Chain", + type: 'endpoint', + category: 'addresses', + httpRequestMethod: 'GET', + fragment: 'get-address-transactions-chain', + title: 'GET Address Transactions Chain', description: { - default: "Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query." + default: 'Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.' }, - urlString: "/address/:address/txs/chain", + urlString: '/address/:address/txs/chain', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -3100,15 +3100,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "addresses", - httpRequestMethod: "GET", - fragment: "get-address-transactions-mempool", - title: "GET Address Transactions Mempool", + type: 'endpoint', + category: 'addresses', + httpRequestMethod: 'GET', + fragment: 'get-address-transactions-mempool', + title: 'GET Address Transactions Mempool', description: { - default: "Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging)." + default: 'Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging).' }, - urlString: "/address/:address/txs/mempool", + urlString: '/address/:address/txs/mempool', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -3225,16 +3225,16 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "addresses", - httpRequestMethod: "GET", - fragment: "get-address-utxo", - title: "GET Address UTXO", + type: 'endpoint', + category: 'addresses', + httpRequestMethod: 'GET', + fragment: 'get-address-utxo', + title: 'GET Address UTXO', description: { - default: "Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx).", - liquid: "Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx). There is also a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof, and range_proof.", + default: 'Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx).', + liquid: 'Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx). There is also a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof, and range_proof.', }, - urlString: "/address/:address/utxo", + urlString: '/address/:address/utxo', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -3357,15 +3357,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "addresses", - httpRequestMethod: "GET", - fragment: "get-address-validate", - title: "GET Address Validation", + type: 'endpoint', + category: 'addresses', + httpRequestMethod: 'GET', + fragment: 'get-address-validate', + title: 'GET Address Validation', description: { - default: "Returns whether an address is valid or not. Available fields: isvalid (boolean), address (string), scriptPubKey (string), isscript (boolean), iswitness (boolean), witness_version (numeric, optional), and witness_program (string, optional).", + default: 'Returns whether an address is valid or not. Available fields: isvalid (boolean), address (string), scriptPubKey (string), isscript (boolean), iswitness (boolean), witness_version (numeric, optional), and witness_program (string, optional).', }, - urlString: "/v1/validate-address/:address", + urlString: '/v1/validate-address/:address', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -3415,22 +3415,22 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "assets", - fragment: "assets", - title: "Assets", + type: 'category', + category: 'assets', + fragment: 'assets', + title: 'Assets', showConditions: liquidNetworks }, { - type: "endpoint", - category: "assets", - httpRequestMethod: "GET", - fragment: "get-asset", - title: "GET Asset", + type: 'endpoint', + category: 'assets', + httpRequestMethod: 'GET', + fragment: 'get-asset', + title: 'GET Asset', description: { - default: "Returns information about a Liquid asset." + default: 'Returns information about a Liquid asset.' }, - urlString: "/asset/:asset_id", + urlString: '/asset/:asset_id', showConditions: liquidNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -3522,15 +3522,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "assets", - httpRequestMethod: "GET", - fragment: "get-asset-transactions", - title: "GET Asset Transactions", + type: 'endpoint', + category: 'assets', + httpRequestMethod: 'GET', + fragment: 'get-asset-transactions', + title: 'GET Asset Transactions', description: { - default: "Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset." + default: 'Returns transactions associated with the specified Liquid asset. For the network\'s native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset.' }, - urlString: "/asset/:asset_id/txs[/mempool|/chain]", + urlString: '/asset/:asset_id/txs[/mempool|/chain]', showConditions: liquidNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -3608,15 +3608,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "assets", - httpRequestMethod: "GET", - fragment: "get-asset-supply", - title: "GET Asset Supply", + type: 'endpoint', + category: 'assets', + httpRequestMethod: 'GET', + fragment: 'get-asset-supply', + title: 'GET Asset Supply', description: { - default: "Get the current total supply of the specified asset. For the native asset (LBTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units." + default: 'Get the current total supply of the specified asset. For the native asset (LBTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset\'s divisibility. Otherwise, returned in base units.' }, - urlString: "/asset/:asset_id/supply[/decimal]", + urlString: '/asset/:asset_id/supply[/decimal]', showConditions: liquidNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -3658,15 +3658,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "assets", - httpRequestMethod: "GET", - fragment: "get-asset-icons", - title: "GET Asset Icons", + type: 'endpoint', + category: 'assets', + httpRequestMethod: 'GET', + fragment: 'get-asset-icons', + title: 'GET Asset Icons', description: { - default: "Get all the Asset IDs that have icons." + default: 'Get all the Asset IDs that have icons.' }, - urlString: "/v1/assets/icons", + urlString: '/v1/assets/icons', showConditions: liquidNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -3699,15 +3699,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "assets", - httpRequestMethod: "GET", - fragment: "get-asset-icon", - title: "GET Asset Icon", + type: 'endpoint', + category: 'assets', + httpRequestMethod: 'GET', + fragment: 'get-asset-icon', + title: 'GET Asset Icon', description: { - default: "Get the icon of the specified asset." + default: 'Get the icon of the specified asset.' }, - urlString: "/v1/asset/:asset_id/icon", + urlString: '/v1/asset/:asset_id/icon', showConditions: liquidNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -3733,23 +3733,23 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "blocks", - fragment: "blocks", - title: "Blocks", + type: 'category', + category: 'blocks', + fragment: 'blocks', + title: 'Blocks', showConditions: bitcoinNetworks.concat(liquidNetworks) }, { options: { electrsOnly: true }, - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block", - title: "GET Block", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block', + title: 'GET Block', description: { - default: "Returns details about a block.", + default: 'Returns details about a block.', }, - urlString: "/block/:hash", + urlString: '/block/:hash', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -3875,15 +3875,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-v1", - title: "GET Block (v1)", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-v1', + title: 'GET Block (v1)', description: { - default: "Returns details about a block using Mempool's Node.js backend.", + default: 'Returns details about a block using Mempool\'s Node.js backend.', }, - urlString: "/v1/block/:hash", + urlString: '/v1/block/:hash', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4160,15 +4160,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-header", - title: "GET Block Header", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-header', + title: 'GET Block Header', description: { - default: "Returns the hex-encoded block header." + default: 'Returns the hex-encoded block header.' }, - urlString: "/block/:hash/header", + urlString: '/block/:hash/header', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4225,15 +4225,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-height", - title: "GET Block Height", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-height', + title: 'GET Block Height', description: { - default: "Returns the hash of the block currently at :height." + default: 'Returns the hash of the block currently at :height.' }, - urlString: "/block-height/:height", + urlString: '/block-height/:height', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4287,15 +4287,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-timestamp", - title: "GET Block Timestamp", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-timestamp', + title: 'GET Block Timestamp', description: { - default: "Returns the height and the hash of the block closest to the given :timestamp." + default: 'Returns the height and the hash of the block closest to the given :timestamp.' }, - urlString: "/v1/mining/blocks/timestamp/:timestamp", + urlString: '/v1/mining/blocks/timestamp/:timestamp', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -4341,15 +4341,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-raw", - title: "GET Block Raw", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-raw', + title: 'GET Block Raw', description: { - default: "Returns the raw block representation in binary." + default: 'Returns the raw block representation in binary.' }, - urlString: "/block/:hash/raw", + urlString: '/block/:hash/raw', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4406,15 +4406,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-status", - title: "GET Block Status", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-status', + title: 'GET Block Status', description: { - default: "Returns the confirmation status of a block. Available fields: in_best_chain (boolean, false for orphaned blocks), next_best (the hash of the next block, only available for blocks in the best chain)." + default: 'Returns the confirmation status of a block. Available fields: in_best_chain (boolean, false for orphaned blocks), next_best (the hash of the next block, only available for blocks in the best chain).' }, - urlString: "/block/:hash/status", + urlString: '/block/:hash/status', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4491,15 +4491,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-tip-height", - title: "GET Block Tip Height", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-tip-height', + title: 'GET Block Tip Height', description: { - default: "Returns the height of the last block." + default: 'Returns the height of the last block.' }, - urlString: "/blocks/tip/height", + urlString: '/blocks/tip/height', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4554,15 +4554,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-tip-hash", - title: "GET Block Tip Hash", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-tip-hash', + title: 'GET Block Tip Hash', description: { - default: "Returns the hash of the last block." + default: 'Returns the hash of the last block.' }, - urlString: "/blocks/tip/hash", + urlString: '/blocks/tip/hash', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4617,15 +4617,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-transaction-id", - title: "GET Block Transaction ID", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-transaction-id', + title: 'GET Block Transaction ID', description: { - default: "Returns the transaction at index :index within the specified block." + default: 'Returns the transaction at index :index within the specified block.' }, - urlString: "/block/:hash/txid/:index", + urlString: '/block/:hash/txid/:index', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4682,15 +4682,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-transaction-ids", - title: "GET Block Transaction IDs", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-transaction-ids', + title: 'GET Block Transaction IDs', description: { - default: "Returns a list of all txids in the block." + default: 'Returns a list of all txids in the block.' }, - urlString: "/block/:hash/txids", + urlString: '/block/:hash/txids', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4776,15 +4776,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-block-transactions", - title: "GET Block Transactions", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-block-transactions', + title: 'GET Block Transactions', description: { - default: "Returns a list of transactions in the block (up to 25 transactions beginning at start_index). Transactions returned here do not have the status field, since all the transactions share the same block and confirmation status." + default: 'Returns a list of transactions in the block (up to 25 transactions beginning at start_index). Transactions returned here do not have the status field, since all the transactions share the same block and confirmation status.' }, - urlString: "/block/:hash/txs[/:start_index]", + urlString: '/block/:hash/txs[/:start_index]', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -4932,15 +4932,15 @@ export const restApiDocsData = [ }, { options: { electrsOnly: true }, - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-blocks", - title: "GET Blocks", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-blocks', + title: 'GET Blocks', description: { - default: "Returns details on the past 10 blocks. If :startHeight is specified, the 10 blocks before (and including) :startHeight are returned." + default: 'Returns details on the past 10 blocks. If :startHeight is specified, the 10 blocks before (and including) :startHeight are returned.' }, - urlString: "/blocks[/:startHeight]", + urlString: '/blocks[/:startHeight]', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -5081,15 +5081,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-blocks-v1", - title: "GET Blocks (v1)", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-blocks-v1', + title: 'GET Blocks (v1)', description: { - default: "Returns details on the past 15 blocks from Mempool's Node.js backend. Includes fee and mining details in an extras field. If :startHeight is specified, the past 15 blocks before (and including) :startHeight are returned." + default: 'Returns details on the past 15 blocks from Mempool\'s Node.js backend. Includes fee and mining details in an extras field. If :startHeight is specified, the past 15 blocks before (and including) :startHeight are returned.' }, - urlString: "/v1/blocks[/:startHeight]", + urlString: '/v1/blocks[/:startHeight]', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -5305,15 +5305,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-blocks-bulk", - title: "GET Blocks (Bulk)", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-blocks-bulk', + title: 'GET Blocks (Bulk)', description: { - default: "

Returns details on the range of blocks between :minHeight and :maxHeight, inclusive, up to 10 blocks. If :maxHeight is not specified, it defaults to the current tip.

To return data for more than 10 blocks, consider becoming an enterprise sponsor.

" + default: '

Returns details on the range of blocks between :minHeight and :maxHeight, inclusive, up to 10 blocks. If :maxHeight is not specified, it defaults to the current tip.

To return data for more than 10 blocks, consider becoming an enterprise sponsor.

' }, - urlString: "/v1/blocks-bulk/:minHeight[/:maxHeight]", + urlString: '/v1/blocks-bulk/:minHeight[/:maxHeight]', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -5517,15 +5517,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-blocks", - title: "GET Blocks", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-blocks', + title: 'GET Blocks', description: { - default: "Returns details on the past 10 blocks with fee and mining details in an extras field. If :startHeight is specified, the past 10 blocks before (and including) :startHeight are returned." + default: 'Returns details on the past 10 blocks with fee and mining details in an extras field. If :startHeight is specified, the past 10 blocks before (and including) :startHeight are returned.' }, - urlString: "/blocks[/:startHeight]", + urlString: '/blocks[/:startHeight]', showConditions: liquidNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -5617,15 +5617,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "blocks", - httpRequestMethod: "GET", - fragment: "get-blocks-v1", - title: "GET Blocks (v1)", + type: 'endpoint', + category: 'blocks', + httpRequestMethod: 'GET', + fragment: 'get-blocks-v1', + title: 'GET Blocks (v1)', description: { - default: "Returns details on the past 15 blocks from Mempool's Node.js backend. If :startHeight is specified, the past 15 blocks before (and including) :startHeight are returned." + default: 'Returns details on the past 15 blocks from Mempool\'s Node.js backend. If :startHeight is specified, the past 15 blocks before (and including) :startHeight are returned.' }, - urlString: "/v1/blocks[/:startHeight]", + urlString: '/v1/blocks[/:startHeight]', showConditions: liquidNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -5716,22 +5716,22 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "mining", - fragment: "mining", - title: "Mining", + type: 'category', + category: 'mining', + fragment: 'mining', + title: 'Mining', showConditions: bitcoinNetworks }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-mining-pools", - title: "GET Mining Pools", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-mining-pools', + title: 'GET Mining Pools', description: { - default: "Returns a list of all known mining pools ordered by blocks found over the specified trailing :timePeriod.

Leave :timePeriod unspecified to get all available data, or specify one of the following values: " + miningTimeIntervals + "." + default: 'Returns a list of all known mining pools ordered by blocks found over the specified trailing :timePeriod.

Leave :timePeriod unspecified to get all available data, or specify one of the following values: ' + miningTimeIntervals + '.' }, - urlString: "/v1/mining/pools[/:timePeriod]", + urlString: '/v1/mining/pools[/:timePeriod]', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -5821,15 +5821,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-mining-pool", - title: "GET Mining Pool", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-mining-pool', + title: 'GET Mining Pool', description: { - default: "

Returns details about the mining pool specified by :slug.

" + default: '

Returns details about the mining pool specified by :slug.

' }, - urlString: "/v1/mining/pool/:slug", + urlString: '/v1/mining/pool/:slug', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -5913,15 +5913,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-mining-pool-hashrates", - title: "GET Mining Pool Hashrates", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-mining-pool-hashrates', + title: 'GET Mining Pool Hashrates', description: { - default: "

Returns average hashrates (and share of total hashrate) of mining pools active in the specified trailing :timePeriod, in descending order of hashrate.

Leave :timePeriod unspecified to get all available data, or specify any of the following time periods: " + miningTimeIntervals.substr(52) + ".

" + default: '

Returns average hashrates (and share of total hashrate) of mining pools active in the specified trailing :timePeriod, in descending order of hashrate.

Leave :timePeriod unspecified to get all available data, or specify any of the following time periods: ' + miningTimeIntervals.substr(52) + '.

' }, - urlString: "/v1/mining/hashrate/pools/[:timePeriod]", + urlString: '/v1/mining/hashrate/pools/[:timePeriod]', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -6019,15 +6019,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-mining-pool-hashrate", - title: "GET Mining Pool Hashrate", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-mining-pool-hashrate', + title: 'GET Mining Pool Hashrate', description: { - default: "Returns all known hashrate data for the mining pool specified by :slug. Hashrate values are weekly averages." + default: 'Returns all known hashrate data for the mining pool specified by :slug. Hashrate values are weekly averages.' }, - urlString: "/v1/mining/pool/:slug/hashrate", + urlString: '/v1/mining/pool/:slug/hashrate', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -6139,15 +6139,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-mining-pool-blocks", - title: "GET Mining Pool Blocks", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-mining-pool-blocks', + title: 'GET Mining Pool Blocks', description: { - default: "Returns past 10 blocks mined by the specified mining pool (:slug) before the specified :blockHeight. If no :blockHeight is specified, the mining pool's 10 most recent blocks are returned." + default: 'Returns past 10 blocks mined by the specified mining pool (:slug) before the specified :blockHeight. If no :blockHeight is specified, the mining pool\'s 10 most recent blocks are returned.' }, - urlString: "/v1/mining/pool/:slug/blocks/[:blockHeight]", + urlString: '/v1/mining/pool/:slug/blocks/[:blockHeight]', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -6348,15 +6348,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-hashrate", - title: "GET Hashrate", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-hashrate', + title: 'GET Hashrate', description: { - default: "

Returns network-wide hashrate and difficulty figures over the specified trailing :timePeriod:

  • Current (real-time) hashrate
  • Current (real-time) difficulty
  • Historical daily average hashrates
  • Historical difficulty

Valid values for :timePeriod are " + miningTimeIntervals.substr(52) + ". If no time interval is specified, all available data is returned.

Be sure that INDEXING_BLOCKS_AMOUNT is set properly in your backend config so that enough blocks are indexed to properly serve your request.

" + default: '

Returns network-wide hashrate and difficulty figures over the specified trailing :timePeriod:

  • Current (real-time) hashrate
  • Current (real-time) difficulty
  • Historical daily average hashrates
  • Historical difficulty

Valid values for :timePeriod are ' + miningTimeIntervals.substr(52) + '. If no time interval is specified, all available data is returned.

Be sure that INDEXING_BLOCKS_AMOUNT is set properly in your backend config so that enough blocks are indexed to properly serve your request.

' }, - urlString: "/v1/mining/hashrate/[:timePeriod]", + urlString: '/v1/mining/hashrate/[:timePeriod]', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -6467,15 +6467,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-difficulty-adjustments", - title: "GET Difficulty Adjustments", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-difficulty-adjustments', + title: 'GET Difficulty Adjustments', description: { - default: "

Returns the record of difficulty adjustments over the specified trailing :interval:

  • Block timestamp
  • Block height
  • Difficulty
  • Difficulty change

If no time interval is specified, all available data is returned." + default: '

Returns the record of difficulty adjustments over the specified trailing :interval:

  • Block timestamp
  • Block height
  • Difficulty
  • Difficulty change

If no time interval is specified, all available data is returned.' }, - urlString: "/v1/mining/difficulty-adjustments/[:interval]", + urlString: '/v1/mining/difficulty-adjustments/[:interval]', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -6561,15 +6561,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-reward-stats", - title: "GET Reward Stats", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-reward-stats', + title: 'GET Reward Stats', description: { - default: "Returns block reward and total transactions confirmed for the past :blockCount blocks." + default: 'Returns block reward and total transactions confirmed for the past :blockCount blocks.' }, - urlString: "/v1/mining/reward-stats/:blockCount", + urlString: '/v1/mining/reward-stats/:blockCount', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -6621,15 +6621,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-block-fees", - title: "GET Block Fees", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-block-fees', + title: 'GET Block Fees', description: { - default: "

Returns average total fees for blocks in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: " + miningTimeIntervals + ".

For 24h and 3d time periods, every block is included and fee amounts are exact (not averages). For the 1w time period, fees may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, fees are averages.

" + default: '

Returns average total fees for blocks in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: ' + miningTimeIntervals + '.

For 24h and 3d time periods, every block is included and fee amounts are exact (not averages). For the 1w time period, fees may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, fees are averages.

' }, - urlString: "/v1/mining/blocks/fees/:timePeriod", + urlString: '/v1/mining/blocks/fees/:timePeriod', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -6719,15 +6719,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-block-rewards", - title: "GET Block Rewards", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-block-rewards', + title: 'GET Block Rewards', description: { - default: "

Returns average block rewards for blocks in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: " + miningTimeIntervals + ".

For 24h and 3d time periods, every block is included and block rewards are exact (not averages). For the 1w time period, block rewards may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, block rewards are averages.

" + default: '

Returns average block rewards for blocks in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: ' + miningTimeIntervals + '.

For 24h and 3d time periods, every block is included and block rewards are exact (not averages). For the 1w time period, block rewards may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, block rewards are averages.

' }, - urlString: "/v1/mining/blocks/rewards/:timePeriod", + urlString: '/v1/mining/blocks/rewards/:timePeriod', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -6812,15 +6812,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-block-feerates", - title: "GET Block Feerates", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-block-feerates', + title: 'GET Block Feerates', description: { - default: "Returns average feerate percentiles for blocks in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: " + miningTimeIntervals + ".

For 24h and 3d time periods, every block is included and percentiles are exact (not averages). For the 1w time period, percentiles may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, percentiles are averages." + default: 'Returns average feerate percentiles for blocks in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: ' + miningTimeIntervals + '.

For 24h and 3d time periods, every block is included and percentiles are exact (not averages). For the 1w time period, percentiles may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, percentiles are averages.' }, - urlString: "/v1/mining/blocks/fee-rates/:timePeriod", + urlString: '/v1/mining/blocks/fee-rates/:timePeriod', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -6938,15 +6938,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-sizes-weights", - title: "GET Block Sizes and Weights", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-sizes-weights', + title: 'GET Block Sizes and Weights', description: { - default: "

Returns average size (bytes) and average weight (weight units) for blocks in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: " + miningTimeIntervals + ".

For 24h and 3d time periods, every block is included and figures are exact (not averages). For the 1w time period, figures may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, figures are averages.

" + default: '

Returns average size (bytes) and average weight (weight units) for blocks in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: ' + miningTimeIntervals + '.

For 24h and 3d time periods, every block is included and figures are exact (not averages). For the 1w time period, figures may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, figures are averages.

' }, - urlString: "/v1/mining/blocks/sizes-weights/:timePeriod", + urlString: '/v1/mining/blocks/sizes-weights/:timePeriod', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -7081,15 +7081,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-block-predictions", - title: "GET Block Predictions", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-block-predictions', + title: 'GET Block Predictions', description: { - default: "

Returns average block health in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: " + miningTimeIntervals + ".

For 24h and 3d time periods, every block is included and figures are exact (not averages). For the 1w time period, figures may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, figures are averages.

" + default: '

Returns average block health in the specified :timePeriod, ordered oldest to newest. :timePeriod can be any of the following: ' + miningTimeIntervals + '.

For 24h and 3d time periods, every block is included and figures are exact (not averages). For the 1w time period, figures may be averages depending on how fast blocks were found around a particular timestamp. For other time periods, figures are averages.

' }, - urlString: ["/v1/mining/blocks/predictions/:timePeriod"], + urlString: ['/v1/mining/blocks/predictions/:timePeriod'], showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -7189,15 +7189,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-block-audit-score", - title: "GET Block Audit Score", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-block-audit-score', + title: 'GET Block Audit Score', description: { - default: "Returns the block audit score for the specified :blockHash. Available fields: hash, matchRate, expectedFees, and expectedWeight." + default: 'Returns the block audit score for the specified :blockHash. Available fields: hash, matchRate, expectedFees, and expectedWeight.' }, - urlString: ["/v1/mining/blocks/audit/score/:blockHash"], + urlString: ['/v1/mining/blocks/audit/score/:blockHash'], showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -7246,15 +7246,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-blocks-audit-scores", - title: "GET Blocks Audit Scores", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-blocks-audit-scores', + title: 'GET Blocks Audit Scores', description: { - default: "Returns blocks audit score for the past 16 blocks. If :startHeight is specified, the past 15 blocks before (and including) :startHeight are returned. Available fields: hash, matchRate, expectedFees, and expectedWeight." + default: 'Returns blocks audit score for the past 16 blocks. If :startHeight is specified, the past 15 blocks before (and including) :startHeight are returned. Available fields: hash, matchRate, expectedFees, and expectedWeight.' }, - urlString: ["/v1/mining/blocks/audit/scores/:startHeight"], + urlString: ['/v1/mining/blocks/audit/scores/:startHeight'], showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -7330,15 +7330,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mining", - httpRequestMethod: "GET", - fragment: "get-block-audit-summary", - title: "GET Block Audit Summary", + type: 'endpoint', + category: 'mining', + httpRequestMethod: 'GET', + fragment: 'get-block-audit-summary', + title: 'GET Block Audit Summary', description: { - default: "Returns the block audit summary for the specified :blockHash. Available fields: height, id, timestamp, template, missingTxs, addedTxs, freshTxs, sigopTxs, fullrbfTxs, acceleratedTxs, matchRate, expectedFees, and expectedWeight." + default: 'Returns the block audit summary for the specified :blockHash. Available fields: height, id, timestamp, template, missingTxs, addedTxs, freshTxs, sigopTxs, fullrbfTxs, acceleratedTxs, matchRate, expectedFees, and expectedWeight.' }, - urlString: ["/v1/block/:blockHash/audit-summary"], + urlString: ['/v1/block/:blockHash/audit-summary'], showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -7478,22 +7478,22 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "fees", - fragment: "fees", - title: "Fees", + type: 'category', + category: 'fees', + fragment: 'fees', + title: 'Fees', showConditions: bitcoinNetworks.concat(liquidNetworks) }, { - type: "endpoint", - category: "fees", - httpRequestMethod: "GET", - fragment: "get-mempool-blocks-fees", - title: "GET Mempool Blocks Fees", + type: 'endpoint', + category: 'fees', + httpRequestMethod: 'GET', + fragment: 'get-mempool-blocks-fees', + title: 'GET Mempool Blocks Fees', description: { - default: "Returns current mempool as projected blocks." + default: 'Returns current mempool as projected blocks.' }, - urlString: "/v1/fees/mempool-blocks", + urlString: '/v1/fees/mempool-blocks', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -7638,15 +7638,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "fees", - httpRequestMethod: "GET", - fragment: "get-recommended-fees", - title: "GET Recommended Fees", + type: 'endpoint', + category: 'fees', + httpRequestMethod: 'GET', + fragment: 'get-recommended-fees', + title: 'GET Recommended Fees', description: { - default: "Returns our currently suggested fees for new transactions." + default: 'Returns our currently suggested fees for new transactions.' }, - urlString: "/v1/fees/recommended", + urlString: '/v1/fees/recommended', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -7731,15 +7731,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "fees", - httpRequestMethod: "GET", - fragment: "get-recommended-fees-precise", - title: "GET Recommended Fees (Precise)", + type: 'endpoint', + category: 'fees', + httpRequestMethod: 'GET', + fragment: 'get-recommended-fees-precise', + title: 'GET Recommended Fees (Precise)', description: { - default: "Returns our currently-suggested feerates with up to 3 decimal places, including sub-sat feerates down to 0.1 s/vb." + default: 'Returns our currently-suggested feerates with up to 3 decimal places, including sub-sat feerates down to 0.1 s/vb.' }, - urlString: "/v1/fees/precise", + urlString: '/v1/fees/precise', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -7813,22 +7813,22 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "mempool", - fragment: "mempool", - title: "Mempool", + type: 'category', + category: 'mempool', + fragment: 'mempool', + title: 'Mempool', showConditions: bitcoinNetworks.concat(liquidNetworks) }, { - type: "endpoint", - category: "mempool", - httpRequestMethod: "GET", - fragment: "get-mempool", - title: "GET Mempool", + type: 'endpoint', + category: 'mempool', + httpRequestMethod: 'GET', + fragment: 'get-mempool', + title: 'GET Mempool', description: { - default: "Returns current mempool backlog statistics." + default: 'Returns current mempool backlog statistics.' }, - urlString: "/mempool", + urlString: '/mempool', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -7923,15 +7923,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mempool", - httpRequestMethod: "GET", - fragment: "get-mempool-transaction-ids", - title: "GET Mempool Transaction IDs", + type: 'endpoint', + category: 'mempool', + httpRequestMethod: 'GET', + fragment: 'get-mempool-transaction-ids', + title: 'GET Mempool Transaction IDs', description: { - default: "Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind." + default: 'Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind.' }, - urlString: "/mempool/txids", + urlString: '/mempool/txids', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -8009,15 +8009,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mempool", - httpRequestMethod: "GET", - fragment: "get-mempool-recent", - title: "GET Mempool Recent", + type: 'endpoint', + category: 'mempool', + httpRequestMethod: 'GET', + fragment: 'get-mempool-recent', + title: 'GET Mempool Recent', description: { - default: "Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: txid, fee, vsize, and value." + default: 'Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: txid, fee, vsize, and value.' }, - urlString: "/mempool/recent", + urlString: '/mempool/recent', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -8115,15 +8115,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mempool", - httpRequestMethod: "GET", - fragment: "get-mempool-rbf", - title: "GET Mempool RBF Transactions", + type: 'endpoint', + category: 'mempool', + httpRequestMethod: 'GET', + fragment: 'get-mempool-rbf', + title: 'GET Mempool RBF Transactions', description: { - default: "Returns the list of mempool transactions that are part of a RBF chain." + default: 'Returns the list of mempool transactions that are part of a RBF chain.' }, - urlString: "/v1/replacements", + urlString: '/v1/replacements', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -8245,15 +8245,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "mempool", - httpRequestMethod: "GET", - fragment: "get-mempool-fullrbf", - title: "GET Mempool Full RBF Transactions", + type: 'endpoint', + category: 'mempool', + httpRequestMethod: 'GET', + fragment: 'get-mempool-fullrbf', + title: 'GET Mempool Full RBF Transactions', description: { - default: "Returns the list of mempool transactions that are part of a Full-RBF chain." + default: 'Returns the list of mempool transactions that are part of a Full-RBF chain.' }, - urlString: "/v1/fullrbf/replacements", + urlString: '/v1/fullrbf/replacements', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -8374,22 +8374,22 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "transactions", - fragment: "transactions", - title: "Transactions", + type: 'category', + category: 'transactions', + fragment: 'transactions', + title: 'Transactions', showConditions: bitcoinNetworks.concat(liquidNetworks) }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-cpfp", - title: "GET Children Pay for Parent", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-cpfp', + title: 'GET Children Pay for Parent', description: { - default: "Returns the ancestors and the best descendant fees for a transaction." + default: 'Returns the ancestors and the best descendant fees for a transaction.' }, - urlString: "/v1/cpfp", + urlString: '/v1/cpfp', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -8446,15 +8446,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction", - title: "GET Transaction", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction', + title: 'GET Transaction', description: { - default: "Returns details about a transaction. Available fields: txid, version, locktime, size, weight, fee, vin, vout, and status." + default: 'Returns details about a transaction. Available fields: txid, version, locktime, size, weight, fee, vin, vout, and status.' }, - urlString: "/tx/:txid", + urlString: '/tx/:txid', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -8586,15 +8586,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction-hex", - title: "GET Transaction Hex", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction-hex', + title: 'GET Transaction Hex', description: { - default: "Returns a transaction serialized as hex." + default: 'Returns a transaction serialized as hex.' }, - urlString: "/tx/:txid/hex", + urlString: '/tx/:txid/hex', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -8651,15 +8651,15 @@ export const restApiDocsData = [ }, }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction-merkleblock-proof", - title: "GET Transaction Merkleblock Proof", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction-merkleblock-proof', + title: 'GET Transaction Merkleblock Proof', description: { - default: "Returns a merkle inclusion proof for the transaction using bitcoind's merkleblock format." + default: 'Returns a merkle inclusion proof for the transaction using bitcoind\'s merkleblock format.' }, - urlString: "/tx/:txid/merkleblock-proof", + urlString: '/tx/:txid/merkleblock-proof', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefault, codeExample: { @@ -8706,15 +8706,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction-merkle-proof", - title: "GET Transaction Merkle Proof", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction-merkle-proof', + title: 'GET Transaction Merkle Proof', description: { - default: "Returns a merkle inclusion proof for the transaction using Electrum's blockchain.transaction.get_merkle format." + default: 'Returns a merkle inclusion proof for the transaction using Electrum\'s blockchain.transaction.get_merkle format.' }, - urlString: "/tx/:txid/merkle-proof", + urlString: '/tx/:txid/merkle-proof', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -8823,15 +8823,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction-outspend", - title: "GET Transaction Outspend", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction-outspend', + title: 'GET Transaction Outspend', description: { - default: "Returns the spending status of a transaction output. Available fields: spent (boolean), txid (optional), vin (optional), and status (optional, the status of the spending tx)." + default: 'Returns the spending status of a transaction output. Available fields: spent (boolean), txid (optional), vin (optional), and status (optional, the status of the spending tx).' }, - urlString: "/tx/:txid/outspend/:vout", + urlString: '/tx/:txid/outspend/:vout', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -8944,15 +8944,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction-outspends", - title: "GET Transaction Outspends", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction-outspends', + title: 'GET Transaction Outspends', description: { - default: "Returns the spending status of all transaction outputs." + default: 'Returns the spending status of all transaction outputs.' }, - urlString: "/tx/:txid/outspends", + urlString: '/tx/:txid/outspends', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -9080,15 +9080,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction-raw", - title: "GET Transaction Raw", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction-raw', + title: 'GET Transaction Raw', description: { - default: "Returns a transaction as binary data." + default: 'Returns a transaction as binary data.' }, - urlString: "/tx/:txid/raw", + urlString: '/tx/:txid/raw', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -9145,15 +9145,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction-rbf-timeline", - title: "GET Transaction RBF Timeline", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction-rbf-timeline', + title: 'GET Transaction RBF Timeline', description: { - default: "Returns the RBF tree timeline of a transaction." + default: 'Returns the RBF tree timeline of a transaction.' }, - urlString: "v1/tx/:txId/rbf", + urlString: 'v1/tx/:txId/rbf', showConditions: bitcoinNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -9286,15 +9286,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction-status", - title: "GET Transaction Status", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction-status', + title: 'GET Transaction Status', description: { - default: "Returns the confirmation status of a transaction. Available fields: confirmed (boolean), block_height (optional), and block_hash (optional)." + default: 'Returns the confirmation status of a transaction. Available fields: confirmed (boolean), block_height (optional), and block_hash (optional).' }, - urlString: "/tx/:txid/status", + urlString: '/tx/:txid/status', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -9373,15 +9373,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "GET", - fragment: "get-transaction-times", - title: "GET Transaction Times", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'GET', + fragment: 'get-transaction-times', + title: 'GET Transaction Times', description: { - default: "Returns the timestamps when a list of unconfirmed transactions was initially observed in the mempool. If a transaction is not found in the mempool or has been mined, the timestamp will be 0." + default: 'Returns the timestamps when a list of unconfirmed transactions was initially observed in the mempool. If a transaction is not found in the mempool or has been mined, the timestamp will be 0.' }, - urlString: "/v1/transaction-times", + urlString: '/v1/transaction-times', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -9415,15 +9415,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "transactions", - httpRequestMethod: "POST", - fragment: "post-transaction", - title: "POST Transaction", + type: 'endpoint', + category: 'transactions', + httpRequestMethod: 'POST', + fragment: 'post-transaction', + title: 'POST Transaction', description: { - default: "Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The txid will be returned on success." + default: 'Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The txid will be returned on success.' }, - urlString: "/api/tx", + urlString: '/api/tx', showConditions: bitcoinNetworks.concat(liquidNetworks), showJsExamples: showJsExamplesDefault, codeExample: { @@ -9482,22 +9482,22 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "lightning", - fragment: "lightning", - title: "Lightning", + type: 'category', + category: 'lightning', + fragment: 'lightning', + title: 'Lightning', showConditions: lightningNetworks }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-lightning-network-stats", - title: "GET Network Stats", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-lightning-network-stats', + title: 'GET Network Stats', description: { - default: "

Returns network-wide stats such as total number of channels and nodes, total capacity, and average/median fee figures.

Pass one of the following for :interval: latest, 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y.

" + default: '

Returns network-wide stats such as total number of channels and nodes, total capacity, and average/median fee figures.

Pass one of the following for :interval: latest, 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y.

' }, - urlString: "/v1/lightning/statistics/:interval", + urlString: '/v1/lightning/statistics/:interval', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -9585,15 +9585,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-lightning-nodes-channels", - title: "GET Nodes/Channels", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-lightning-nodes-channels', + title: 'GET Nodes/Channels', description: { - default: "

Returns Lightning nodes and channels that match a full-text, case-insensitive search :query across node aliases, node pubkeys, channel IDs, and short channel IDs.

" + default: '

Returns Lightning nodes and channels that match a full-text, case-insensitive search :query across node aliases, node pubkeys, channel IDs, and short channel IDs.

' }, - urlString: "/v1/lightning/search?searchText=:query", + urlString: '/v1/lightning/search?searchText=:query', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -9670,15 +9670,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-lightning-nodes-country", - title: "GET Nodes in Country", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-lightning-nodes-country', + title: 'GET Nodes in Country', description: { - default: "

Returns a list of Lightning nodes running on clearnet in the requested :country, where :country is an ISO Alpha-2 country code.

" + default: '

Returns a list of Lightning nodes running on clearnet in the requested :country, where :country is an ISO Alpha-2 country code.

' }, - urlString: "/v1/lightning/nodes/country/:country", + urlString: '/v1/lightning/nodes/country/:country', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -9892,15 +9892,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-country-node-stats", - title: "GET Node Stats Per Country", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-country-node-stats', + title: 'GET Node Stats Per Country', description: { - default: "

Returns aggregate capacity and number of clearnet nodes per country. Capacity figures are in satoshis.

" + default: '

Returns aggregate capacity and number of clearnet nodes per country. Capacity figures are in satoshis.

' }, - urlString: "/v1/lightning/nodes/countries", + urlString: '/v1/lightning/nodes/countries', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -10036,15 +10036,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-isp-nodes", - title: "GET ISP Nodes", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-isp-nodes', + title: 'GET ISP Nodes', description: { - default: "

Returns a list of nodes hosted by a specified :isp, where :isp is an ISP's ASN.

" + default: '

Returns a list of nodes hosted by a specified :isp, where :isp is an ISP\'s ASN.

' }, - urlString: "/v1/lightning/nodes/isp/:isp", + urlString: '/v1/lightning/nodes/isp/:isp', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -10155,15 +10155,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-isp-node-stats", - title: "GET Node Stats Per ISP", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-isp-node-stats', + title: 'GET Node Stats Per ISP', description: { - default: "

Returns aggregate capacity, number of nodes, and number of channels per ISP. Capacity figures are in satoshis.

" + default: '

Returns aggregate capacity, number of nodes, and number of channels per ISP. Capacity figures are in satoshis.

' }, - urlString: "/v1/lightning/nodes/isp-ranking", + urlString: '/v1/lightning/nodes/isp-ranking', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -10267,15 +10267,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-top-100-nodes", - title: "GET Top 100 Nodes", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-top-100-nodes', + title: 'GET Top 100 Nodes', description: { - default: "

Returns two lists of the top 100 nodes: one ordered by liquidity (aggregate channel capacity) and the other ordered by connectivity (number of open channels).

" + default: '

Returns two lists of the top 100 nodes: one ordered by liquidity (aggregate channel capacity) and the other ordered by connectivity (number of open channels).

' }, - urlString: "/v1/lightning/nodes/rankings", + urlString: '/v1/lightning/nodes/rankings', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -10390,15 +10390,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-top-100-nodes-liquidity", - title: "GET Top 100 Nodes by Liquidity", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-top-100-nodes-liquidity', + title: 'GET Top 100 Nodes by Liquidity', description: { - default: "

Returns a list of the top 100 nodes by liquidity (aggregate channel capacity).

" + default: '

Returns a list of the top 100 nodes by liquidity (aggregate channel capacity).

' }, - urlString: "/v1/lightning/nodes/rankings/liquidity", + urlString: '/v1/lightning/nodes/rankings/liquidity', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -10587,15 +10587,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-top-100-nodes-connectivity", - title: "GET Top 100 Nodes by Connectivity", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-top-100-nodes-connectivity', + title: 'GET Top 100 Nodes by Connectivity', description: { - default: "

Returns a list of the top 100 nodes by connectivity (number of open channels).

" + default: '

Returns a list of the top 100 nodes by connectivity (number of open channels).

' }, - urlString: "/v1/lightning/nodes/rankings/connectivity", + urlString: '/v1/lightning/nodes/rankings/connectivity', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -10783,15 +10783,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-top-100-oldest-nodes", - title: "GET Top 100 Oldest Nodes", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-top-100-oldest-nodes', + title: 'GET Top 100 Oldest Nodes', description: { - default: "

Returns a list of the top 100 oldest nodes.

" + default: '

Returns a list of the top 100 oldest nodes.

' }, - urlString: "/v1/lightning/nodes/rankings/age", + urlString: '/v1/lightning/nodes/rankings/age', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -10970,15 +10970,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-node-stats", - title: "GET Node Stats", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-node-stats', + title: 'GET Node Stats', description: { - default: "

Returns details about a node with the given :pubKey.

" + default: '

Returns details about a node with the given :pubKey.

' }, - urlString: "/v1/lightning/nodes/:pubKey", + urlString: '/v1/lightning/nodes/:pubKey', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -11134,15 +11134,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-historical-node-stats", - title: "GET Historical Node Stats", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-historical-node-stats', + title: 'GET Historical Node Stats', description: { - default: "

Returns historical stats for a node with the given :pubKey.

" + default: '

Returns historical stats for a node with the given :pubKey.

' }, - urlString: "/v1/lightning/nodes/:pubKey/statistics", + urlString: '/v1/lightning/nodes/:pubKey/statistics', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -11232,15 +11232,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-channel", - title: "GET Channel", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-channel', + title: 'GET Channel', description: { - default: "

Returns info about a Lightning channel with the given :channelId.

" + default: '

Returns info about a Lightning channel with the given :channelId.

' }, - urlString: "/v1/lightning/channels/:channelId", + urlString: '/v1/lightning/channels/:channelId', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -11397,15 +11397,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-channels-from-txid", - title: "GET Channels from TXID", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-channels-from-txid', + title: 'GET Channels from TXID', description: { - default: "

Returns channels that correspond to the given :txid (multiple transaction IDs can be specified).

" + default: '

Returns channels that correspond to the given :txid (multiple transaction IDs can be specified).

' }, - urlString: "/v1/lightning/channels/txids?txId[]=:txid", + urlString: '/v1/lightning/channels/txids?txId[]=:txid', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -11598,15 +11598,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-channels-from-pubkey", - title: "GET Channels from Node Pubkey", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-channels-from-pubkey', + title: 'GET Channels from Node Pubkey', description: { - default: "

Returns a list of a node's channels given its :pubKey. Ten channels are returned at a time. Use :index for paging. :channelStatus can be open, active, or closed.

" + default: '

Returns a list of a node\'s channels given its :pubKey. Ten channels are returned at a time. Use :index for paging. :channelStatus can be open, active, or closed.

' }, - urlString: "/v1/lightning/channels?public_key=:pubKey&status=:channelStatus", + urlString: '/v1/lightning/channels?public_key=:pubKey&status=:channelStatus', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -11734,15 +11734,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-channel-geodata", - title: "GET Channel Geodata", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-channel-geodata', + title: 'GET Channel Geodata', description: { - default: "

Returns a list of channels with corresponding node geodata.

" + default: '

Returns a list of channels with corresponding node geodata.

' }, - urlString: "/v1/lightning/channels-geo", + urlString: '/v1/lightning/channels-geo', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -11842,15 +11842,15 @@ export const restApiDocsData = [ } }, { - type: "endpoint", - category: "lightning", - httpRequestMethod: "GET", - fragment: "get-channel-geodata-node", - title: "GET Channel Geodata for Node", + type: 'endpoint', + category: 'lightning', + httpRequestMethod: 'GET', + fragment: 'get-channel-geodata-node', + title: 'GET Channel Geodata for Node', description: { - default: "

Returns a list of channels with corresponding geodata for a node with the given :pubKey.

" + default: '

Returns a list of channels with corresponding geodata for a node with the given :pubKey.

' }, - urlString: "/v1/lightning/channels-geo/:pubKey", + urlString: '/v1/lightning/channels-geo/:pubKey', showConditions: lightningNetworks, showJsExamples: showJsExamplesDefaultFalse, codeExample: { @@ -11950,25 +11950,25 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "accelerator-public", - fragment: "accelerator-public", - title: "Accelerator (Public)", - showConditions: [""], + type: 'category', + category: 'accelerator-public', + fragment: 'accelerator-public', + title: 'Accelerator (Public)', + showConditions: [''], options: { officialOnly: true }, }, { options: { officialOnly: true }, - type: "endpoint", - category: "accelerator-public", - httpRequestMethod: "POST", - fragment: "accelerator-estimate", - title: "POST Calculate Estimated Costs", + type: 'endpoint', + category: 'accelerator-public', + httpRequestMethod: 'POST', + fragment: 'accelerator-estimate', + title: 'POST Calculate Estimated Costs', description: { - default: "

Returns estimated costs to accelerate a transaction. Optionally set the X-Mempool-Auth header to get customized estimation.

" + default: '

Returns estimated costs to accelerate a transaction. Optionally set the X-Mempool-Auth header to get customized estimation.

' }, - urlString: "/v1/services/accelerator/estimate", - showConditions: [""], + urlString: '/v1/services/accelerator/estimate', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -11980,8 +11980,8 @@ export const restApiDocsData = [ codeSampleMainnet: { esModule: [], commonJS: [], - curl: ["txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29"], - headers: "X-Mempool-Auth: stacksats", + curl: ['txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29'], + headers: 'X-Mempool-Auth: stacksats', response: `{ "txSummary": { "txid": "ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29", @@ -12034,16 +12034,16 @@ export const restApiDocsData = [ }, { options: { officialOnly: true }, - type: "endpoint", - category: "accelerator-public", - httpRequestMethod: "POST", - fragment: "accelerator-get-invoice", - title: "POST Generate Acceleration Invoice", + type: 'endpoint', + category: 'accelerator-public', + httpRequestMethod: 'POST', + fragment: 'accelerator-get-invoice', + title: 'POST Generate Acceleration Invoice', description: { - default: "

Request a LN invoice to accelerate a transaction.

" + default: '

Request a LN invoice to accelerate a transaction.

' }, - urlString: "/v1/services/payments/bitcoin", - showConditions: [""], + urlString: '/v1/services/payments/bitcoin', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -12055,8 +12055,8 @@ export const restApiDocsData = [ codeSampleMainnet: { esModule: [], commonJS: [], - curl: ["product=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29&amount=12500"], - headers: "", + curl: ['product=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29&amount=12500'], + headers: '', response: `[ { "btcpayInvoiceId": "4Ww53d7VgSa596jmCFufe7", @@ -12074,16 +12074,16 @@ export const restApiDocsData = [ }, { options: { officialOnly: true }, - type: "endpoint", - category: "accelerator-public", - httpRequestMethod: "GET", - fragment: "accelerator-pending", - title: "GET Pending Accelerations", + type: 'endpoint', + category: 'accelerator-public', + httpRequestMethod: 'GET', + fragment: 'accelerator-pending', + title: 'GET Pending Accelerations', description: { - default: "

Returns all transactions currently being accelerated.

" + default: '

Returns all transactions currently being accelerated.

' }, - urlString: "/v1/services/accelerator/accelerations", - showConditions: [""], + urlString: '/v1/services/accelerator/accelerations', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -12125,11 +12125,11 @@ export const restApiDocsData = [ }, { options: { officialOnly: true }, - type: "endpoint", - category: "accelerator-public", - httpRequestMethod: "GET", - fragment: "accelerator-public-history", - title: "GET Acceleration History", + type: 'endpoint', + category: 'accelerator-public', + httpRequestMethod: 'GET', + fragment: 'accelerator-public-history', + title: 'GET Acceleration History', description: { default: `

Returns all past accelerated transactions. Filters can be applied:

` }, - urlString: "/v1/services/accelerator/accelerations/history", - showConditions: [""], + urlString: '/v1/services/accelerator/accelerations/history', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -12184,25 +12184,25 @@ export const restApiDocsData = [ } }, { - type: "category", - category: "accelerator-private", - fragment: "accelerator-private", - title: "Accelerator (Authenticated)", - showConditions: [""], + type: 'category', + category: 'accelerator-private', + fragment: 'accelerator-private', + title: 'Accelerator (Authenticated)', + showConditions: [''], options: { officialOnly: true }, }, { options: { officialOnly: true }, - type: "endpoint", - category: "accelerator-private", - httpRequestMethod: "GET", - fragment: "accelerator-top-up-history", - title: "GET Top Up History", + type: 'endpoint', + category: 'accelerator-private', + httpRequestMethod: 'GET', + fragment: 'accelerator-top-up-history', + title: 'GET Top Up History', description: { - default: "

Returns a list of top ups the user has made as prepayment for the accelerator service.

" + default: '

Returns a list of top ups the user has made as prepayment for the accelerator service.

' }, - urlString: "/v1/services/accelerator/top-up-history", - showConditions: [""], + urlString: '/v1/services/accelerator/top-up-history', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -12215,7 +12215,7 @@ export const restApiDocsData = [ esModule: [], commonJS: [], curl: [], - headers: "X-Mempool-Auth: stacksats", + headers: 'X-Mempool-Auth: stacksats', response: `[ { "type": "Bitcoin", @@ -12241,16 +12241,16 @@ export const restApiDocsData = [ }, { options: { officialOnly: true }, - type: "endpoint", - category: "accelerator-private", - httpRequestMethod: "GET", - fragment: "accelerator-balance", - title: "GET Available Balance", + type: 'endpoint', + category: 'accelerator-private', + httpRequestMethod: 'GET', + fragment: 'accelerator-balance', + title: 'GET Available Balance', description: { - default: "

Returns the user's currently available balance, currently locked funds, and total fees paid so far.

" + default: '

Returns the user\'s currently available balance, currently locked funds, and total fees paid so far.

' }, - urlString: "/v1/services/accelerator/balance", - showConditions: [""], + urlString: '/v1/services/accelerator/balance', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -12263,7 +12263,7 @@ export const restApiDocsData = [ esModule: [], commonJS: [], curl: [], - headers: "X-Mempool-Auth: stacksats", + headers: 'X-Mempool-Auth: stacksats', response: `{ "balance": 99900000, "hold": 101829, @@ -12275,16 +12275,16 @@ export const restApiDocsData = [ }, { options: { officialOnly: true }, - type: "endpoint", - category: "accelerator-private", - httpRequestMethod: "POST", - fragment: "accelerator-accelerate", - title: "POST Accelerate A Transaction (Pro)", + type: 'endpoint', + category: 'accelerator-private', + httpRequestMethod: 'POST', + fragment: 'accelerator-accelerate', + title: 'POST Accelerate A Transaction (Pro)', description: { - default: "

Sends a request to accelerate a transaction.

" + default: '

Sends a request to accelerate a transaction.

' }, - urlString: "/v1/services/accelerator/accelerate", - showConditions: [""], + urlString: '/v1/services/accelerator/accelerate', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -12296,8 +12296,8 @@ export const restApiDocsData = [ codeSampleMainnet: { esModule: [], commonJS: [], - curl: ["txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29&userBid=21000000"], - headers: "X-Mempool-Auth: stacksats", + curl: ['txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29&userBid=21000000'], + headers: 'X-Mempool-Auth: stacksats', response: `HTTP/1.1 200 OK`, }, } @@ -12305,16 +12305,16 @@ export const restApiDocsData = [ }, { options: { officialOnly: true }, - type: "endpoint", - category: "accelerator-private", - httpRequestMethod: "GET", - fragment: "accelerator-history", - title: "GET Acceleration History", + type: 'endpoint', + category: 'accelerator-private', + httpRequestMethod: 'GET', + fragment: 'accelerator-history', + title: 'GET Acceleration History', description: { - default: "

Returns the user's past acceleration requests.

Pass one of the following for :status (required): all, requested, accelerating, mined, completed, failed.
Pass true in :details to get a detailed history of the acceleration request.

" + default: '

Returns the user\'s past acceleration requests.

Pass one of the following for :status (required): all, requested, accelerating, mined, completed, failed.
Pass true in :details to get a detailed history of the acceleration request.

' }, - urlString: "/v1/services/accelerator/history?status=:status&details=:details", - showConditions: [""], + urlString: '/v1/services/accelerator/history?status=:status&details=:details', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -12327,7 +12327,7 @@ export const restApiDocsData = [ esModule: [], commonJS: [], curl: [], - headers: "X-Mempool-Auth: stacksats", + headers: 'X-Mempool-Auth: stacksats', response: `[ { "id": 89, @@ -12423,16 +12423,16 @@ export const restApiDocsData = [ }, { options: { officialOnly: true }, - type: "endpoint", - category: "accelerator-private", - httpRequestMethod: "POST", - fragment: "accelerator-cancel", - title: "POST Cancel Acceleration (Pro)", + type: 'endpoint', + category: 'accelerator-private', + httpRequestMethod: 'POST', + fragment: 'accelerator-cancel', + title: 'POST Cancel Acceleration (Pro)', description: { - default: "

Sends a request to cancel an acceleration in the accelerating status.
You can retrieve eligible acceleration id using the history endpoint GET /api/v1/services/accelerator/history?status=accelerating." + default: '

Sends a request to cancel an acceleration in the accelerating status.
You can retrieve eligible acceleration id using the history endpoint GET /api/v1/services/accelerator/history?status=accelerating.' }, - urlString: "/v1/services/accelerator/cancel", - showConditions: [""], + urlString: '/v1/services/accelerator/cancel', + showConditions: [''], showJsExamples: showJsExamplesDefaultFalse, codeExample: { default: { @@ -12444,8 +12444,8 @@ export const restApiDocsData = [ codeSampleMainnet: { esModule: [], commonJS: [], - curl: ["id=42"], - headers: "X-Mempool-Auth: stacksats", + curl: ['id=42'], + headers: 'X-Mempool-Auth: stacksats', response: `HTTP/1.1 200 OK`, }, } @@ -12455,272 +12455,272 @@ export const restApiDocsData = [ export const faqData = [ { - type: "category", - category: "basics", - fragment: "basics", - title: "Basics", + type: 'category', + category: 'basics', + fragment: 'basics', + title: 'Basics', showConditions: bitcoinNetworks }, { - type: "endpoint", - category: "basics", + type: 'endpoint', + category: 'basics', showConditions: bitcoinNetworks, - fragment: "what-is-a-mempool", - title: "What is a mempool?", + fragment: 'what-is-a-mempool', + title: 'What is a mempool?', }, { - type: "endpoint", - category: "basics", + type: 'endpoint', + category: 'basics', showConditions: bitcoinNetworks, - fragment: "what-is-a-mempool-explorer", - title: "What is a mempool explorer?", + fragment: 'what-is-a-mempool-explorer', + title: 'What is a mempool explorer?', }, { - type: "endpoint", - category: "basics", + type: 'endpoint', + category: 'basics', showConditions: bitcoinNetworks, - fragment: "what-is-a-blockchain", - title: "What is a blockchain?", + fragment: 'what-is-a-blockchain', + title: 'What is a blockchain?', }, { - type: "endpoint", - category: "basics", + type: 'endpoint', + category: 'basics', showConditions: bitcoinNetworks, - fragment: "what-is-a-block-explorer", - title: "What is a block explorer?", + fragment: 'what-is-a-block-explorer', + title: 'What is a block explorer?', }, { - type: "endpoint", - category: "basics", + type: 'endpoint', + category: 'basics', showConditions: bitcoinNetworks, - fragment: "what-is-mining", - title: "What is mining?", + fragment: 'what-is-mining', + title: 'What is mining?', }, { - type: "endpoint", - category: "basics", + type: 'endpoint', + category: 'basics', showConditions: bitcoinNetworks, - fragment: "what-are-mining-pools", - title: "What are mining pools?", + fragment: 'what-are-mining-pools', + title: 'What are mining pools?', }, { - type: "endpoint", - category: "basics", + type: 'endpoint', + category: 'basics', showConditions: bitcoinNetworks, - fragment: "what-are-vb-wu", - title: "What are virtual bytes (vB) and weight units (WU)?", + fragment: 'what-are-vb-wu', + title: 'What are virtual bytes (vB) and weight units (WU)?', }, { - type: "endpoint", - category: "basics", + type: 'endpoint', + category: 'basics', showConditions: bitcoinNetworks, - fragment: "what-is-svb", - title: "What is sat/vB?", + fragment: 'what-is-svb', + title: 'What is sat/vB?', }, { - type: "category", - category: "help", - fragment: "help-stuck-transaction", - title: "Help! My transaction is stuck", + type: 'category', + category: 'help', + fragment: 'help-stuck-transaction', + title: 'Help! My transaction is stuck', showConditions: bitcoinNetworks }, { - type: "endpoint", - category: "help", + type: 'endpoint', + category: 'help', showConditions: bitcoinNetworks, - fragment: "why-is-transaction-stuck-in-mempool", - title: "Why isn't my transaction confirming?", + fragment: 'why-is-transaction-stuck-in-mempool', + title: 'Why isn\'t my transaction confirming?', }, { - type: "endpoint", - category: "help", + type: 'endpoint', + category: 'help', showConditions: bitcoinNetworks, - fragment: "how-to-get-transaction-confirmed-quickly", - title: "How can I get my transaction confirmed more quickly?", + fragment: 'how-to-get-transaction-confirmed-quickly', + title: 'How can I get my transaction confirmed more quickly?', }, { - type: "endpoint", - category: "help", + type: 'endpoint', + category: 'help', showConditions: bitcoinNetworks, - fragment: "how-prevent-stuck-transaction", - title: "How can I prevent a transaction from getting stuck in the future?", + fragment: 'how-prevent-stuck-transaction', + title: 'How can I prevent a transaction from getting stuck in the future?', }, { - type: "category", - category: "using", - fragment: "using-this-website", - title: "Using this website", + type: 'category', + category: 'using', + fragment: 'using-this-website', + title: 'Using this website', showConditions: bitcoinNetworks }, { - type: "endpoint", - category: "how-to", + type: 'endpoint', + category: 'how-to', showConditions: bitcoinNetworks, - fragment: "looking-up-transactions", - title: "How can I look up a transaction?", + fragment: 'looking-up-transactions', + title: 'How can I look up a transaction?', }, { - type: "endpoint", - category: "how-to", + type: 'endpoint', + category: 'how-to', showConditions: bitcoinNetworks, - fragment: "looking-up-addresses", - title: "How can I look up an address?", + fragment: 'looking-up-addresses', + title: 'How can I look up an address?', }, { - type: "endpoint", - category: "how-to", + type: 'endpoint', + category: 'how-to', showConditions: bitcoinNetworks, - fragment: "looking-up-blocks", - title: "How can I look up a block?", + fragment: 'looking-up-blocks', + title: 'How can I look up a block?', }, { - type: "endpoint", - category: "how-to", + type: 'endpoint', + category: 'how-to', showConditions: bitcoinNetworks, - fragment: "looking-up-fee-estimates", - title: "How can I look up fee estimates?", + fragment: 'looking-up-fee-estimates', + title: 'How can I look up fee estimates?', }, { - type: "endpoint", - category: "how-to", + type: 'endpoint', + category: 'how-to', showConditions: bitcoinNetworks, - fragment: "looking-up-historical-trends", - title: "How can I explore historical trends?", + fragment: 'looking-up-historical-trends', + title: 'How can I explore historical trends?', }, { - type: "category", - category: "advanced", - fragment: "advanced", - title: "Advanced", + type: 'category', + category: 'advanced', + fragment: 'advanced', + title: 'Advanced', showConditions: bitcoinNetworks }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "what-is-full-mempool", - title: "What does it mean for the mempool to be \"full\"?", + fragment: 'what-is-full-mempool', + title: 'What does it mean for the mempool to be "full"?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "how-big-is-mempool-used-by-mempool-space", - title: "How big is the mempool used by mempool.space?", + fragment: 'how-big-is-mempool-used-by-mempool-space', + title: 'How big is the mempool used by mempool.space?', options: { officialOnly: true }, }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "what-is-memory-usage", - title: "What is memory usage?", + fragment: 'what-is-memory-usage', + title: 'What is memory usage?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "why-empty-blocks", - title: "Why are there empty blocks?", + fragment: 'why-empty-blocks', + title: 'Why are there empty blocks?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "why-block-timestamps-dont-always-increase", - title: "Why don't block timestamps always increase?", + fragment: 'why-block-timestamps-dont-always-increase', + title: 'Why don\'t block timestamps always increase?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "why-dont-fee-ranges-match", - title: "Why doesn't the fee range shown for a block match the feerates of transactions within the block?", + fragment: 'why-dont-fee-ranges-match', + title: 'Why doesn\'t the fee range shown for a block match the feerates of transactions within the block?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, options: { auditOnly: true }, - fragment: "how-do-block-audits-work", - title: "How do block audits work?", + fragment: 'how-do-block-audits-work', + title: 'How do block audits work?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, options: { auditOnly: true }, - fragment: "what-is-block-health", - title: "What is block health?", + fragment: 'what-is-block-health', + title: 'What is block health?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "how-do-mempool-goggles-work", - title: "How do Mempool Goggles™ work?", + fragment: 'how-do-mempool-goggles-work', + title: 'How do Mempool Goggles™ work?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "what-are-sigops", - title: "What are sigops?", + fragment: 'what-are-sigops', + title: 'What are sigops?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "what-is-adjusted-vsize", - title: "What is adjusted vsize?", + fragment: 'what-is-adjusted-vsize', + title: 'What is adjusted vsize?', }, { - type: "endpoint", - category: "advanced", + type: 'endpoint', + category: 'advanced', showConditions: bitcoinNetworks, - fragment: "why-do-the-projected-block-fee-ranges-overlap", - title: "Why do the projected block fee ranges overlap?", + fragment: 'why-do-the-projected-block-fee-ranges-overlap', + title: 'Why do the projected block fee ranges overlap?', }, { - type: "category", - category: "self-hosting", - fragment: "self-hosting", - title: "Self-Hosting", + type: 'category', + category: 'self-hosting', + fragment: 'self-hosting', + title: 'Self-Hosting', showConditions: bitcoinNetworks }, { - type: "endpoint", - category: "self-hosting", + type: 'endpoint', + category: 'self-hosting', showConditions: bitcoinNetworks, - fragment: "who-runs-this-website", - title: "Who runs this website?", + fragment: 'who-runs-this-website', + title: 'Who runs this website?', }, { - type: "endpoint", - category: "self-hosting", + type: 'endpoint', + category: 'self-hosting', showConditions: bitcoinNetworks, - fragment: "host-my-own-instance-raspberry-pi", - title: "How can I host my own instance on a Raspberry Pi?", + fragment: 'host-my-own-instance-raspberry-pi', + title: 'How can I host my own instance on a Raspberry Pi?', }, { - type: "endpoint", - category: "self-hosting", + type: 'endpoint', + category: 'self-hosting', showConditions: bitcoinNetworks, - fragment: "host-my-own-instance-server", - title: "How can I host a Mempool instance on my own server?", + fragment: 'host-my-own-instance-server', + title: 'How can I host a Mempool instance on my own server?', }, { - type: "endpoint", - category: "self-hosting", + type: 'endpoint', + category: 'self-hosting', showConditions: bitcoinNetworks, - fragment: "install-mempool-with-docker", - title: "Can I install Mempool using Docker?", + fragment: 'install-mempool-with-docker', + title: 'Can I install Mempool using Docker?', }, { - type: "endpoint", - category: "self-hosting", + type: 'endpoint', + category: 'self-hosting', showConditions: bitcoinNetworks, - fragment: "address-lookup-issues", - title: "Why do I get an error for certain address lookups on my Mempool instance?", + fragment: 'address-lookup-issues', + title: 'Why do I get an error for certain address lookups on my Mempool instance?', } ]; diff --git a/frontend/src/app/docs/api-docs/api-docs.component.ts b/frontend/src/app/docs/api-docs/api-docs.component.ts index cd084ee4f..3e2bfae8e 100644 --- a/frontend/src/app/docs/api-docs/api-docs.component.ts +++ b/frontend/src/app/docs/api-docs/api-docs.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, Input, QueryList, AfterViewInit, ViewChildren } from import { Env, StateService } from '@app/services/state.service'; import { Observable, merge, of, Subject, Subscription } from 'rxjs'; import { tap, takeUntil } from 'rxjs/operators'; -import { ActivatedRoute } from "@angular/router"; +import { ActivatedRoute } from '@angular/router'; import { faqData, restApiDocsData, wsApiDocsData } from '@app/docs/api-docs/api-docs-data'; import { FaqTemplateDirective } from '@app/docs/faq-template/faq-template.component'; @@ -23,7 +23,7 @@ export class ApiDocsComponent implements OnInit, AfterViewInit { code: any; baseNetworkUrl = ''; @Input() whichTab: string; - desktopDocsNavPosition = "relative"; + desktopDocsNavPosition = 'relative'; faq: any[]; restDocs: any[]; wsDocs: any; @@ -49,7 +49,7 @@ export class ApiDocsComponent implements OnInit, AfterViewInit { if (this.faqTemplates) { this.faqTemplates.forEach((x) => this.dict[x.type] = x.template); } - this.desktopDocsNavPosition = ( window.pageYOffset > 115 ) ? "fixed" : "relative"; + this.desktopDocsNavPosition = ( window.pageYOffset > 115 ) ? 'fixed' : 'relative'; this.mobileViewport = window.innerWidth <= 992; } @@ -59,7 +59,7 @@ export class ApiDocsComponent implements OnInit, AfterViewInit { if( this.route.snapshot.fragment ) { this.openEndpointContainer( this.route.snapshot.fragment ); if (document.getElementById( this.route.snapshot.fragment )) { - let vOffset = ( window.innerWidth <= 992 ) ? 100 : 60; + const vOffset = ( window.innerWidth <= 992 ) ? 100 : 60; window.scrollTo({ top: document.getElementById( this.route.snapshot.fragment ).offsetTop - vOffset }); @@ -102,19 +102,19 @@ export class ApiDocsComponent implements OnInit, AfterViewInit { this.network$.pipe(takeUntil(this.destroy$)).subscribe((network) => { this.active = (network === 'liquid' || network === 'liquidtestnet') ? 2 : 0; switch( network ) { - case "": + case '': this.electrsPort = 50002; break; - case "mainnet": + case 'mainnet': this.electrsPort = 50002; break; - case "testnet": + case 'testnet': this.electrsPort = 60002; break; - case "testnet4": + case 'testnet4': this.electrsPort = 40002; break; - case "signet": + case 'signet': this.electrsPort = 60602; break; - case "liquid": + case 'liquid': this.electrsPort = 51002; break; - case "liquidtestnet": + case 'liquidtestnet': this.electrsPort = 51302; break; } }); @@ -132,39 +132,39 @@ export class ApiDocsComponent implements OnInit, AfterViewInit { } onDocScroll() { - this.desktopDocsNavPosition = ( window.pageYOffset > 115 ) ? "fixed" : "relative"; + this.desktopDocsNavPosition = ( window.pageYOffset > 115 ) ? 'fixed' : 'relative'; } anchorLinkClick( e ) { - let targetId = e.fragment; - let vOffset = ( window.innerWidth <= 992 ) ? 100 : 60; + const targetId = e.fragment; + const vOffset = ( window.innerWidth <= 992 ) ? 100 : 60; window.scrollTo({ top: document.getElementById( targetId ).offsetTop - vOffset }); - window.history.pushState({}, null, document.location.href.split("#")[0] + "#" + targetId); + window.history.pushState({}, null, document.location.href.split('#')[0] + '#' + targetId); this.openEndpointContainer( targetId ); } openEndpointContainer( targetId ) { let tabHeaderHeight = 0; - if (document.getElementById( targetId + "-tab-header" )) { - tabHeaderHeight = document.getElementById( targetId + "-tab-header" ).scrollHeight; + if (document.getElementById( targetId + '-tab-header' )) { + tabHeaderHeight = document.getElementById( targetId + '-tab-header' ).scrollHeight; } if( ( window.innerWidth <= 992 ) && ( ( this.whichTab === 'rest' ) || ( this.whichTab === 'faq' ) || ( this.whichTab === 'websocket' ) ) && targetId ) { - const endpointContainerEl = document.querySelector( "#" + targetId ); - const endpointContentEl = document.querySelector( "#" + targetId + " .endpoint-content" ); + const endpointContainerEl = document.querySelector( '#' + targetId ); + const endpointContentEl = document.querySelector( '#' + targetId + ' .endpoint-content' ); const endPointContentElHeight = endpointContentEl.clientHeight; - if( endpointContentEl.classList.contains( "open" ) ) { - endpointContainerEl.style.height = "auto"; - endpointContentEl.style.top = "-10000px"; - endpointContentEl.style.opacity = "0"; - endpointContentEl.classList.remove( "open" ); + if( endpointContentEl.classList.contains( 'open' ) ) { + endpointContainerEl.style.height = 'auto'; + endpointContentEl.style.top = '-10000px'; + endpointContentEl.style.opacity = '0'; + endpointContentEl.classList.remove( 'open' ); } else { - endpointContainerEl.style.height = endPointContentElHeight + tabHeaderHeight + 28 + "px"; - endpointContentEl.style.top = tabHeaderHeight + 28 + "px"; - endpointContentEl.style.opacity = "1"; - endpointContentEl.classList.add( "open" ); + endpointContainerEl.style.height = endPointContentElHeight + tabHeaderHeight + 28 + 'px'; + endpointContentEl.style.top = tabHeaderHeight + 28 + 'px'; + endpointContentEl.style.opacity = '1'; + endpointContentEl.classList.add( 'open' ); } } } diff --git a/frontend/src/app/docs/code-template/code-template.component.ts b/frontend/src/app/docs/code-template/code-template.component.ts index 2c227d3e8..bfbfc115a 100644 --- a/frontend/src/app/docs/code-template/code-template.component.ts +++ b/frontend/src/app/docs/code-template/code-template.component.ts @@ -25,12 +25,12 @@ export class CodeTemplateComponent implements OnInit { } adjustContainerHeight( event ) { - if( ( window.innerWidth <= 992 ) && ( this.method !== "websocket" ) ) { - const urlObj = new URL( window.location + "" ); + if( ( window.innerWidth <= 992 ) && ( this.method !== 'websocket' ) ) { + const urlObj = new URL( window.location + '' ); const endpointContainerEl = document.querySelector( urlObj.hash ); - const endpointContentEl = document.querySelector( urlObj.hash + " .endpoint-content" ); + const endpointContentEl = document.querySelector( urlObj.hash + ' .endpoint-content' ); window.setTimeout( function() { - endpointContainerEl.style.height = endpointContentEl.clientHeight + 90 + "px"; + endpointContainerEl.style.height = endpointContentEl.clientHeight + 90 + 'px'; }, 550); } } @@ -260,7 +260,7 @@ yarn add @mempool/liquid.js`; } wrapPythonTemplate(code: any) { - return ( ( this.network === 'testnet' || this.network === 'testnet4' || this.network === 'signet' ) ? ( code.codeTemplate.python.replace( "wss://mempool.space/api/v1/ws", "wss://mempool.space/" + this.network + "/api/v1/ws" ) ) : code.codeTemplate.python ); + return ( ( this.network === 'testnet' || this.network === 'testnet4' || this.network === 'signet' ) ? ( code.codeTemplate.python.replace( 'wss://mempool.space/api/v1/ws', 'wss://mempool.space/' + this.network + '/api/v1/ws' ) ) : code.codeTemplate.python ); } replaceJSPlaceholder(text: string, code: any) { @@ -274,8 +274,8 @@ yarn add @mempool/liquid.js`; replaceCurlPlaceholder(curlText: any, code: any) { let text = curlText; - text = text.replace( "[[hostname]]", this.hostname ); - text = text.replace( "[[baseNetworkUrl]]", this.baseNetworkUrl ); + text = text.replace( '[[hostname]]', this.hostname ); + text = text.replace( '[[baseNetworkUrl]]', this.baseNetworkUrl ); for (let index = 0; index < code.curl.length; index++) { const textReplace = code.curl[index]; const indexNumber = index + 1; @@ -283,7 +283,7 @@ yarn add @mempool/liquid.js`; } const headersString = code.headers ? ` -H "${code.headers}"` : ``; - + if (this.env.BASE_MODULE === 'mempool') { if (this.network === 'main' || this.network === '' || this.network === this.env.ROOT_NETWORK) { if (this.method === 'POST') { diff --git a/frontend/src/app/docs/docs/docs.component.ts b/frontend/src/app/docs/docs/docs.component.ts index 35b01be0e..d60252863 100644 --- a/frontend/src/app/docs/docs/docs.component.ts +++ b/frontend/src/app/docs/docs/docs.component.ts @@ -35,19 +35,19 @@ export class DocsComponent implements OnInit { this.showFaqTab = ( this.env.BASE_MODULE === 'mempool' ) ? true : false; this.showElectrsTab = this.stateService.env.OFFICIAL_MEMPOOL_SPACE; - document.querySelector( "html" ).style.scrollBehavior = "smooth"; + document.querySelector( 'html' ).style.scrollBehavior = 'smooth'; } ngDoCheck(): void { const url = this.route.snapshot.url; - if (url[0].path === "faq" ) { + if (url[0].path === 'faq' ) { this.activeTab = 0; this.seoService.setTitle($localize`:@@meta.title.docs.faq:FAQ`); this.seoService.setDescription($localize`:@@meta.description.docs.faq:Get answers to common questions like: What is a mempool? Why isn't my transaction confirming? How can I run my own instance of The Mempool Open Source Project? And more.`); this.ogService.setManualOgImage('faq.jpg'); - } else if( url[1].path === "rest" ) { + } else if( url[1].path === 'rest' ) { this.activeTab = 1; this.seoService.setTitle($localize`:@@meta.title.docs.rest:REST API`); if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) { @@ -55,7 +55,7 @@ export class DocsComponent implements OnInit { } else { this.seoService.setDescription($localize`:@@meta.description.docs.rest-bitcoin:Documentation for the mempool.space REST API service: get info on addresses, transactions, blocks, fees, mining, the Lightning network, and more.`); } - } else if( url[1].path === "websocket" ) { + } else if( url[1].path === 'websocket' ) { this.activeTab = 2; this.seoService.setTitle($localize`:@@meta.title.docs.websocket:WebSocket API`); if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) { @@ -71,6 +71,6 @@ export class DocsComponent implements OnInit { } ngOnDestroy(): void { - document.querySelector( "html" ).style.scrollBehavior = "auto"; + document.querySelector( 'html' ).style.scrollBehavior = 'auto'; } } diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index eacd9df4b..ac449fbf3 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -1,4 +1,4 @@ -import { AddressTxSummary, Block, ChainStats } from "./electrs.interface"; +import { AddressTxSummary, Block, ChainStats } from './electrs.interface'; export interface OptimizedMempoolStats { added: number; @@ -91,7 +91,7 @@ export interface PegsVolume { number: number; } -export interface FederationAddress { +export interface FederationAddress { bitcoinaddress: string; balance: string; } @@ -334,13 +334,13 @@ export interface INodesRanking { export interface INodesStatisticsEntry { added: string; - avg_base_fee_mtokens: number; + avg_base_fee_mtokens: number; avg_capacity: number; avg_fee_rate: number; channel_count: number; clearnet_nodes: number; clearnet_tor_nodes: number; - id: number; + id: number; med_base_fee_mtokens: number; med_capacity: number; med_fee_rate: number; @@ -458,26 +458,26 @@ export interface TestMempoolAcceptResult { vsize?: number, fees?: { base: number, - "effective-feerate": number, - "effective-includes": string[], + 'effective-feerate': number, + 'effective-includes': string[], }, ['reject-reason']?: string, } export interface SubmitPackageResult { package_msg: string; - "tx-results": { [wtxid: string]: TxResult }; - "replaced-transactions"?: string[]; + 'tx-results': { [wtxid: string]: TxResult }; + 'replaced-transactions'?: string[]; } export interface TxResult { txid: string; - "other-wtxid"?: string; + 'other-wtxid'?: string; vsize?: number; fees?: { base: number; - "effective-feerate"?: number; - "effective-includes"?: string[]; + 'effective-feerate'?: number; + 'effective-includes'?: string[]; }; error?: string; } diff --git a/frontend/src/app/interfaces/services.interface.ts b/frontend/src/app/interfaces/services.interface.ts index f0ec6de7b..6085db749 100644 --- a/frontend/src/app/interfaces/services.interface.ts +++ b/frontend/src/app/interfaces/services.interface.ts @@ -10,5 +10,5 @@ export type MenuItem = { export type MenuGroup = { title: string; i18n: string; - items: MenuItem[]; + items: MenuItem[]; } diff --git a/frontend/src/app/lightning/channel/channel.component.ts b/frontend/src/app/lightning/channel/channel.component.ts index 19254a5e1..064206a6e 100644 --- a/frontend/src/app/lightning/channel/channel.component.ts +++ b/frontend/src/app/lightning/channel/channel.component.ts @@ -84,7 +84,7 @@ export class ChannelComponent implements OnInit { } showCloseBoxes(channel: IChannel): boolean { - return !!(channel.node_left.funding_balance || channel.node_left.closing_balance + return !!(channel.node_left.funding_balance || channel.node_left.closing_balance || channel.node_right.funding_balance || channel.node_right.closing_balance); } diff --git a/frontend/src/app/lightning/channel/closing-type/closing-type.component.ts b/frontend/src/app/lightning/channel/closing-type/closing-type.component.ts index 541011469..43243143d 100644 --- a/frontend/src/app/lightning/channel/closing-type/closing-type.component.ts +++ b/frontend/src/app/lightning/channel/closing-type/closing-type.component.ts @@ -17,7 +17,7 @@ export class ClosingTypeComponent implements OnChanges { getLabelFromType(type: number): { label: string; class: string } { switch (type) { - case 1: return { + case 1: return { label: $localize`Mutually closed`, class: 'success', }; diff --git a/frontend/src/app/lightning/channels-list/channels-list.component.ts b/frontend/src/app/lightning/channels-list/channels-list.component.ts index a7a083278..93333a48b 100644 --- a/frontend/src/app/lightning/channels-list/channels-list.component.ts +++ b/frontend/src/app/lightning/channels-list/channels-list.component.ts @@ -33,7 +33,7 @@ export class ChannelsListComponent implements OnInit, OnChanges { constructor( private lightningApiService: LightningApiService, private formBuilder: UntypedFormBuilder, - ) { + ) { this.channelStatusForm = this.formBuilder.group({ status: [this.defaultStatus], }); diff --git a/frontend/src/app/lightning/group/group.component.ts b/frontend/src/app/lightning/group/group.component.ts index fdc689c11..34a3e9e2c 100644 --- a/frontend/src/app/lightning/group/group.component.ts +++ b/frontend/src/app/lightning/group/group.component.ts @@ -89,7 +89,7 @@ export class GroupComponent implements OnInit { const sumLiquidity = nodes.reduce((partialSum, a) => partialSum + parseInt(a.capacity, 10), 0); const sumChannels = nodes.reduce((partialSum, a) => partialSum + a.opened_channel_count, 0); - + return { nodes: nodes, sumLiquidity: sumLiquidity, diff --git a/frontend/src/app/lightning/lightning-api.service.ts b/frontend/src/app/lightning/lightning-api.service.ts index 14276dc12..c4411630c 100644 --- a/frontend/src/app/lightning/lightning-api.service.ts +++ b/frontend/src/app/lightning/lightning-api.service.ts @@ -10,7 +10,7 @@ import { IChannel, INodesRanking, IOldestNodes, ITopNodesPerCapacity, ITopNodesP export class LightningApiService { private apiBaseUrl: string; // base URL is protocol, hostname, and port private apiBasePath = ''; // network path is /testnet, etc. or '' for mainnet - + private requestCache = new Map, expiry: number }>; constructor( diff --git a/frontend/src/app/lightning/node/liquidity-ad.ts b/frontend/src/app/lightning/node/liquidity-ad.ts index 4b0e04b0b..373bd5c22 100644 --- a/frontend/src/app/lightning/node/liquidity-ad.ts +++ b/frontend/src/app/lightning/node/liquidity-ad.ts @@ -18,7 +18,7 @@ export function parseLiquidityAdHex(compact_lease: string): ILiquidityAd | false channel_fee_max_rate: parseInt(compact_lease.slice(8, 12), 16), lease_fee_base_sat: parseInt(compact_lease.slice(12, 20), 16), channel_fee_max_base: compact_lease.length > 20 ? parseInt(compact_lease.slice(20), 16) : 0, - } + }; if (Object.values(liquidityAd).reduce((valid: boolean, value: number): boolean => (valid && !isNaN(value) && value >= 0), true)) { liquidityAd.compact_lease = compact_lease; return liquidityAd; diff --git a/frontend/src/app/lightning/node/node-preview.component.ts b/frontend/src/app/lightning/node/node-preview.component.ts index 63aecc4ae..4eeadcd76 100644 --- a/frontend/src/app/lightning/node/node-preview.component.ts +++ b/frontend/src/app/lightning/node/node-preview.component.ts @@ -73,7 +73,7 @@ export class NodePreviewComponent implements OnInit { label: label, socket: node.public_key + '@' + socket, }); - socketTypesMap[label] = true + socketTypesMap[label] = true; } node.socketsObject = socketsObject; this.socketTypes = Object.keys(socketTypesMap); diff --git a/frontend/src/app/lightning/nodes-channels/node-channels.component.ts b/frontend/src/app/lightning/nodes-channels/node-channels.component.ts index 90876e7f8..bbadac34e 100644 --- a/frontend/src/app/lightning/nodes-channels/node-channels.component.ts +++ b/frontend/src/app/lightning/nodes-channels/node-channels.component.ts @@ -127,7 +127,7 @@ export class NodeChannels implements OnChanges { } } ] - }; + }; } onChartInit(ec: any): void { diff --git a/frontend/src/app/lightning/nodes-per-country/nodes-per-country.component.ts b/frontend/src/app/lightning/nodes-per-country/nodes-per-country.component.ts index 213c02408..7cd8a4b9d 100644 --- a/frontend/src/app/lightning/nodes-per-country/nodes-per-country.component.ts +++ b/frontend/src/app/lightning/nodes-per-country/nodes-per-country.component.ts @@ -97,7 +97,7 @@ export class NodesPerCountry implements OnInit { }; }), tap(() => { - this.isLoading = false + this.isLoading = false; this.cd.markForCheck(); }), share() diff --git a/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp.component.ts b/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp.component.ts index ad8851942..66cf306ad 100644 --- a/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp.component.ts +++ b/frontend/src/app/lightning/nodes-per-isp/nodes-per-isp.component.ts @@ -77,7 +77,7 @@ export class NodesPerISP implements OnInit { } } topCountry.flag = getFlagEmoji(topCountry.iso); - + return { nodes: response.nodes, sumLiquidity: sumLiquidity, diff --git a/frontend/src/app/lightning/nodes-ranking/oldest-nodes/oldest-nodes.component.ts b/frontend/src/app/lightning/nodes-ranking/oldest-nodes/oldest-nodes.component.ts index b5cbf0a41..e2b913304 100644 --- a/frontend/src/app/lightning/nodes-ranking/oldest-nodes/oldest-nodes.component.ts +++ b/frontend/src/app/lightning/nodes-ranking/oldest-nodes/oldest-nodes.component.ts @@ -14,7 +14,7 @@ import { LightningApiService } from '@app/lightning/lightning-api.service'; }) export class OldestNodes implements OnInit { @Input() widget: boolean = false; - + oldestNodes$: Observable; skeletonRows: number[] = []; diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts index 6fb1a45a1..7fc1007e6 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts @@ -61,7 +61,7 @@ export class TopNodesPerCapacity implements OnInit { totalCapacity: statistics.latest.total_capacity, totalChannels: statistics.latest.channel_count, } - } + }; }) ); } else { @@ -76,7 +76,7 @@ export class TopNodesPerCapacity implements OnInit { statistics: { totalCapacity: statistics.latest.total_capacity, } - } + }; }) ); } diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts index 532cbc50f..ca9fb07e7 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts @@ -17,11 +17,11 @@ export class TopNodesPerChannels implements OnInit { @Input() nodes$: Observable; @Input() statistics$: Observable; @Input() widget: boolean = false; - + topNodesPerChannels$: Observable<{ nodes: ITopNodesPerChannels[]; statistics: { totalChannels: number; totalCapacity?: number; } }>; skeletonRows: number[] = []; currency$: Observable; - + constructor( private apiService: LightningApiService, private stateService: StateService, @@ -30,7 +30,7 @@ export class TopNodesPerChannels implements OnInit { ngOnInit(): void { this.currency$ = this.stateService.fiatCurrency$; - + for (let i = 1; i <= (this.widget ? 6 : 100); ++i) { this.skeletonRows.push(i); } @@ -59,7 +59,7 @@ export class TopNodesPerChannels implements OnInit { totalChannels: statistics.latest.channel_count, totalCapacity: statistics.latest.total_capacity, } - } + }; }) ); } else { @@ -82,7 +82,7 @@ export class TopNodesPerChannels implements OnInit { statistics: { totalChannels: statistics.latest.channel_count, } - } + }; }) ); } diff --git a/frontend/src/app/liquid/liquid-master-page.module.ts b/frontend/src/app/liquid/liquid-master-page.module.ts index d90643b4d..44d660508 100644 --- a/frontend/src/app/liquid/liquid-master-page.module.ts +++ b/frontend/src/app/liquid/liquid-master-page.module.ts @@ -11,7 +11,7 @@ import { PushTransactionComponent } from '@components/push-transaction/push-tran import { BlocksList } from '@components/blocks-list/blocks-list.component'; import { AssetGroupComponent } from '@components/assets/asset-group/asset-group.component'; import { AssetsComponent } from '@components/assets/assets.component'; -import { AssetsFeaturedComponent } from '@components/assets/assets-featured/assets-featured.component' +import { AssetsFeaturedComponent } from '@components/assets/assets-featured/assets-featured.component'; import { AssetComponent } from '@components/asset/asset.component'; import { AssetsNavComponent } from '@components/assets/assets-nav/assets-nav.component'; import { RecentPegsListComponent } from '@components/liquid-reserves-audit/recent-pegs-list/recent-pegs-list.component'; diff --git a/frontend/src/app/master-page.module.ts b/frontend/src/app/master-page.module.ts index c0297b971..291a3e7ba 100644 --- a/frontend/src/app/master-page.module.ts +++ b/frontend/src/app/master-page.module.ts @@ -144,7 +144,7 @@ if (window['__env']?.OFFICIAL_MEMPOOL_SPACE) { data: { networks: ['bitcoin'] }, component: FaucetComponent, }] - }) + }); } } diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 78626ff23..702e3d014 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -237,7 +237,7 @@ export class ApiService { } listFeaturedAssets$(network: string = 'liquid'): Observable { - if (network === 'liquid') return this.httpClient.get(this.apiBaseUrl + '/api/v1/assets/featured'); + if (network === 'liquid') {return this.httpClient.get(this.apiBaseUrl + '/api/v1/assets/featured');} return of([]); } @@ -286,7 +286,7 @@ export class ApiService { return response; }) ); - } + } getPoolStats$(slug: string): Observable { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pool/${slug}`) @@ -440,7 +440,7 @@ export class ApiService { } lightningSearch$(searchText: string): Observable<{ nodes: any[], channels: any[] }> { - let params = new HttpParams().set('searchText', searchText); + const params = new HttpParams().set('searchText', searchText); // Don't request the backend if searchText is less than 3 characters if (searchText.length < 3) { return of({ nodes: [], channels: [] }); diff --git a/frontend/src/app/services/assets.service.ts b/frontend/src/app/services/assets.service.ts index 1e8d5346a..42afa9627 100644 --- a/frontend/src/app/services/assets.service.ts +++ b/frontend/src/app/services/assets.service.ts @@ -30,7 +30,7 @@ export class AssetsService { switchMap(() => this.httpClient.get(`${apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.json`)), map((rawAssets) => { const assets: AssetExtended[] = Object.values(rawAssets); - + if (this.stateService.network === 'liquid') { // @ts-ignore assets.push({ @@ -46,7 +46,7 @@ export class AssetsService { asset_id: this.nativeAssetId, }); } - + return { objects: rawAssets, array: assets.sort((a: any, b: any) => a.name.localeCompare(b.name)), @@ -60,7 +60,7 @@ export class AssetsService { map((assetsMinimal) => { if (this.stateService.network === 'liquidtestnet') { // Hard coding the Liquid Testnet native asset - assetsMinimal['144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49'] = [null, "tLBTC", "Test Liquid Bitcoin", 8]; + assetsMinimal['144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49'] = [null, 'tLBTC', 'Test Liquid Bitcoin', 8]; } return assetsMinimal; }), diff --git a/frontend/src/app/services/cache.service.ts b/frontend/src/app/services/cache.service.ts index 246008043..6e23164e0 100644 --- a/frontend/src/app/services/cache.service.ts +++ b/frontend/src/app/services/cache.service.ts @@ -50,7 +50,7 @@ export class CacheService { this.txCache[tx.txid] = tx; }); } - + getTxFromCache(txid) { if (this.txCache && this.txCache[txid]) { return this.txCache[txid]; @@ -78,7 +78,7 @@ export class CacheService { try { result = await firstValueFrom(this.apiService.getBlocks$(maxHeight)); } catch (e) { - console.log("failed to load blocks: ", e.message); + console.log('failed to load blocks: ', e.message); } if (result && result.length) { result.forEach(block => { diff --git a/frontend/src/app/services/eta.service.ts b/frontend/src/app/services/eta.service.ts index 8a2e2dc24..d097a6a89 100644 --- a/frontend/src/app/services/eta.service.ts +++ b/frontend/src/app/services/eta.service.ts @@ -269,7 +269,7 @@ export class EtaService { relatives.push(cpfpInfo.bestDescendant); } - if (!!relatives.length) { + if (relatives.length) { const totalWeight = tx.weight + relatives.reduce((prev, val) => prev + val.weight, 0); const totalFees = tx.fee + relatives.reduce((prev, val) => prev + val.fee, 0); diff --git a/frontend/src/app/services/http-cache.interceptor.ts b/frontend/src/app/services/http-cache.interceptor.ts index da683325e..eaae84053 100644 --- a/frontend/src/app/services/http-cache.interceptor.ts +++ b/frontend/src/app/services/http-cache.interceptor.ts @@ -39,7 +39,7 @@ export class HttpCacheInterceptor implements HttpInterceptor { .pipe( tap((event: HttpEvent) => { if (!this.isBrowser && event instanceof HttpResponse) { - let keyId = request.url.split('/').slice(3).join('/'); + const keyId = request.url.split('/').slice(3).join('/'); const headers = {}; for (const k of event.headers.keys()) { headers[k] = event.headers.getAll(k); diff --git a/frontend/src/app/services/opengraph.service.ts b/frontend/src/app/services/opengraph.service.ts index 47b9d87d4..aba487dfc 100644 --- a/frontend/src/app/services/opengraph.service.ts +++ b/frontend/src/app/services/opengraph.service.ts @@ -25,13 +25,13 @@ export class OpenGraphService { private activatedRoute: ActivatedRoute, ) { // save og:image tag from original template - const initialOgImageTag = metaService.getTag("property='og:image'"); + const initialOgImageTag = metaService.getTag('property=\'og:image\''); this.defaultImageUrl = initialOgImageTag?.content || 'https://mempool.space/resources/previews/mempool-space-preview.jpg'; this.router.events.pipe( filter(event => event instanceof NavigationEnd), map(() => this.activatedRoute), map(route => { - while (route.firstChild) route = route.firstChild; + while (route.firstChild) {route = route.firstChild;} return route; }), filter(route => route.outlet === 'primary'), @@ -120,10 +120,10 @@ export class OpenGraphService { this.previewLoadingEvents = {}; this.previewLoadingCount = 0; this.sessionId++; - this.metaService.removeTag("property='og:preview:loading'"); - this.metaService.removeTag("property='og:preview:ready'"); - this.metaService.removeTag("property='og:preview:fail'"); - this.metaService.removeTag("property='og:meta:ready'"); + this.metaService.removeTag('property=\'og:preview:loading\''); + this.metaService.removeTag('property=\'og:preview:ready\''); + this.metaService.removeTag('property=\'og:preview:fail\''); + this.metaService.removeTag('property=\'og:meta:ready\''); } loadPage(path) { diff --git a/frontend/src/app/services/ord-api.service.ts b/frontend/src/app/services/ord-api.service.ts index ae0076906..1a26cd52a 100644 --- a/frontend/src/app/services/ord-api.service.ts +++ b/frontend/src/app/services/ord-api.service.ts @@ -85,7 +85,7 @@ export class OrdApiService { while (true) { const pointer = getNextInscriptionMark(raw, startPosition); - if (pointer === -1) break; + if (pointer === -1) {break;} const inscription = extractInscriptionData(raw, pointer); if (inscription) { diff --git a/frontend/src/app/services/price.service.ts b/frontend/src/app/services/price.service.ts index f4a1717a9..1f729bf4b 100644 --- a/frontend/src/app/services/price.service.ts +++ b/frontend/src/app/services/price.service.ts @@ -211,7 +211,7 @@ export class PriceService { }; for (const price of conversion.prices) { historicalPrice.prices[price.time] = this.stateService.env.ADDITIONAL_CURRENCIES ? { - USD: price.USD, EUR: price.EUR, GBP: price.GBP, CAD: price.CAD, CHF: price.CHF, AUD: price.AUD, + USD: price.USD, EUR: price.EUR, GBP: price.GBP, CAD: price.CAD, CHF: price.CHF, AUD: price.AUD, JPY: price.JPY, BGN: price.BGN, BRL: price.BRL, CNY: price.CNY, CZK: price.CZK, DKK: price.DKK, HKD: price.HKD, HRK: price.HRK, HUF: price.HUF, IDR: price.IDR, ILS: price.ILS, INR: price.INR, ISK: price.ISK, KRW: price.KRW, MXN: price.MXN, MYR: price.MYR, NOK: price.NOK, NZD: price.NZD, @@ -276,7 +276,7 @@ export class PriceService { }; for (const price of conversion.prices) { historicalPrice.prices[price.time] = this.stateService.env.ADDITIONAL_CURRENCIES ? { - USD: price.USD, EUR: price.EUR, GBP: price.GBP, CAD: price.CAD, CHF: price.CHF, AUD: price.AUD, + USD: price.USD, EUR: price.EUR, GBP: price.GBP, CAD: price.CAD, CHF: price.CHF, AUD: price.AUD, JPY: price.JPY, BGN: price.BGN, BRL: price.BRL, CNY: price.CNY, CZK: price.CZK, DKK: price.DKK, HKD: price.HKD, HRK: price.HRK, HUF: price.HUF, IDR: price.IDR, ILS: price.ILS, INR: price.INR, ISK: price.ISK, KRW: price.KRW, MXN: price.MXN, MYR: price.MYR, NOK: price.NOK, NZD: price.NZD, @@ -286,7 +286,7 @@ export class PriceService { USD: price.USD, EUR: price.EUR, GBP: price.GBP, CAD: price.CAD, CHF: price.CHF, AUD: price.AUD, JPY: price.JPY }; } - + const priceTimestamps = Object.keys(historicalPrice.prices).map(Number); priceTimestamps.push(Number.MAX_SAFE_INTEGER); priceTimestamps.sort((a, b) => b - a); diff --git a/frontend/src/app/services/seo.service.ts b/frontend/src/app/services/seo.service.ts index e5ede4db3..55ea1bf9c 100644 --- a/frontend/src/app/services/seo.service.ts +++ b/frontend/src/app/services/seo.service.ts @@ -37,7 +37,7 @@ export class SeoService { filter(event => event instanceof NavigationEnd), map(() => this.activatedRoute), map(route => { - while (route.firstChild) route = route.firstChild; + while (route.firstChild) {route = route.firstChild;} return route; }), filter(route => route.outlet === 'primary'), @@ -88,15 +88,15 @@ export class SeoService { getTitle(): string { if (this.network === 'testnet') - return this.baseTitle + ' - Bitcoin Testnet3'; + {return this.baseTitle + ' - Bitcoin Testnet3';} if (this.network === 'testnet4') - return this.baseTitle + ' - Bitcoin Testnet4'; + {return this.baseTitle + ' - Bitcoin Testnet4';} if (this.network === 'signet') - return this.baseTitle + ' - Bitcoin Signet'; + {return this.baseTitle + ' - Bitcoin Signet';} if (this.network === 'liquid') - return this.baseTitle + ' - Liquid Network'; + {return this.baseTitle + ' - Liquid Network';} if (this.network === 'liquidtestnet') - return this.baseTitle + ' - Liquid Testnet'; + {return this.baseTitle + ' - Liquid Testnet';} return this.baseTitle + ' - ' + (this.network ? this.ucfirst(this.network) : 'Bitcoin') + ' Explorer'; } diff --git a/frontend/src/app/services/services-api.service.ts b/frontend/src/app/services/services-api.service.ts index d85698e42..2814501f0 100644 --- a/frontend/src/app/services/services-api.service.ts +++ b/frontend/src/app/services/services-api.service.ts @@ -54,7 +54,7 @@ export class ServicesApiServices { if (this.stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE) { this.getServicesBackendInfo$().subscribe(version => { this.stateService.servicesBackendInfo$.next(version); - }) + }); } this.getUserInfo$().subscribe(); @@ -82,7 +82,7 @@ export class ServicesApiServices { return of(null); }), share(), - ) + ); } /** diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index f4bed10af..93195fc6f 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -367,7 +367,7 @@ export class StateService { this.hideAudit.subscribe((hide) => { this.storageService.setValue('audit-preference', hide ? 'hide' : 'show'); }); - + const fiatPreference = this.storageService.getValue('fiat-preference'); this.fiatCurrency$ = new BehaviorSubject(fiatPreference || 'USD'); @@ -513,7 +513,7 @@ export class StateService { focusSearchInputDesktop() { if (!hasTouchScreen()) { this.searchFocus$.next(true); - } + } } private testIsProdDomain(prodDomains: string[]): boolean { diff --git a/frontend/src/app/shared/common.utils.ts b/frontend/src/app/shared/common.utils.ts index 9b53600c1..d88e358cc 100644 --- a/frontend/src/app/shared/common.utils.ts +++ b/frontend/src/app/shared/common.utils.ts @@ -1,6 +1,6 @@ -import { MempoolBlockDelta, MempoolBlockDeltaCompressed, MempoolDeltaChange, TransactionCompressed } from "../interfaces/websocket.interface"; -import { TransactionStripped } from "@interfaces/node-api.interface"; -import { AmountShortenerPipe } from "@app/shared/pipes/amount-shortener.pipe"; +import { MempoolBlockDelta, MempoolBlockDeltaCompressed, MempoolDeltaChange, TransactionCompressed } from '../interfaces/websocket.interface'; +import { TransactionStripped } from '@interfaces/node-api.interface'; +import { AmountShortenerPipe } from '@app/shared/pipes/amount-shortener.pipe'; import { Router, ActivatedRoute } from '@angular/router'; const amountShortenerPipe = new AmountShortenerPipe(); @@ -230,7 +230,7 @@ export function handleDemoRedirect(route: ActivatedRoute, router: Router) { const index = path.indexOf(params.next); if (index >= 0) { const nextPath = path[(index + 1) % path.length]; - setTimeout(() => { window.location.replace(`${params.next}?next=${nextPath}`) }, 15000); + setTimeout(() => { window.location.replace(`${params.next}?next=${nextPath}`); }, 15000); } } } @@ -239,9 +239,9 @@ export function handleDemoRedirect(route: ActivatedRoute, router: Router) { // https://stackoverflow.com/a/60467595 export function md5(inputString): string { - var hc="0123456789abcdef"; - function rh(n) {var j,s="";for(j=0;j<=3;j++) s+=hc.charAt((n>>(j*8+4))&0x0F)+hc.charAt((n>>(j*8))&0x0F);return s;} - function ad(x,y) {var l=(x&0xFFFF)+(y&0xFFFF);var m=(x>>16)+(y>>16)+(l>>16);return (m<<16)|(l&0xFFFF);} + const hc='0123456789abcdef'; + function rh(n) {let j,s='';for(j=0;j<=3;j++) {s+=hc.charAt((n>>(j*8+4))&0x0F)+hc.charAt((n>>(j*8))&0x0F);}return s;} + function ad(x,y) {const l=(x&0xFFFF)+(y&0xFFFF);const m=(x>>16)+(y>>16)+(l>>16);return (m<<16)|(l&0xFFFF);} function rl(n,c) {return (n<>>(32-c));} function cm(q,a,b,x,s,t) {return ad(rl(ad(ad(a,q),ad(x,t)),s),b);} function ff(a,b,c,d,x,s,t) {return cm((b&c)|((~b)&d),a,b,x,s,t);} @@ -249,11 +249,11 @@ export function md5(inputString): string { function hh(a,b,c,d,x,s,t) {return cm(b^c^d,a,b,x,s,t);} function ii(a,b,c,d,x,s,t) {return cm(c^(b|(~d)),a,b,x,s,t);} function sb(x) { - var i;var nblk=((x.length+8)>>6)+1;var blks=new Array(nblk*16);for(i=0;i>2]|=x.charCodeAt(i)<<((i%4)*8); + let i;const nblk=((x.length+8)>>6)+1;const blks=new Array(nblk*16);for(i=0;i>2]|=x.charCodeAt(i)<<((i%4)*8);} blks[i>>2]|=0x80<<((i%4)*8);blks[nblk*16-2]=x.length*8;return blks; } - var i,x=sb(""+inputString),a=1732584193,b=-271733879,c=-1732584194,d=271733878,olda,oldb,oldc,oldd; + let i,x=sb(''+inputString),a=1732584193,b=-271733879,c=-1732584194,d=271733878,olda,oldb,oldc,oldd; for(i=0;i this.crop) { - let croppedInstruction = instructions[i]; + const croppedInstruction = instructions[i]; instructions = instructions.slice(0, i); // add cropped instruction let remainingChars = this.crop - chars; diff --git a/frontend/src/app/shared/components/btc/btc.component.ts b/frontend/src/app/shared/components/btc/btc.component.ts index e2c4ceb0d..038502b67 100644 --- a/frontend/src/app/shared/components/btc/btc.component.ts +++ b/frontend/src/app/shared/components/btc/btc.component.ts @@ -36,10 +36,10 @@ export class BtcComponent implements OnInit, OnChanges { ngOnChanges(changes: SimpleChanges): void { if (this.satoshis >= 1_000_000) { this.value = (this.satoshis / 100_000_000); - this.unit = 'BTC' + this.unit = 'BTC'; } else { this.value = Math.round(this.satoshis); - this.unit = 'sats' + this.unit = 'sats'; } } } diff --git a/frontend/src/app/shared/components/geolocation/geolocation.component.ts b/frontend/src/app/shared/components/geolocation/geolocation.component.ts index 2c8e3b8d3..04e31d0a4 100644 --- a/frontend/src/app/shared/components/geolocation/geolocation.component.ts +++ b/frontend/src/app/shared/components/geolocation/geolocation.component.ts @@ -67,7 +67,7 @@ export class GeolocationComponent implements OnChanges { } } } - + if (this.type === 'node') { const city = this.data.city ? this.data.city : ''; diff --git a/frontend/src/app/shared/components/global-footer/global-footer.component.ts b/frontend/src/app/shared/components/global-footer/global-footer.component.ts index 80729f463..f5f0e3252 100644 --- a/frontend/src/app/shared/components/global-footer/global-footer.component.ts +++ b/frontend/src/app/shared/components/global-footer/global-footer.component.ts @@ -76,7 +76,7 @@ export class GlobalFooterComponent implements OnInit, OnDestroy, OnChanges { this.urlSubscription = this.route.url.subscribe((url) => { this.user = this.storageService.getAuth(); this.cd.markForCheck(); - }) + }); } ngOnChanges(changes: SimpleChanges): void { diff --git a/frontend/src/app/shared/components/mempool-error/mempool-error.component.ts b/frontend/src/app/shared/components/mempool-error/mempool-error.component.ts index f857b9837..af07aa2d8 100644 --- a/frontend/src/app/shared/components/mempool-error/mempool-error.component.ts +++ b/frontend/src/app/shared/components/mempool-error/mempool-error.component.ts @@ -21,7 +21,7 @@ export const MempoolErrors = { 'recommended_fees_not_available': `Recommended fees are not available right now.`, 'too_many_relatives': `This transaction has too many relatives.`, 'txid_not_in_mempool': `This transaction is not in the mempool.`, - 'waitlisted': `You are currently on the wait list. You will get notified once you are granted access.`, + 'waitlisted': `You are currently on the wait list. You will get notified once you are granted access.`, 'not_whitelisted_by_any_pool': `You are not whitelisted by any mining pool`, 'unauthorized': `You are not authorized to do this`, 'faucet_too_soon': `You cannot request any more coins right now. Try again later.`, diff --git a/frontend/src/app/shared/components/toggle/toggle.component.ts b/frontend/src/app/shared/components/toggle/toggle.component.ts index 38caaf655..35d54192c 100644 --- a/frontend/src/app/shared/components/toggle/toggle.component.ts +++ b/frontend/src/app/shared/components/toggle/toggle.component.ts @@ -20,7 +20,7 @@ export class ToggleComponent implements AfterViewInit { ngAfterViewInit(): void { this.animate = true; - setTimeout(() => { this.cd.markForCheck()}); + setTimeout(() => { this.cd.markForCheck();}); } onToggleStatusChanged(e): void { diff --git a/frontend/src/app/shared/i18n/dates.ts b/frontend/src/app/shared/i18n/dates.ts index 188adedf1..09bb8105e 100644 --- a/frontend/src/app/shared/i18n/dates.ts +++ b/frontend/src/app/shared/i18n/dates.ts @@ -14,5 +14,5 @@ export const dates = (counter: number) => { i18nMinutes: $localize`:@@date-base.minutes:${counter}:DATE: minutes`, i18nSecond: $localize`:@@date-base.second:${counter}:DATE: second`, i18nSeconds: $localize`:@@date-base.seconds:${counter}:DATE: seconds`, - } -} \ No newline at end of file + }; +}; \ No newline at end of file diff --git a/frontend/src/app/shared/ord/inscription.utils.ts b/frontend/src/app/shared/ord/inscription.utils.ts index 08ecc316a..13e19ade5 100644 --- a/frontend/src/app/shared/ord/inscription.utils.ts +++ b/frontend/src/app/shared/ord/inscription.utils.ts @@ -75,7 +75,7 @@ export const knownFields = { // delegate, with a tag of 11, see delegate docs: https://docs.ordinals.com/inscriptions/delegate.html delegate: 0xb -} +}; /** * Retrieves the value for a given field from an array of field objects. @@ -171,7 +171,7 @@ export function readBytes(raw: Uint8Array, pointer: number, n: number): [Uint8Ar */ export function readPushdata(raw: Uint8Array, pointer: number): [Uint8Array, number] { - let [opcodeSlice, newPointer] = readBytes(raw, pointer, 1); + const [opcodeSlice, newPointer] = readBytes(raw, pointer, 1); const opcode = opcodeSlice[0]; // Handle the special case of OP_0 (0x00) which pushes an empty array (interpreted as zero) @@ -209,8 +209,8 @@ export function readPushdata(raw: Uint8Array, pointer: number): [Uint8Array, num throw new Error(`Invalid push opcode ${opcode} at position ${pointer}`); } - let [dataSizeArray, nextPointer] = readBytes(raw, newPointer, numBytes); - let dataSize = littleEndianBytesToNumber(dataSizeArray); + const [dataSizeArray, nextPointer] = readBytes(raw, newPointer, numBytes); + const dataSize = littleEndianBytesToNumber(dataSizeArray); return readBytes(raw, nextPointer, dataSize); } @@ -393,7 +393,7 @@ export function extractInscriptionData(raw: Uint8Array, pointer: number): Inscri } const combinedLengthOfAllArrays = data.reduce((acc, curr) => acc + curr.length, 0); - let combinedData = new Uint8Array(combinedLengthOfAllArrays); + const combinedData = new Uint8Array(combinedLengthOfAllArrays); // Copy all segments from data into combinedData, forming a single contiguous Uint8Array let idx = 0; diff --git a/frontend/src/app/shared/pipes/bytes-pipe/bytes.pipe.ts b/frontend/src/app/shared/pipes/bytes-pipe/bytes.pipe.ts index 3ff8acfcf..cc9e02358 100644 --- a/frontend/src/app/shared/pipes/bytes-pipe/bytes.pipe.ts +++ b/frontend/src/app/shared/pipes/bytes-pipe/bytes.pipe.ts @@ -34,7 +34,7 @@ export class BytesPipe implements PipeTransform { unit = BytesPipe.formats[unit].prev!; } - let numberFormat = sigfigs == null ? + const numberFormat = sigfigs == null ? (number) => toDecimal(number, decimal).toString() : (number) => toSigFigs(number, sigfigs); diff --git a/frontend/src/app/shared/pipes/fee-rounding/fee-rounding.pipe.ts b/frontend/src/app/shared/pipes/fee-rounding/fee-rounding.pipe.ts index 1e7a51e9b..2ff8d1cda 100644 --- a/frontend/src/app/shared/pipes/fee-rounding/fee-rounding.pipe.ts +++ b/frontend/src/app/shared/pipes/fee-rounding/fee-rounding.pipe.ts @@ -1,8 +1,8 @@ -import { formatNumber } from "@angular/common"; -import { Inject, LOCALE_ID, Pipe, PipeTransform } from "@angular/core"; +import { formatNumber } from '@angular/common'; +import { Inject, LOCALE_ID, Pipe, PipeTransform } from '@angular/core'; @Pipe({ - name: "feeRounding", + name: 'feeRounding', standalone: false, }) export class FeeRoundingPipe implements PipeTransform { diff --git a/frontend/src/app/shared/pipes/fiat-shortener.pipe.ts b/frontend/src/app/shared/pipes/fiat-shortener.pipe.ts index 48ef3b455..024e4404c 100644 --- a/frontend/src/app/shared/pipes/fiat-shortener.pipe.ts +++ b/frontend/src/app/shared/pipes/fiat-shortener.pipe.ts @@ -42,7 +42,7 @@ export class FiatShortenerPipe implements PipeTransform { let result = item ? (num / item.value).toFixed(digits).replace(rx, '$1') : '0'; result = new Intl.NumberFormat(this.locale, { style: 'currency', currency, maximumFractionDigits: 0 }).format(item ? num / item.value : 0); - + return result + item.symbol; } } diff --git a/frontend/src/app/shared/pipes/math-ceil/math-ceil.pipe.ts b/frontend/src/app/shared/pipes/math-ceil/math-ceil.pipe.ts index 02f711eb1..379209289 100644 --- a/frontend/src/app/shared/pipes/math-ceil/math-ceil.pipe.ts +++ b/frontend/src/app/shared/pipes/math-ceil/math-ceil.pipe.ts @@ -1,6 +1,6 @@ import { Pipe, PipeTransform } from '@angular/core'; -@Pipe({ +@Pipe({ name: 'ceil', standalone: false, }) diff --git a/frontend/src/app/shared/pipes/relative-url/relative-url.pipe.ts b/frontend/src/app/shared/pipes/relative-url/relative-url.pipe.ts index e927a73d6..73614b128 100644 --- a/frontend/src/app/shared/pipes/relative-url/relative-url.pipe.ts +++ b/frontend/src/app/shared/pipes/relative-url/relative-url.pipe.ts @@ -13,7 +13,7 @@ export class RelativeUrlPipe implements PipeTransform { transform(value: string, swapNetwork?: string): string { let network = swapNetwork || this.stateService.network; - if (network === 'mainnet' || network === this.stateService.env.ROOT_NETWORK) { + if (network === 'mainnet' || network === this.stateService.env.ROOT_NETWORK) { network = ''; } if (this.stateService.env.BASE_MODULE === 'liquid' && network === 'liquidtestnet') { diff --git a/frontend/src/app/shared/regex.utils.ts b/frontend/src/app/shared/regex.utils.ts index 00d4ec2f9..5e8a3aebc 100644 --- a/frontend/src/app/shared/regex.utils.ts +++ b/frontend/src/app/shared/regex.utils.ts @@ -97,7 +97,7 @@ const ADDRESS_CHARS: { + `|` + `[V][TJ]` // Confidential P2PKH or P2SH starts with VT or VJ + BASE58_CHARS - + `{78}`, + + `{78}`, bech32: `(?:` + `(?:` // bech32 liquid starts with ex1 (unconfidential) or lq1 (confidential) + `ex1` @@ -138,7 +138,7 @@ const ADDRESS_CHARS: { + `{6,100}` + `)`, }, -} +}; type RegexTypeNoAddrNoBlockHash = | `transaction` | `blockheight` | `date` | `timestamp`; export type RegexType = `address` | `blockhash` | RegexTypeNoAddrNoBlockHash; @@ -146,7 +146,7 @@ export const NETWORKS = [`mainnet`, `testnet4`, `testnet`, `signet`, `liquid`, ` export type Network = typeof NETWORKS[number]; // Turn const array into union type export const ADDRESS_REGEXES: [RegExp, Network][] = NETWORKS - .map(network => [getRegex('address', network), network]) + .map(network => [getRegex('address', network), network]); export function findOtherNetworks(address: string, skipNetwork: Network, env: Env): { network: Network, address: string, isNetworkAvailable: boolean }[] { return ADDRESS_REGEXES @@ -174,7 +174,7 @@ function isNetworkAvailable(network: Network, env: Env): boolean { } export function needBaseModuleChange(fromBaseModule: 'mempool' | 'liquid', toNetwork: Network): boolean { - if (!toNetwork) return false; // No target network means no change needed + if (!toNetwork) {return false;} // No target network means no change needed if (fromBaseModule === 'mempool') { return toNetwork !== 'mainnet' && toNetwork !== 'testnet' && toNetwork !== 'testnet4' && toNetwork !== 'signet'; } diff --git a/frontend/src/app/shared/script.utils.ts b/frontend/src/app/shared/script.utils.ts index 287b30efb..5b86c4d64 100644 --- a/frontend/src/app/shared/script.utils.ts +++ b/frontend/src/app/shared/script.utils.ts @@ -1,6 +1,6 @@ -import { Vin } from "../interfaces/electrs.interface"; -import { AddressType, detectAddressType } from "./address-utils"; -import { ParsedTaproot } from "./transaction.utils"; +import { Vin } from '../interfaces/electrs.interface'; +import { AddressType, detectAddressType } from './address-utils'; +import { ParsedTaproot } from './transaction.utils'; const opcodes = { OP_FALSE: 0, @@ -530,7 +530,7 @@ export function isPoint(pointHex: string): boolean { } // Function modified slightly from noble-curves - + // Now we know that pointHex is a 33 or 65 byte hex string. const isCompressed = pointHex.length === 66; diff --git a/frontend/src/app/shared/sha256.ts b/frontend/src/app/shared/sha256.ts index 08aa0f995..020bb2d16 100644 --- a/frontend/src/app/shared/sha256.ts +++ b/frontend/src/app/shared/sha256.ts @@ -152,7 +152,7 @@ export class Hash { // instance must be reset to use it again. update(data: Uint8Array, dataLength: number = data.length): this { if (this.finished) { - throw new Error("SHA256: can't update because hash was finished."); + throw new Error('SHA256: can\'t update because hash was finished.'); } let dataPos = 0; this.bytesHashed += dataLength; @@ -353,7 +353,7 @@ function fillBuffer(buffer: Uint8Array, hmac: HMAC, info: Uint8Array | undefined const num = counter[0]; if (num === 0) { - throw new Error("hkdf: cannot expand more"); + throw new Error('hkdf: cannot expand more'); } // Prepare HMAC instance for new data with old key. @@ -425,7 +425,7 @@ export function pbkdf2(password: Uint8Array, salt: Uint8Array, iterations: numbe const dk = new Uint8Array(dkLen); for (let i = 0; i * len < dkLen; i++) { - let c = i + 1; + const c = i + 1; ctr[0] = (c >>> 24) & 0xff; ctr[1] = (c >>> 16) & 0xff; ctr[2] = (c >>> 8) & 0xff; diff --git a/frontend/src/app/shared/transaction.utils.ts b/frontend/src/app/shared/transaction.utils.ts index 24ac39344..9c238d491 100644 --- a/frontend/src/app/shared/transaction.utils.ts +++ b/frontend/src/app/shared/transaction.utils.ts @@ -303,7 +303,7 @@ export function processInputSignatures(vin: Vin): SigInfo[] { return signatures; } -/* +/* * returns the number of missing signatures, the number of bytes to add to the transaction * and whether these should benefit from witness discounting * - Add a DER sig in scriptsig/witness: 71 bytes signature + 1 push or witness size byte = 72 bytes @@ -1125,7 +1125,7 @@ function convertScriptSigAsm(hex: string): string { * the script item if it is a script spend. */ function witnessToP2TRScript(witness: string[]): string | null { - if (witness.length < 2) return null; + if (witness.length < 2) {return null;} // Note: see BIP341 for parsing details of witness stack // If there are at least two witness elements, and the first byte of the @@ -1135,7 +1135,7 @@ function witnessToP2TRScript(witness: string[]): string | null { // If there are at least two witness elements left, script path spending is used. // Call the second-to-last stack element s, the script. // (Note: this phrasing from BIP341 assumes we've *removed* the annex from the stack) - if (hasAnnex && witness.length < 3) return null; + if (hasAnnex && witness.length < 3) {return null;} const positionOfScript = hasAnnex ? witness.length - 3 : witness.length - 2; return witness[positionOfScript]; } @@ -1188,7 +1188,7 @@ function fromBuffer(buffer: Uint8Array, network: string, inputs?: PsbtKeyValueMa block_time: null, } } as Transaction; - + [tx.version, offset] = readInt32(buffer, offset); let marker, flag; @@ -1250,7 +1250,7 @@ function fromBuffer(buffer: Uint8Array, network: string, inputs?: PsbtKeyValueMa if (offset !== buffer.length) { throw new Error('Transaction has unexpected data'); } - + // Optionally add data from PSBT: prevouts, redeem/witness scripts and signatures if (inputs) { for (let i = 0; i < tx.vin.length; i++) { @@ -1311,7 +1311,7 @@ function fromBuffer(buffer: Uint8Array, network: string, inputs?: PsbtKeyValueMa if (groups.redeemScript && !finalizedScriptSig) { const redeemScript = groups.redeemScript.value; if (redeemScript.length > 520) { - throw new Error("Redeem script must be <= 520 bytes"); + throw new Error('Redeem script must be <= 520 bytes'); } let pushOpcode; if (redeemScript.length < 0x4c) { @@ -1336,7 +1336,7 @@ function fromBuffer(buffer: Uint8Array, network: string, inputs?: PsbtKeyValueMa const scriptpubkey_type = vin.prevout?.scriptpubkey_type; if (scriptpubkey_type === 'multisig' && !finalizedScriptSig) { if (signature.length > 74) { - throw new Error("Signature must be <= 74 bytes"); + throw new Error('Signature must be <= 74 bytes'); } const pushOpcode = new Uint8Array([signature.length]); vin.scriptsig = uint8ArrayToHexString(pushOpcode) + uint8ArrayToHexString(signature) + (vin.scriptsig || ''); @@ -1351,7 +1351,7 @@ function fromBuffer(buffer: Uint8Array, network: string, inputs?: PsbtKeyValueMa } else { if (!finalizedScriptSig) { if (signature.length > 74) { - throw new Error("Signature must be <= 74 bytes"); + throw new Error('Signature must be <= 74 bytes'); } const pushOpcode = new Uint8Array([signature.length]); vin.scriptsig = uint8ArrayToHexString(pushOpcode) + uint8ArrayToHexString(signature) + (vin.scriptsig || ''); @@ -1419,7 +1419,7 @@ function fromBuffer(buffer: Uint8Array, network: string, inputs?: PsbtKeyValueMa } } } - } + } } // Calculate final size, weight, and txid @@ -1483,7 +1483,7 @@ function decodePsbt(psbtBuffer: Uint8Array): { rawTx: Uint8Array; inputs: PsbtKe const expectedMagic = [0x70, 0x73, 0x62, 0x74]; for (let i = 0; i < expectedMagic.length; i++) { if (psbtBuffer[offset + i] !== expectedMagic[i]) { - throw new Error("Invalid PSBT magic bytes"); + throw new Error('Invalid PSBT magic bytes'); } } offset += expectedMagic.length; @@ -1491,7 +1491,7 @@ function decodePsbt(psbtBuffer: Uint8Array): { rawTx: Uint8Array; inputs: PsbtKe const separator = psbtBuffer[offset]; offset += 1; if (separator !== 0xff) { - throw new Error("Invalid PSBT separator"); + throw new Error('Invalid PSBT separator'); } // GLOBAL MAP @@ -1517,7 +1517,7 @@ function decodePsbt(psbtBuffer: Uint8Array): { rawTx: Uint8Array; inputs: PsbtKe } if (!rawTx) { - throw new Error("Unsigned transaction not found in PSBT"); + throw new Error('Unsigned transaction not found in PSBT'); } const readMaps = (count: number, startOffset: number): { map: PsbtKeyValueMap[]; offset: number } => { @@ -1840,24 +1840,24 @@ export function taprootAddressToOutputKey(address: string): { outputKey: string, // base58 encoding function base58Encode(data: Uint8Array): string { - const BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; - let hexString = Array.from(data) + const hexString = Array.from(data) .map(byte => byte.toString(16).padStart(2, '0')) .join(''); - - let num = BigInt("0x" + hexString); - let encoded = ""; + let num = BigInt('0x' + hexString); + + let encoded = ''; while (num > 0) { const remainder = Number(num % 58n); num = num / 58n; encoded = BASE58_ALPHABET[remainder] + encoded; } - for (let byte of data) { + for (const byte of data) { if (byte === 0) { - encoded = "1" + encoded; + encoded = '1' + encoded; } else { break; } @@ -1868,7 +1868,7 @@ function base58Encode(data: Uint8Array): string { // bech32 encoding / decoding // Adapted from https://github.com/bitcoinjs/bech32/blob/5ceb0e3d4625561a459c85643ca6947739b2d83c/src/index.ts -const BECH32_ALPHABET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; +const BECH32_ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'; type Bech32Encoding = 'bech32' | 'bech32m'; function bech32Encode(prefix: string, words: number[], encoding: Bech32Encoding = 'bech32'): string { @@ -1968,7 +1968,7 @@ function convertBits(data, fromBits, toBits, pad) { for (let i = 0; i < data.length; ++i) { const value = data[i]; - if (value < 0 || value >> fromBits) throw new Error('Invalid value'); + if (value < 0 || value >> fromBits) {throw new Error('Invalid value');} acc = (acc << fromBits) | value; bits += fromBits; while (bits >= toBits) { @@ -2098,13 +2098,13 @@ function readVarInt(buffer: Uint8Array, offset: number): [number, number] { const [bigValue, nextOffset] = readInt64(buffer, newOffset); if (bigValue > Number.MAX_SAFE_INTEGER) { - throw new Error("VarInt exceeds safe integer range"); + throw new Error('VarInt exceeds safe integer range'); } const numValue = Number(bigValue); return [numValue, nextOffset]; } else { - throw new Error("Invalid VarInt prefix"); + throw new Error('Invalid VarInt prefix'); } } From 5469442cda7dff841f8cf142aa2c1def7d1d5112 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 4 Jan 2026 13:02:01 +0000 Subject: [PATCH 18/56] fix core hash display on monitoring page --- .../app/components/server-health/server-health.component.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/app/components/server-health/server-health.component.html b/frontend/src/app/components/server-health/server-health.component.html index 28893f103..4a222e632 100644 --- a/frontend/src/app/components/server-health/server-health.component.html +++ b/frontend/src/app/components/server-health/server-health.component.html @@ -38,6 +38,8 @@ @if (type !== 'core' && host.hashes?.[type]) { {{ host.hashes[type].slice(0, 8) || '?' }} + } @else if (host.hashes?.[type]) { + {{ host.hashes[type] || '?' }} } @else { ? } From 9ecd7dc2cecfa875da3c600013f8da3223f513e2 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Sun, 4 Jan 2026 13:03:42 -0800 Subject: [PATCH 19/56] Fix backend lint warnings --- backend/jest.config.ts | 18 +-- backend/jest.integration.config.ts | 18 +-- backend/jest.integration.setup.ts | 8 +- backend/jest.integration.teardown.ts | 16 +-- .../blocks-repository.test.ts | 26 ++-- .../database-migration.test.ts | 6 +- .../pools-repository.test.ts | 8 +- .../src/__integration_tests__/test-helpers.ts | 6 +- backend/src/__tests__/api/common.ts | 2 +- backend/src/__tests__/config.test.ts | 2 +- backend/src/api/about.routes.ts | 8 +- .../src/api/bitcoin/bitcoin-api.interface.ts | 82 +++++------ backend/src/api/bitcoin/bitcoin-api.ts | 2 +- backend/src/api/bitcoin/electrum-api.ts | 4 +- backend/src/api/blocks.ts | 18 +-- backend/src/api/common.ts | 12 +- backend/src/api/cpfp.ts | 2 +- backend/src/api/database-migration.ts | 38 ++--- backend/src/api/explorer/channels.api.ts | 16 +-- backend/src/api/explorer/nodes.api.ts | 20 +-- backend/src/api/explorer/nodes.routes.ts | 4 +- backend/src/api/fetch-version.ts | 6 +- .../lightning/clightning/clightning-client.ts | 8 +- backend/src/api/lightning/lnd/lnd-api.ts | 4 +- backend/src/api/liquid/elements-parser.ts | 24 ++-- backend/src/api/liquid/liquid.routes.ts | 2 +- backend/src/api/mempool.ts | 18 +-- backend/src/api/mining/mining-routes.ts | 4 +- backend/src/api/mining/mining.ts | 18 +-- backend/src/api/rbf-cache.ts | 12 +- backend/src/api/statistics/statistics-api.ts | 2 +- backend/src/api/transaction-utils.ts | 8 +- backend/src/api/tx-selection-worker.ts | 6 +- backend/src/api/websocket-handler.ts | 4 +- backend/src/config.ts | 2 +- backend/src/indexer.ts | 8 +- backend/src/logger.ts | 4 +- .../src/replication/StatisticsReplication.ts | 22 +-- backend/src/replication/replicator.ts | 2 +- .../repositories/AccelerationRepository.ts | 6 +- .../repositories/BlocksAuditsRepository.ts | 2 +- backend/src/repositories/BlocksRepository.ts | 42 +++--- .../repositories/BlocksSummariesRepository.ts | 4 +- .../src/repositories/HashratesRepository.ts | 2 +- backend/src/repositories/PoolsRepository.ts | 22 +-- backend/src/repositories/PricesRepository.ts | 20 +-- backend/src/rpc-api/index.ts | 42 +++--- backend/src/rpc-api/jsonrpc.ts | 136 +++++++++--------- .../src/tasks/lightning/forensics.service.ts | 2 +- .../tasks/lightning/network-sync.service.ts | 4 +- .../sync-tasks/funding-tx-fetcher.ts | 6 +- .../lightning/sync-tasks/node-locations.ts | 14 +- .../lightning/sync-tasks/stats-importer.ts | 14 +- backend/src/tasks/price-feeds/kraken-api.ts | 2 +- backend/src/tasks/price-updater.ts | 6 +- backend/src/utils/bitcoin-script.ts | 2 +- backend/src/utils/format.ts | 4 +- backend/src/utils/secp256k1.ts | 2 +- backend/testSetup.integration.ts | 2 +- 59 files changed, 402 insertions(+), 402 deletions(-) diff --git a/backend/jest.config.ts b/backend/jest.config.ts index ae4a6b3b2..7989fca81 100644 --- a/backend/jest.config.ts +++ b/backend/jest.config.ts @@ -1,24 +1,24 @@ -import type { Config } from "@jest/types" +import type { Config } from '@jest/types'; const config: Config.InitialOptions = { - preset: "ts-jest", - testEnvironment: "node", + preset: 'ts-jest', + testEnvironment: 'node', verbose: true, automock: false, collectCoverage: true, - collectCoverageFrom: ["./src/**/**.ts"], - coverageProvider: "v8", + collectCoverageFrom: ['./src/**/**.ts'], + coverageProvider: 'v8', coverageThreshold: { global: { lines: 1 } }, setupFiles: [ - "./testSetup.ts", + './testSetup.ts', ], testPathIgnorePatterns: [ - "/node_modules/", - "/__integration_tests__/", + '/node_modules/', + '/__integration_tests__/', ], -} +}; export default config; diff --git a/backend/jest.integration.config.ts b/backend/jest.integration.config.ts index f395e94be..f0c159aed 100644 --- a/backend/jest.integration.config.ts +++ b/backend/jest.integration.config.ts @@ -1,21 +1,21 @@ -import type { Config } from "@jest/types" +import type { Config } from '@jest/types'; const config: Config.InitialOptions = { - preset: "ts-jest", - testEnvironment: "node", + preset: 'ts-jest', + testEnvironment: 'node', verbose: true, automock: false, collectCoverage: false, - coverageProvider: "v8", + coverageProvider: 'v8', testMatch: [ - "**/__integration_tests__/**/*.test.ts" + '**/__integration_tests__/**/*.test.ts' ], - globalSetup: "./jest.integration.setup.ts", // Start database before all tests + globalSetup: './jest.integration.setup.ts', // Start database before all tests setupFiles: [ - "./testSetup.integration.ts", + './testSetup.integration.ts', ], - globalTeardown: "./jest.integration.teardown.ts", // Stop database after all tests + globalTeardown: './jest.integration.teardown.ts', // Stop database after all tests maxWorkers: 1, // Force sequential execution -} +}; export default config; diff --git a/backend/jest.integration.setup.ts b/backend/jest.integration.setup.ts index 2156e3cdd..c5093b01a 100644 --- a/backend/jest.integration.setup.ts +++ b/backend/jest.integration.setup.ts @@ -35,18 +35,18 @@ module.exports = async () => { try { const composeFile = path.join(__dirname, 'docker-compose.test.yml'); const dockerComposeCmd = getDockerComposeCmd(); - + // Start the container - execSync(`${dockerComposeCmd} -f "${composeFile}" up -d`, { + execSync(`${dockerComposeCmd} -f "${composeFile}" up -d`, { stdio: 'inherit', cwd: __dirname }); - + // Wait for database to be ready console.log('Waiting for database to be ready...'); let attempts = 0; const maxAttempts = 30; - + while (attempts < maxAttempts) { try { execSync(`${dockerComposeCmd} -f "${composeFile}" exec -T db-test mysqladmin ping -h localhost -u mempool_test -pmempool_test --silent`, { diff --git a/backend/jest.integration.teardown.ts b/backend/jest.integration.teardown.ts index c4229a262..386e26ab3 100644 --- a/backend/jest.integration.teardown.ts +++ b/backend/jest.integration.teardown.ts @@ -43,7 +43,7 @@ module.exports = async () => { ]; await DB.query('SET FOREIGN_KEY_CHECKS = 0'); - + for (const table of tables) { try { // Use 'silent' error logging to avoid noise for optional tables that don't exist @@ -52,29 +52,29 @@ module.exports = async () => { // Table might not exist - silently ignore } } - + await DB.query('SET FOREIGN_KEY_CHECKS = 1'); - + logger.info('Integration tests cleanup completed'); - + // Close the database connection pool to prevent Jest from hanging await DB.close(); logger.info('Database connection pool closed'); - + // Clean up singleton resources that have timers or sockets mempool.destroy(); logger.info('Mempool resources cleaned up'); - + // Close logger's UDP socket last (after all logging is done) logger.close(); - + // Stop and remove the Docker test database container // Skip if SKIP_DB_TEARDOWN is set (e.g., when test-with-db.sh manages the database) if (!process.env.SKIP_DB_TEARDOWN) { try { const composeFile = path.join(__dirname, 'docker-compose.test.yml'); const dockerComposeCmd = getDockerComposeCmd(); - execSync(`${dockerComposeCmd} -f "${composeFile}" down -v`, { + execSync(`${dockerComposeCmd} -f "${composeFile}" down -v`, { stdio: 'inherit', cwd: __dirname }); diff --git a/backend/src/__integration_tests__/blocks-repository.test.ts b/backend/src/__integration_tests__/blocks-repository.test.ts index b9f449538..91d0353a0 100644 --- a/backend/src/__integration_tests__/blocks-repository.test.ts +++ b/backend/src/__integration_tests__/blocks-repository.test.ts @@ -40,7 +40,7 @@ describe('BlocksRepository Integration Tests', () => { }); const block = await BlocksRepository.$getBlockByHeight(height); - + expect(block).toBeDefined(); expect(block!.height).toBe(height); expect(block!.id).toBe(blockHash); @@ -58,7 +58,7 @@ describe('BlocksRepository Integration Tests', () => { }); const block = await BlocksRepository.$getBlockByHash(blockHash); - + expect(block).toBeDefined(); expect(block!.id).toBe(blockHash); expect(block!.height).toBe(height); @@ -71,36 +71,36 @@ describe('BlocksRepository Integration Tests', () => { test('should check for missing blocks in range', async () => { // Insert blocks with a gap - await insertTestBlock({ - height: 800100, + await insertTestBlock({ + height: 800100, hash: '0000000000000000000100000000000000000000000000000000000000000001', poolId: defaultPoolId }); - await insertTestBlock({ - height: 800102, + await insertTestBlock({ + height: 800102, hash: '0000000000000000000100000000000000000000000000000000000000000003', poolId: defaultPoolId }); const missingBlocks = await BlocksRepository.$getMissingBlocksBetweenHeights(800100, 800102); - + expect(missingBlocks).toContain(800101); }); test('should get latest block height', async () => { - await insertTestBlock({ - height: 800200, + await insertTestBlock({ + height: 800200, hash: '0000000000000000000200000000000000000000000000000000000000000001', poolId: defaultPoolId }); - await insertTestBlock({ - height: 800201, + await insertTestBlock({ + height: 800201, hash: '0000000000000000000200000000000000000000000000000000000000000002', poolId: defaultPoolId }); const height = await BlocksRepository.$mostRecentBlockHeight(); - + expect(height).toBe(800201); }); @@ -121,7 +121,7 @@ describe('BlocksRepository Integration Tests', () => { }); const block = await BlocksRepository.$getBlockByHash(blockHash); - + expect(block).toBeDefined(); expect(block).not.toBeNull(); // The pool should be populated with the test pool's data diff --git a/backend/src/__integration_tests__/database-migration.test.ts b/backend/src/__integration_tests__/database-migration.test.ts index 7b8a5dd74..9270f9fc8 100644 --- a/backend/src/__integration_tests__/database-migration.test.ts +++ b/backend/src/__integration_tests__/database-migration.test.ts @@ -18,7 +18,7 @@ describe('Database Migration Integration Tests', () => { }); test('should have schema version in state table', async () => { - const [result] = await DB.query("SELECT number FROM state WHERE name = 'schema_version'"); + const [result] = await DB.query('SELECT number FROM state WHERE name = \'schema_version\''); expect(result).toHaveLength(1); expect(result[0].number).toBeGreaterThan(0); }); @@ -70,7 +70,7 @@ describe('Database Migration Integration Tests', () => { WHERE TABLE_SCHEMA = 'mempool_test' AND TABLE_NAME = 'blocks'` ); - + const columnNames = columns.map((col: any) => col.COLUMN_NAME); expect(columnNames).toContain('height'); expect(columnNames).toContain('hash'); @@ -87,7 +87,7 @@ describe('Database Migration Integration Tests', () => { WHERE TABLE_SCHEMA = 'mempool_test' AND TABLE_NAME = 'pools'` ); - + const columnNames = columns.map((col: any) => col.COLUMN_NAME); expect(columnNames).toContain('id'); expect(columnNames).toContain('name'); diff --git a/backend/src/__integration_tests__/pools-repository.test.ts b/backend/src/__integration_tests__/pools-repository.test.ts index 7920e7f88..55e503b26 100644 --- a/backend/src/__integration_tests__/pools-repository.test.ts +++ b/backend/src/__integration_tests__/pools-repository.test.ts @@ -43,7 +43,7 @@ describe('PoolsRepository Integration Tests', () => { }); const pool = await PoolsRepository.$getPool('antpool'); - + expect(pool).toBeDefined(); expect(pool!.name).toBe('AntPool'); expect(pool!.slug).toBe('antpool'); @@ -64,7 +64,7 @@ describe('PoolsRepository Integration Tests', () => { }); const pools = await PoolsRepository.$getPools(); - + expect(pools.length).toBeGreaterThanOrEqual(3); }); @@ -77,7 +77,7 @@ describe('PoolsRepository Integration Tests', () => { }); const pool = await PoolsRepository.$getPool('multi-address-pool', false); - + expect(pool).toBeDefined(); const poolAddresses = JSON.parse(pool!.addresses); expect(poolAddresses).toHaveLength(3); @@ -93,7 +93,7 @@ describe('PoolsRepository Integration Tests', () => { }); const pool = await PoolsRepository.$getPool('regex-pool', false); - + expect(pool).toBeDefined(); const poolRegexes = JSON.parse(pool!.regexes); expect(poolRegexes).toHaveLength(2); diff --git a/backend/src/__integration_tests__/test-helpers.ts b/backend/src/__integration_tests__/test-helpers.ts index 74752d9d2..91e47fe2e 100644 --- a/backend/src/__integration_tests__/test-helpers.ts +++ b/backend/src/__integration_tests__/test-helpers.ts @@ -45,7 +45,7 @@ export async function cleanupTestData(): Promise { try { // Disable foreign key checks temporarily for faster cleanup await DB.query('SET FOREIGN_KEY_CHECKS = 0'); - + for (const table of tables) { try { // Use 'silent' error logging to avoid noise for optional tables that don't exist @@ -55,7 +55,7 @@ export async function cleanupTestData(): Promise { // Silently ignore - no need to log since these are expected for optional features } } - + // Re-enable foreign key checks await DB.query('SET FOREIGN_KEY_CHECKS = 1'); } catch (error) { @@ -143,7 +143,7 @@ export async function insertTestBlock(blockData: { const size = blockData.size || 1000000; const weight = blockData.weight || 4000000; const txCount = blockData.tx_count || 2000; - + await DB.query( `INSERT INTO blocks ( height, hash, blockTimestamp, size, weight, tx_count, diff --git a/backend/src/__tests__/api/common.ts b/backend/src/__tests__/api/common.ts index 14ae3c78b..5380391ac 100644 --- a/backend/src/__tests__/api/common.ts +++ b/backend/src/__tests__/api/common.ts @@ -30,7 +30,7 @@ describe('Common', () => { expect(Common.isNonStandard(tx)).toEqual(true); }); }); - + test('should not misclassify as nonstandard transactions', () => { randomTransactions.forEach((tx) => { expect(Common.isNonStandard(tx)).toEqual(false); diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index 23b3dd346..cf81a5f7f 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -144,7 +144,7 @@ describe('Mempool Backend Config', () => { }); expect(config.MEMPOOL_SERVICES).toStrictEqual({ - API: "", + API: '', ACCELERATIONS: false, }); diff --git a/backend/src/api/about.routes.ts b/backend/src/api/about.routes.ts index 2020d111d..8ea052d12 100644 --- a/backend/src/api/about.routes.ts +++ b/backend/src/api/about.routes.ts @@ -1,7 +1,7 @@ -import { Application } from "express"; -import config from "../config"; -import axios from "axios"; -import logger from "../logger"; +import { Application } from 'express'; +import config from '../config'; +import axios from 'axios'; +import logger from '../logger'; class AboutRoutes { public initRoutes(app: Application) { diff --git a/backend/src/api/bitcoin/bitcoin-api.interface.ts b/backend/src/api/bitcoin/bitcoin-api.interface.ts index 5d8371d27..22f800af7 100644 --- a/backend/src/api/bitcoin/bitcoin-api.interface.ts +++ b/backend/src/api/bitcoin/bitcoin-api.interface.ts @@ -165,44 +165,44 @@ export namespace IBitcoinApi { timeout: number; // (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in since: number; // (numeric) height of the first block to which the status applies statistics: { // (object) numeric statistics about BIP9 signalling for a softfork (only for started status) - period: number; // (numeric) the length in blocks of the BIP9 signalling period - threshold: number; // (numeric) the number of blocks with the version bit set required to activate the feature - elapsed: number; // (numeric) the number of blocks elapsed since the beginning of the current period - count: number; // (numeric) the number of blocks with the version bit set in the current period - possible: boolean; // (boolean) returns false if there are not enough blocks left in this period to pass activation threshold + period: number; // (numeric) the length in blocks of the BIP9 signalling period + threshold: number; // (numeric) the number of blocks with the version bit set required to activate the feature + elapsed: number; // (numeric) the number of blocks elapsed since the beginning of the current period + count: number; // (numeric) the number of blocks with the version bit set in the current period + possible: boolean; // (boolean) returns false if there are not enough blocks left in this period to pass activation threshold } } export interface BlockStats { - "avgfee": number; - "avgfeerate": number; - "avgtxsize": number; - "blockhash": string; - "feerate_percentiles": [number, number, number, number, number]; - "height": number; - "ins": number; - "maxfee": number; - "maxfeerate": number; - "maxtxsize": number; - "medianfee": number; - "mediantime": number; - "mediantxsize": number; - "minfee": number; - "minfeerate": number; - "mintxsize": number; - "outs": number; - "subsidy": number; - "swtotal_size": number; - "swtotal_weight": number; - "swtxs": number; - "time": number; - "total_out": number; - "total_size": number; - "total_weight": number; - "totalfee": number; - "txs": number; - "utxo_increase": number; - "utxo_size_inc": number; + 'avgfee': number; + 'avgfeerate': number; + 'avgtxsize': number; + 'blockhash': string; + 'feerate_percentiles': [number, number, number, number, number]; + 'height': number; + 'ins': number; + 'maxfee': number; + 'maxfeerate': number; + 'maxtxsize': number; + 'medianfee': number; + 'mediantime': number; + 'mediantxsize': number; + 'minfee': number; + 'minfeerate': number; + 'mintxsize': number; + 'outs': number; + 'subsidy': number; + 'swtotal_size': number; + 'swtotal_weight': number; + 'swtxs': number; + 'time': number; + 'total_out': number; + 'total_size': number; + 'total_weight': number; + 'totalfee': number; + 'txs': number; + 'utxo_increase': number; + 'utxo_size_inc': number; } } @@ -213,26 +213,26 @@ export interface TestMempoolAcceptResult { vsize?: number, fees?: { base: number, - "effective-feerate": number, - "effective-includes": string[], + 'effective-feerate': number, + 'effective-includes': string[], }, ['reject-reason']?: string, } export interface SubmitPackageResult { package_msg: string; - "tx-results": { [wtxid: string]: TxResult }; - "replaced-transactions"?: string[]; + 'tx-results': { [wtxid: string]: TxResult }; + 'replaced-transactions'?: string[]; } export interface TxResult { txid: string; - "other-wtxid"?: string; + 'other-wtxid'?: string; vsize?: number; fees?: { base: number; - "effective-feerate"?: number; - "effective-includes"?: string[]; + 'effective-feerate'?: number; + 'effective-includes'?: string[]; }; error?: string; } diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts index edd1a2a1e..90543f03f 100644 --- a/backend/src/api/bitcoin/bitcoin-api.ts +++ b/backend/src/api/bitcoin/bitcoin-api.ts @@ -130,7 +130,7 @@ class BitcoinApi implements AbstractBitcoinApi { $getRawBlock(hash: string): Promise { return this.bitcoindClient.getBlock(hash, 0) - .then((raw: string) => Buffer.from(raw, "hex")); + .then((raw: string) => Buffer.from(raw, 'hex')); } $getBlockHash(height: number): Promise { diff --git a/backend/src/api/bitcoin/electrum-api.ts b/backend/src/api/bitcoin/electrum-api.ts index ce8ad3cbb..9e8e17705 100644 --- a/backend/src/api/bitcoin/electrum-api.ts +++ b/backend/src/api/bitcoin/electrum-api.ts @@ -5,7 +5,7 @@ import { IEsploraApi } from './esplora-api.interface'; import { IElectrumApi } from './electrum-api.interface'; import BitcoinApi from './bitcoin-api'; import logger from '../../logger'; -import crypto from "crypto-js"; +import crypto from 'crypto-js'; import loadingIndicators from '../loading-indicators'; import memoryCache from '../memory-cache'; @@ -209,7 +209,7 @@ class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi { async $getScriptHashUtxos(scripthash: string): Promise { const utxos = await this.$getScriptHashUnspent(scripthash); const result: IEsploraApi.UTXO[] = []; - for(let utxo of utxos) { + for(const utxo of utxos) { if(utxo.height===0) { //Unconfirmed result.push({ diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index d33e8fda6..cfd5fcae4 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -106,7 +106,7 @@ class Blocks { const mempool = memPool.getMempool(); let foundInMempool = 0; let totalFound = 0; - let missing = 0; + const missing = 0; // Copy existing transactions from the mempool if (!onlyCoinbase) { @@ -1365,15 +1365,15 @@ class Blocks { /** * Get 15 blocks - * + * * Internally this function uses two methods to get the blocks, and * the method is automatically selected: * - Using previous block hash links * - Using block height - * - * @param fromHeight - * @param limit - * @returns + * + * @param fromHeight + * @param limit + * @returns */ public async $getBlocks(fromHeight?: number, limit: number = 15): Promise { let currentHeight = fromHeight !== undefined ? fromHeight : this.currentBlockHeight; @@ -1405,9 +1405,9 @@ class Blocks { /** * Used for bulk block data query - * - * @param fromHeight - * @param toHeight + * + * @param fromHeight + * @param toHeight */ public async $getBlocksBetweenHeight(fromHeight: number, toHeight: number): Promise { if (!Common.indexingEnabled()) { diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index 0064b7710..df1767d76 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -911,7 +911,7 @@ export class Common { if (id.indexOf('/') !== -1) { id = id.slice(0, -2); } - + if (id.indexOf('x') !== -1) { // Already a short id return id; } @@ -1081,7 +1081,7 @@ export class Common { } static getTransactionFromRequest(req: Request, form: boolean): string { - let rawTx: any = typeof req.body === 'object' && form + const rawTx: any = typeof req.body === 'object' && form ? Object.values(req.body)[0] as any : req.body; if (typeof rawTx !== 'string') { @@ -1182,7 +1182,7 @@ export class Common { } } } - }) + }); } // Pass through the input string untouched @@ -1220,14 +1220,14 @@ export class Common { /** * Class to calculate average fee rates of a list of transactions * at certain weight percentiles, in a single pass - * + * * init with: * maxWeight - the total weight to measure percentiles relative to (e.g. 4MW for a single block) * percentileBandWidth - how many weight units to average over for each percentile (as a % of maxWeight) * percentiles - an array of weight percentiles to compute, in % - * + * * then call .processNext(tx) for each transaction, in descending order - * + * * retrieve the final results with .getFeeStats() */ export class OnlineFeeStatsCalculator { diff --git a/backend/src/api/cpfp.ts b/backend/src/api/cpfp.ts index 953664fcc..ad601361c 100644 --- a/backend/src/api/cpfp.ts +++ b/backend/src/api/cpfp.ts @@ -236,7 +236,7 @@ export function calculateMempoolTxCpfp(tx: MempoolTransactionExtended, mempool: /** * Given a root transaction and a list of in-mempool ancestors, * Calculate the CPFP cluster - * + * * @param tx * @param ancestors */ diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index 00955a758..b0e46be96 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -566,8 +566,8 @@ class DatabaseMigration { await this.$executeQuery('ALTER TABLE `blocks_templates` ADD INDEX `version` (`version`)'); await this.updateToSchemaVersion(67); } - - if (databaseSchemaVersion < 68 && config.MEMPOOL.NETWORK === "liquid") { + + if (databaseSchemaVersion < 68 && config.MEMPOOL.NETWORK === 'liquid') { await this.$executeQuery('TRUNCATE TABLE elements_pegs'); await this.$executeQuery('ALTER TABLE elements_pegs ADD PRIMARY KEY (txid, txindex);'); await this.$executeQuery(`UPDATE state SET number = 0 WHERE name = 'last_elements_block';`); @@ -931,24 +931,24 @@ class DatabaseMigration { // Version 34 await this.$executeQuery('ALTER TABLE `lightning_stats` ADD clearnet_tor_nodes int(11) NOT NULL DEFAULT "0"'); - + // Version 35 await this.$executeQuery('DELETE from `lightning_stats` WHERE added > "2021-09-19"'); await this.$executeQuery('ALTER TABLE `lightning_stats` ADD CONSTRAINT added_unique UNIQUE (added);'); // Version 36 await this.$executeQuery('ALTER TABLE `nodes` ADD status TINYINT NOT NULL DEFAULT "1"'); - + // Version 37 await this.$executeQuery(this.getCreateLNNodesSocketsTableQuery(), await this.$checkIfTableExists('nodes_sockets')); - + // Version 38 await this.$executeQuery(`TRUNCATE lightning_stats`); await this.$executeQuery(`TRUNCATE node_stats`); await this.$executeQuery('ALTER TABLE `lightning_stats` CHANGE `added` `added` timestamp NULL'); await this.$executeQuery('ALTER TABLE `node_stats` CHANGE `added` `added` timestamp NULL'); await this.updateToSchemaVersion(38); - + // Version 39 await this.$executeQuery('ALTER TABLE `nodes` ADD alias_search TEXT NULL DEFAULT NULL AFTER `alias`'); await this.$executeQuery('ALTER TABLE nodes ADD FULLTEXT(alias_search)'); @@ -963,7 +963,7 @@ class DatabaseMigration { // Version 42 await this.$executeQuery('ALTER TABLE `channels` ADD closing_resolved tinyint(1) DEFAULT 0'); - + // Version 43 await this.$executeQuery(this.getCreateLNNodeRecordsTableQuery(), await this.$checkIfTableExists('nodes_records')); @@ -972,7 +972,7 @@ class DatabaseMigration { // Version 45 await this.$executeQuery('ALTER TABLE `blocks_audits` ADD fresh_txs JSON DEFAULT "[]"'); - + // Version 48 await this.$executeQuery('ALTER TABLE `channels` ADD source_checked tinyint(1) DEFAULT 0'); await this.$executeQuery('ALTER TABLE `channels` ADD closing_fee bigint(20) unsigned DEFAULT 0'); @@ -1002,13 +1002,13 @@ class DatabaseMigration { // Version 62 await this.$executeQuery('ALTER TABLE `blocks_audits` ADD expected_fees BIGINT UNSIGNED DEFAULT NULL'); await this.$executeQuery('ALTER TABLE `blocks_audits` ADD expected_weight BIGINT UNSIGNED DEFAULT NULL'); - + // Version 63 await this.$executeQuery('ALTER TABLE `blocks_audits` ADD fullrbf_txs JSON DEFAULT "[]"'); - + // Version 64 await this.$executeQuery('ALTER TABLE `nodes` ADD features text NULL'); - + // Version 65 await this.$executeQuery('ALTER TABLE `blocks_audits` ADD accelerated_txs JSON DEFAULT "[]"'); @@ -1044,8 +1044,8 @@ class DatabaseMigration { ADD INDEX \`closing_reason\` (\`closing_reason\`), ADD INDEX \`closing_resolved\` (\`closing_resolved\`) `); - - // Version 86 + + // Version 86 await this.$executeQuery(` ALTER TABLE \`nodes\` ADD INDEX \`status\` (\`status\`), @@ -1058,20 +1058,20 @@ class DatabaseMigration { // Version 87 await this.$executeQuery('ALTER TABLE `nodes_sockets` ADD INDEX `type` (`type`)'); await this.updateToSchemaVersion(87); - + // Version 88 await this.$executeQuery('ALTER TABLE `lightning_stats` ADD INDEX `added` (`added`)'); - + // Version 89 await this.$executeQuery('ALTER TABLE `geo_names` ADD INDEX `names` (`names`)'); - + // Version 90 await this.$executeQuery('ALTER TABLE `hashrates` ADD INDEX `type` (`type`)'); // Version 91 await this.$executeQuery('ALTER TABLE `blocks_audits` ADD INDEX `time` (`time`)'); } - + if (config.MEMPOOL.NETWORK !== 'liquid') { // Apply all the liquid specific migrations to all other networks // Version 68 @@ -1093,7 +1093,7 @@ class DatabaseMigration { ADD INDEX \`bitcoinaddress\` (\`bitcoinaddress\`), ADD INDEX \`bitcointxid\` (\`bitcointxid\`) `); - + // Version 93 await this.$executeQuery(` ALTER TABLE \`federation_txos\` @@ -1456,7 +1456,7 @@ class DatabaseMigration { pegtxid varchar(65) NOT NULL, pegindex int(11) NOT NULL, pegblocktime int(11) unsigned NOT NULL, - PRIMARY KEY (txid, txindex), + PRIMARY KEY (txid, txindex), FOREIGN KEY (bitcoinaddress) REFERENCES federation_addresses (bitcoinaddress) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; } diff --git a/backend/src/api/explorer/channels.api.ts b/backend/src/api/explorer/channels.api.ts index 514239d2b..943ef0a12 100644 --- a/backend/src/api/explorer/channels.api.ts +++ b/backend/src/api/explorer/channels.api.ts @@ -53,7 +53,7 @@ class ChannelsApi { GROUP BY nodes_1.public_key, nodes_2.public_key ORDER BY channels.capacity DESC LIMIT 10000 - `; + `; } const [rows]: any = await DB.query(query, params); @@ -241,10 +241,10 @@ class ChannelsApi { let [feeRates2]: any = await DB.query(query); feeRates2 = feeRates2.map(rate => rate.node2_fee_rate); - let feeRates = (feeRates1.concat(feeRates2)).sort((a, b) => a - b); + const feeRates = (feeRates1.concat(feeRates2)).sort((a, b) => a - b); let avgFeeRate = 0; for (const rate of feeRates) { - avgFeeRate += rate; + avgFeeRate += rate; } avgFeeRate /= feeRates.length; const medianFeeRate = feeRates[Math.floor(feeRates.length / 2)]; @@ -257,14 +257,14 @@ class ChannelsApi { let [baseFees2]: any = await DB.query(query); baseFees2 = baseFees2.map(rate => rate.node2_base_fee_mtokens); - let baseFees = (baseFees1.concat(baseFees2)).sort((a, b) => a - b); + const baseFees = (baseFees1.concat(baseFees2)).sort((a, b) => a - b); let avgBaseFee = 0; for (const fee of baseFees) { - avgBaseFee += fee; + avgBaseFee += fee; } avgBaseFee /= baseFees.length; const medianBaseFee = feeRates[Math.floor(baseFees.length / 2)]; - + return { avgCapacity: parseInt(avgCapacity[0].avgCapacity, 10), avgFeeRate: avgFeeRate, @@ -272,7 +272,7 @@ class ChannelsApi { medianCapacity: medianCapacity, medianFeeRate: medianFeeRate, medianBaseFee: medianBaseFee, - } + }; } catch (e) { logger.err(`Cannot calculate channels statistics. Reason: ${e instanceof Error ? e.message : e}`); @@ -456,7 +456,7 @@ class ChannelsApi { allChannels = allChannels.slice(0, 1000); } - const channels: any[] = [] + const channels: any[] = []; for (const row of allChannels) { let channel; if (index >= 0) { diff --git a/backend/src/api/explorer/nodes.api.ts b/backend/src/api/explorer/nodes.api.ts index 22c854fcc..eba6ff516 100644 --- a/backend/src/api/explorer/nodes.api.ts +++ b/backend/src/api/explorer/nodes.api.ts @@ -34,7 +34,7 @@ class NodesApi { `; const [maximums]: any[] = await DB.query(query); - + return { maxLiquidity: maximums[0].maxLiquidity, maxChannels: maximums[0].maxChannels, @@ -78,7 +78,7 @@ class NodesApi { node.city = JSON.parse(node.city); node.country = JSON.parse(node.country); - // Features + // Features node.features = JSON.parse(node.features); node.featuresBits = null; if (node.features) { @@ -87,7 +87,7 @@ class NodesApi { maxBit = Math.max(maxBit, feature.bit); } maxBit = Math.ceil(maxBit / 4) * 4 - 1; - + node.featuresBits = new Array(maxBit + 1).fill(0); for (const feature of node.features) { node.featuresBits[feature.bit] = 1; @@ -394,7 +394,7 @@ class NodesApi { try { const publicKeySearch = search.replace(/[^a-zA-Z0-9]/g, '') + '%'; const aliasSearch = search - .replace(/[-_.]/g, ' ') // Replace all -_. characters with empty space. Eg: "ln.nicehash" becomes "ln nicehash". + .replace(/[-_.]/g, ' ') // Replace all -_. characters with empty space. Eg: "ln.nicehash" becomes "ln nicehash". .replace(/[^a-zA-Z0-9 ]/g, '') // Remove all special characters and keep just A to Z, 0 to 9. .split(' ') .filter(key => key.length) @@ -455,7 +455,7 @@ class NodesApi { } else if (ispList[isp2].ids.includes(channel.isp2ID) === false) { ispList[isp2].ids.push(channel.isp2ID); } - + ispList[isp1].capacity += channel.capacity; ispList[isp1].channels += 1; ispList[isp1].nodes[channel.node1PublicKey] = true; @@ -463,7 +463,7 @@ class NodesApi { ispList[isp2].channels += 1; ispList[isp2].nodes[channel.node2PublicKey] = true; } - + const ispRanking: any[] = []; for (const isp of Object.keys(ispList)) { ispRanking.push([ @@ -494,7 +494,7 @@ class NodesApi { `; const [clearnetCapacity]: any = await DB.query(query); - // Get the total capacity of all channels which have both nodes on Tor + // Get the total capacity of all channels which have both nodes on Tor query = ` SELECT SUM(capacity) as capacity FROM ( @@ -642,11 +642,11 @@ class NodesApi { for (const country of nodesCountPerCountry) { nodesPerCountry.push({ name: JSON.parse(country.names), - iso: country.iso_code, + iso: country.iso_code, count: country.nodesCount, share: Math.floor(country.nodesCount / nodesWithAS[0].total * 10000) / 100, capacity: country.capacity, - }) + }); } return nodesPerCountry; @@ -665,7 +665,7 @@ class NodesApi { if ((node.last_update ?? 0) < 1514736061) { // January 1st 2018 node.last_update = null; } - + const uniqueAddr = [...new Set(node.addresses?.map(a => a.addr))]; const formattedSockets = (uniqueAddr.join(',')) ?? ''; diff --git a/backend/src/api/explorer/nodes.routes.ts b/backend/src/api/explorer/nodes.routes.ts index 6f9539fcb..113e29b9a 100644 --- a/backend/src/api/explorer/nodes.routes.ts +++ b/backend/src/api/explorer/nodes.routes.ts @@ -39,7 +39,7 @@ class NodesRoutes { private async $getNodeGroup(req: Request, res: Response) { try { let nodesList; - let nodes: any[] = []; + const nodes: any[] = []; switch (config.MEMPOOL.NETWORK) { case 'testnet': nodesList = [ @@ -174,7 +174,7 @@ class NodesRoutes { ]; } - for (let pubKey of nodesList) { + for (const pubKey of nodesList) { try { const node = await nodesApi.$getNode(pubKey); if (node) { diff --git a/backend/src/api/fetch-version.ts b/backend/src/api/fetch-version.ts index cb0813c35..7183007a8 100644 --- a/backend/src/api/fetch-version.ts +++ b/backend/src/api/fetch-version.ts @@ -1,5 +1,5 @@ import fs from 'fs'; -import path from "path"; +import path from 'path'; const { spawnSync } = require('child_process'); function getVersion(): string { @@ -29,9 +29,9 @@ function getGitCommit(): string { const versionInfo = { version: getVersion(), gitCommit: getGitCommit() -} +}; fs.writeFileSync( path.join(__dirname, 'version.json'), - JSON.stringify(versionInfo, null, 2) + "\n" + JSON.stringify(versionInfo, null, 2) + '\n' ); diff --git a/backend/src/api/lightning/clightning/clightning-client.ts b/backend/src/api/lightning/clightning/clightning-client.ts index d80341063..28fc8e9f3 100644 --- a/backend/src/api/lightning/clightning/clightning-client.ts +++ b/backend/src/api/lightning/clightning/clightning-client.ts @@ -116,7 +116,7 @@ class LightningError extends Error { const defaultRpcPath = path.join(homedir(), '.lightning') , fStat = (...p) => statSync(path.join(...p)) - , fExists = (...p) => existsSync(path.join(...p)) + , fExists = (...p) => existsSync(path.join(...p)); export default class CLightningClient extends EventEmitter implements AbstractLightningApi { private rpcPath: string; @@ -141,9 +141,9 @@ export default class CLightningClient extends EventEmitter implements AbstractLi // main data directory provided, default to using the bitcoin mainnet subdirectory // to be removed in v0.2.0 else if (fExists(rpcPath, 'bitcoin', 'lightning-rpc')) { - logger.warn(`${rpcPath}/lightning-rpc is missing, using the bitcoin mainnet subdirectory at ${rpcPath}/bitcoin instead.`, logger.tags.ln) - logger.warn(`specifying the main lightning data directory is deprecated, please specify the network directory explicitly.\n`, logger.tags.ln) - rpcPath = path.join(rpcPath, 'bitcoin', 'lightning-rpc') + logger.warn(`${rpcPath}/lightning-rpc is missing, using the bitcoin mainnet subdirectory at ${rpcPath}/bitcoin instead.`, logger.tags.ln); + logger.warn(`specifying the main lightning data directory is deprecated, please specify the network directory explicitly.\n`, logger.tags.ln); + rpcPath = path.join(rpcPath, 'bitcoin', 'lightning-rpc'); } } diff --git a/backend/src/api/lightning/lnd/lnd-api.ts b/backend/src/api/lightning/lnd/lnd-api.ts index f4099e82b..eb48b5f96 100644 --- a/backend/src/api/lightning/lnd/lnd-api.ts +++ b/backend/src/api/lightning/lnd/lnd-api.ts @@ -46,10 +46,10 @@ class LndApi implements AbstractLightningApi { for (const node of graph.nodes) { const nodeFeatures: ILightningApi.Feature[] = []; - for (const bit in node.features) { + for (const bit in node.features) { nodeFeatures.push({ bit: parseInt(bit, 10), - name: node.features[bit].name, + name: node.features[bit].name, is_required: node.features[bit].is_required, is_known: node.features[bit].is_known, }); diff --git a/backend/src/api/liquid/elements-parser.ts b/backend/src/api/liquid/elements-parser.ts index 727865b95..0e5818ab0 100644 --- a/backend/src/api/liquid/elements-parser.ts +++ b/backend/src/api/liquid/elements-parser.ts @@ -87,7 +87,7 @@ class ElementsParser { logger.debug(`Saved L-BTC peg from Liquid block height #${height} with TXID ${txid}.`); if (amount > 0) { // Peg-in - + // Add the address to the federation addresses table await DB.query(`INSERT IGNORE INTO federation_addresses (bitcoinaddress) VALUES (?)`, [bitcoinaddress]); @@ -95,7 +95,7 @@ class ElementsParser { const query_utxos = `INSERT IGNORE INTO federation_txos (txid, txindex, bitcoinaddress, amount, blocknumber, blocktime, unspent, lastblockupdate, lasttimeupdate, timelock, expiredAt, emergencyKey, pegtxid, pegindex, pegblocktime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`; const params_utxos: (string | number)[] = [bitcointxid, bitcoinindex, bitcoinaddress, amount, bitcoinblock, bitcoinBlockTime, 1, bitcoinblock - 1, 0, 4032, 0, 0, txid, txindex, blockTime]; await DB.query(query_utxos, params_utxos); - const [minBlockUpdate] = await DB.query(`SELECT MIN(lastblockupdate) AS lastblockupdate FROM federation_txos WHERE unspent = 1`) + const [minBlockUpdate] = await DB.query(`SELECT MIN(lastblockupdate) AS lastblockupdate FROM federation_txos WHERE unspent = 1`); await this.$saveLastBlockAuditToDatabase(minBlockUpdate[0]['lastblockupdate']); logger.debug(`Saved new Federation UTXO ${bitcointxid}:${bitcoinindex} belonging to ${bitcoinaddress} to federation txos`); @@ -174,7 +174,7 @@ class ElementsParser { const runningFor = (Date.now() / 1000) - startedAt; const blockPerSeconds = indexedThisRun / elapsedSeconds; indexingSpeeds.push(blockPerSeconds); - if (indexingSpeeds.length > 100) indexingSpeeds.shift(); // Keep the length of the up to 100 last indexing speeds + if (indexingSpeeds.length > 100) {indexingSpeeds.shift();} // Keep the length of the up to 100 last indexing speeds const meanIndexingSpeed = indexingSpeeds.reduce((a, b) => a + b, 0) / indexingSpeeds.length; const eta = (auditProgress.confirmedTip - auditProgress.lastBlockAudit) / meanIndexingSpeed; logger.debug(`Scanning ${utxos.length} Federation UTXOs and ${redeemAddresses.length} Peg-Out Addresses at Bitcoin block height #${auditProgress.lastBlockAudit} / #${auditProgress.confirmedTip} | ~${meanIndexingSpeed.toFixed(2)} blocks/sec | elapsed: ${(runningFor / 60).toFixed(0)} minutes | ETA: ${(eta / 60).toFixed(0)} minutes`); @@ -189,7 +189,7 @@ class ElementsParser { await this.$parseBitcoinBlock(block, spentAsTip, unspentAsTip, auditProgress.confirmedTip, redeemAddresses); // Finally, update the lastblockupdate of the remaining UTXOs and save to the database - const [minBlockUpdate] = await DB.query(`SELECT MIN(lastblockupdate) AS lastblockupdate FROM federation_txos WHERE unspent = 1`) + const [minBlockUpdate] = await DB.query(`SELECT MIN(lastblockupdate) AS lastblockupdate FROM federation_txos WHERE unspent = 1`); await this.$saveLastBlockAuditToDatabase(minBlockUpdate[0]['lastblockupdate']); auditProgress = await this.$getAuditProgress(); @@ -201,11 +201,11 @@ class ElementsParser { } catch (e) { this.isUtxosUpdatingRunning = false; throw new Error(e instanceof Error ? e.message : 'Error'); - } + } } // Get the UTXOs that need to be scanned in block height (UTXOs that were last updated in the block height - 1) - protected async $getFederationUtxosToScan(height: number) { + protected async $getFederationUtxosToScan(height: number) { const query = `SELECT txid, txindex, bitcoinaddress, amount, blocknumber, timelock, expiredAt FROM federation_txos WHERE lastblockupdate = ? AND unspent = 1`; const [rows] = await DB.query(query, [height - 1]); return rows as any[]; @@ -220,7 +220,7 @@ class ElementsParser { const result = await bitcoinSecondClient.getTxOut(utxo.txid, utxo.txindex, false); result ? unspentAsTip.push(utxo) : spentAsTip.push(utxo); } - + return {spentAsTip, unspentAsTip}; } @@ -296,7 +296,7 @@ class ElementsParser { } } - for (const utxo of spentAsTip) { + for (const utxo of spentAsTip) { if (utxo.expiredAt === 0 && block.height >= utxo.blocknumber + utxo.timelock) { // The UTXO is expiring in this block await DB.query(`UPDATE federation_txos SET lastblockupdate = ?, expiredAt = ? WHERE txid = ? AND txindex = ?`, [block.height, block.time, utxo.txid, utxo.txindex]); } else { @@ -308,7 +308,7 @@ class ElementsParser { if (utxo.expiredAt === 0 && block.height >= utxo.blocknumber + utxo.timelock) { // The UTXO is expiring in this block await DB.query(`UPDATE federation_txos SET unspent = 0, lastblockupdate = ?, expiredAt = ? WHERE txid = ? AND txindex = ?`, [confirmedTip, block.time, utxo.txid, utxo.txindex]); } else if (utxo.expiredAt === 0 && confirmedTip >= utxo.blocknumber + utxo.timelock) { // The UTXO is expiring before the tip: we need to keep track of it - await DB.query(`UPDATE federation_txos SET lastblockupdate = ? WHERE txid = ? AND txindex = ?`, [utxo.blocknumber + utxo.timelock - 1, utxo.txid, utxo.txindex]); + await DB.query(`UPDATE federation_txos SET lastblockupdate = ? WHERE txid = ? AND txindex = ?`, [utxo.blocknumber + utxo.timelock - 1, utxo.txid, utxo.txindex]); } else { await DB.query(`UPDATE federation_txos SET lastblockupdate = ? WHERE txid = ? AND txindex = ?`, [confirmedTip, utxo.txid, utxo.txindex]); } @@ -336,7 +336,7 @@ class ElementsParser { return { bitcoinBlocks: result.blocks, bitcoinHeaders: result.headers, - } + }; } protected async $getLastBlockAudit(): Promise { @@ -384,7 +384,7 @@ class ElementsParser { AND (expiredAt = 0 OR expiredAt > UNIX_TIMESTAMP(LAST_DAY(FROM_UNIXTIME(blocktime)) + INTERVAL 1 DAY)) GROUP BY - date;`; + date;`; const [rows] = await DB.query(query); return rows; } @@ -444,7 +444,7 @@ class ElementsParser { const [rows] = await DB.query(query); return rows; } - + // Get the total number of federation addresses public async $getFederationAddressesNumber(): Promise { const query = `SELECT COUNT(DISTINCT bitcoinaddress) AS address_count FROM federation_txos WHERE unspent = 1 AND expiredAt = 0;`; diff --git a/backend/src/api/liquid/liquid.routes.ts b/backend/src/api/liquid/liquid.routes.ts index 563cbaced..3c99900b3 100644 --- a/backend/src/api/liquid/liquid.routes.ts +++ b/backend/src/api/liquid/liquid.routes.ts @@ -14,7 +14,7 @@ class LiquidRoutes { .get(config.MEMPOOL.API_URL_PREFIX + 'asset/:assetId/icon', this.getLiquidIcon) .get(config.MEMPOOL.API_URL_PREFIX + 'assets/group/:id', this.$getAssetGroup) ; - + if (config.DATABASE.ENABLED) { app .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs', this.$getElementsPegs) diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 34a27f510..ac9b4ba52 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -38,7 +38,7 @@ class Mempool { private mempoolProtection = 0; private latestTransactions: any[] = []; - private ESPLORA_MISSING_TX_WARNING_THRESHOLD = 100; + private ESPLORA_MISSING_TX_WARNING_THRESHOLD = 100; private SAMPLE_TIME = 10000; // In ms private timer = new Date().getTime(); private missingTxCount = 0; @@ -51,15 +51,15 @@ class Mempool { // Initialize mempoolInfo here to avoid circular dependency issues // Use config directly instead of Common.isLiquid() to break circular dependency const isLiquid = config.MEMPOOL.NETWORK === 'liquid' || config.MEMPOOL.NETWORK === 'liquidtestnet'; - this.mempoolInfo = { - loaded: false, - size: 0, - bytes: 0, - usage: 0, + this.mempoolInfo = { + loaded: false, + size: 0, + bytes: 0, + usage: 0, total_fee: 0, - maxmempool: 300000000, - mempoolminfee: isLiquid ? 0.00000100 : 0.00001000, - minrelaytxfee: isLiquid ? 0.00000100 : 0.00001000 + maxmempool: 300000000, + mempoolminfee: isLiquid ? 0.00000100 : 0.00001000, + minrelaytxfee: isLiquid ? 0.00000100 : 0.00001000 }; this.txPerSecondInterval = setInterval(this.updateTxPerSecond.bind(this), 1000); } diff --git a/backend/src/api/mining/mining-routes.ts b/backend/src/api/mining/mining-routes.ts index 806b113f1..d63b13a08 100644 --- a/backend/src/api/mining/mining-routes.ts +++ b/backend/src/api/mining/mining-routes.ts @@ -1,12 +1,12 @@ import { Application, Request, Response } from 'express'; -import config from "../../config"; +import config from '../../config'; import logger from '../../logger'; import BlocksAuditsRepository from '../../repositories/BlocksAuditsRepository'; import BlocksRepository from '../../repositories/BlocksRepository'; import DifficultyAdjustmentsRepository from '../../repositories/DifficultyAdjustmentsRepository'; import HashratesRepository from '../../repositories/HashratesRepository'; import bitcoinClient from '../bitcoin/bitcoin-client'; -import mining from "./mining"; +import mining from './mining'; import PricesRepository from '../../repositories/PricesRepository'; import AccelerationRepository from '../../repositories/AccelerationRepository'; import accelerationApi from '../services/acceleration'; diff --git a/backend/src/api/mining/mining.ts b/backend/src/api/mining/mining.ts index 2b007e9c5..ef58b6cd9 100644 --- a/backend/src/api/mining/mining.ts +++ b/backend/src/api/mining/mining.ts @@ -26,7 +26,7 @@ class Mining { private blocksPriceIndexingRunning = false; public lastHashrateIndexingDate: number | null = null; public lastWeeklyHashrateIndexingDate: number | null = null; - + public reindexHashrateRequested = false; public reindexDifficultyAdjustmentRequested = false; @@ -66,7 +66,7 @@ class Mining { {from, to} ); } - + /** * Get historical block rewards */ @@ -175,8 +175,8 @@ class Mining { const blockCount1w: number = await BlocksRepository.$blockCount(pool.id, '1w'); const totalBlock1w: number = await BlocksRepository.$blockCount(null, '1w'); - const avgHealth = await BlocksRepository.$getAvgBlockHealthPerPoolId(pool.id); - const totalReward = await BlocksRepository.$getTotalRewardForPoolId(pool.id); + const avgHealth = await BlocksRepository.$getAvgBlockHealthPerPoolId(pool.id); + const totalReward = await BlocksRepository.$getTotalRewardForPoolId(pool.id); let currentEstimatedHashrate = 0; try { @@ -235,7 +235,7 @@ class Mining { const indexedTimestamp = await HashratesRepository.$getWeeklyHashrateTimestamps(); const hashrates: any[] = []; - + const lastMonday = new Date(now.setDate(now.getDate() - (now.getDay() + 6) % 7)); const lastMondayMidnight = this.getDateMidnight(lastMonday); let toTimestamp = lastMondayMidnight.getTime(); @@ -537,7 +537,7 @@ class Mining { let totalInserted = 0; try { - const prices: any[] = await PricesRepository.$getPricesTimesAndId(); + const prices: any[] = await PricesRepository.$getPricesTimesAndId(); const blocksWithoutPrices: any[] = await BlocksRepository.$getBlocksWithoutPrice(); const blocksPrices: BlockPrice[] = []; @@ -609,11 +609,11 @@ class Mining { while (currentBlockHeight > 0) { const indexedBlocks = await BlocksRepository.$getBlocksMissingCoinStatsIndex( currentBlockHeight, currentBlockHeight - 10000); - + for (const block of indexedBlocks) { const txoutset = await bitcoinClient.getTxoutSetinfo('none', block.height); await BlocksRepository.$updateCoinStatsIndexData(block.hash, txoutset.txouts, - Math.round(txoutset.block_info.prevout_spent * 100000000)); + Math.round(txoutset.block_info.prevout_spent * 100000000)); ++totalIndexed; const elapsedSeconds = Math.max(1, new Date().getTime() / 1000 - timer); @@ -688,7 +688,7 @@ class Mining { default: return 1 * scale; } } - + // Finds the oldest block in a consecutive chain back from the tip // assumes `blocks` is sorted in ascending height order diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts index edd22a582..31c5c5e9c 100644 --- a/backend/src/api/rbf-cache.ts +++ b/backend/src/api/rbf-cache.ts @@ -1,10 +1,10 @@ -import config from "../config"; -import logger from "../logger"; -import { MempoolTransactionExtended, TransactionStripped } from "../mempool.interfaces"; +import config from '../config'; +import logger from '../logger'; +import { MempoolTransactionExtended, TransactionStripped } from '../mempool.interfaces'; import bitcoinApi from './bitcoin/bitcoin-api-factory'; -import { IEsploraApi } from "./bitcoin/esplora-api.interface"; -import { Common } from "./common"; -import redisCache from "./redis-cache"; +import { IEsploraApi } from './bitcoin/esplora-api.interface'; +import { Common } from './common'; +import redisCache from './redis-cache'; export interface RbfTransaction extends TransactionStripped { rbf?: boolean; diff --git a/backend/src/api/statistics/statistics-api.ts b/backend/src/api/statistics/statistics-api.ts index fa13b60b9..5a3222e82 100644 --- a/backend/src/api/statistics/statistics-api.ts +++ b/backend/src/api/statistics/statistics-api.ts @@ -514,7 +514,7 @@ class StatisticsApi { vsize_1600: completeVsizes[36], vsize_1800: completeVsizes[37], vsize_2000: completeVsizes[38], - } + }; }); } } diff --git a/backend/src/api/transaction-utils.ts b/backend/src/api/transaction-utils.ts index da9e908e8..bc5b65607 100644 --- a/backend/src/api/transaction-utils.ts +++ b/backend/src/api/transaction-utils.ts @@ -116,7 +116,7 @@ class TransactionUtils { public extendMempoolTransaction(transaction: IEsploraApi.Transaction): MempoolTransactionExtended { const vsize = Math.ceil(transaction.weight / 4); const fractionalVsize = (transaction.weight / 4); - let sigops = Common.isLiquid() ? 0 : (transaction.sigops != null ? transaction.sigops : this.countSigops(transaction)); + const sigops = Common.isLiquid() ? 0 : (transaction.sigops != null ? transaction.sigops : this.countSigops(transaction)); // https://github.com/bitcoin/bitcoin/blob/e9262ea32a6e1d364fb7974844fadc36f931f8c6/src/policy/policy.cpp#L295-L298 const adjustedVsize = Math.max(fractionalVsize, sigops * 5); // adjusted vsize = Max(weight, sigops * bytes_per_sigop) / witness_scale_factor const feePerVbytes = (transaction.fee || 0) / fractionalVsize; @@ -365,7 +365,7 @@ class TransactionUtils { * the script item if it is a script spend. */ public witnessToP2TRScript(witness: string[]): string | null { - if (witness.length < 2) return null; + if (witness.length < 2) {return null;} // Note: see BIP341 for parsing details of witness stack // If there are at least two witness elements, and the first byte of the @@ -375,7 +375,7 @@ class TransactionUtils { // If there are at least two witness elements left, script path spending is used. // Call the second-to-last stack element s, the script. // (Note: this phrasing from BIP341 assumes we've *removed* the annex from the stack) - if (hasAnnex && witness.length < 3) return null; + if (hasAnnex && witness.length < 3) {return null;} const positionOfScript = hasAnnex ? witness.length - 3 : witness.length - 2; return witness[positionOfScript]; } @@ -482,7 +482,7 @@ class TransactionUtils { return 'unknown'; } } - + } export default new TransactionUtils(); diff --git a/backend/src/api/tx-selection-worker.ts b/backend/src/api/tx-selection-worker.ts index 8ac7328fe..98dd42909 100644 --- a/backend/src/api/tx-selection-worker.ts +++ b/backend/src/api/tx-selection-worker.ts @@ -18,7 +18,7 @@ if (parentPort) { mempool.delete(uid); }); } - + const { blocks, rates, clusters } = makeBlockTemplates(mempool); // return the result to main thread. @@ -38,7 +38,7 @@ function makeBlockTemplates(mempool: Map) const auditPool: Map = new Map(); const mempoolArray: AuditTransaction[] = []; const cpfpClusters: Map = new Map(); - + mempool.forEach(tx => { tx.dirty = false; // initializing everything up front helps V8 optimize property access later @@ -85,7 +85,7 @@ function makeBlockTemplates(mempool: Map) // (i.e. the package rooted in the transaction with the best ancestor score) const blocks: number[][] = []; let blockWeight = 4000; - let blockSigops = 0; + const blockSigops = 0; let transactions: AuditTransaction[] = []; const modified: PairingHeap = new PairingHeap((a, b): boolean => { if (a.score === b.score) { diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 532d6d4a1..6186932b2 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -1002,7 +1002,7 @@ class WebsocketHandler { }); } } - + async handleNewBlock(block: BlockExtended, txIds: string[], transactions: MempoolTransactionExtended[]): Promise { if (!this.webSocketServers.length) { throw new Error('No WebSocket.Server have been set'); @@ -1518,7 +1518,7 @@ class WebsocketHandler { if (client['track-rbf']) { numRbfSubs++; } - }) + }); } let count = 0; diff --git a/backend/src/config.ts b/backend/src/config.ts index 3fe3db2ee..f7f8b371b 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -398,7 +398,7 @@ class Config implements IConfig { }); return next; }); - } + }; } export default new Config(); diff --git a/backend/src/indexer.ts b/backend/src/indexer.ts index ca0b2303c..d4d2197e1 100644 --- a/backend/src/indexer.ts +++ b/backend/src/indexer.ts @@ -46,7 +46,7 @@ class Indexer { synced: indexes[indexName].synced, best_block_height: indexes[indexName].best_block_height, }; - logger.info(`Core index '${indexName}' is ${indexes[indexName].synced ? 'synced' : 'not synced'}. Best block height is ${indexes[indexName].best_block_height}`); + logger.info(`Core index '${indexName}' is ${indexes[indexName].synced ? 'synced' : 'not synced'}. Best block height is ${indexes[indexName].best_block_height}`); updatedCoreIndexes.push(newState); if (indexName === 'coinstatsindex' && newState.synced === true) { @@ -62,9 +62,9 @@ class Indexer { /** * Return the best block height if a core index is available, or 0 if not - * - * @param name - * @returns + * + * @param name + * @returns */ public isCoreIndexReady(name: string): CoreIndex | null { for (const index of this.coreIndexes) { diff --git a/backend/src/logger.ts b/backend/src/logger.ts index 27aa942e6..879dbab5b 100644 --- a/backend/src/logger.ts +++ b/backend/src/logger.ts @@ -36,7 +36,7 @@ class Logger { mining: 'Mining', ln: 'Lightning', goggles: 'Goggles', - }; + }; // @ts-ignore public emerg: ((msg: string, tag?: string) => void); @@ -86,7 +86,7 @@ class Logger { private getNetwork(): string { if (config.LIGHTNING.ENABLED) { - return config.MEMPOOL.NETWORK === 'mainnet' ? 'lightning' : `${config.MEMPOOL.NETWORK}-lightning`; + return config.MEMPOOL.NETWORK === 'mainnet' ? 'lightning' : `${config.MEMPOOL.NETWORK}-lightning`; } if (config.MEMPOOL.NETWORK && config.MEMPOOL.NETWORK !== 'mainnet') { return config.MEMPOOL.NETWORK; diff --git a/backend/src/replication/StatisticsReplication.ts b/backend/src/replication/StatisticsReplication.ts index 49259b458..59ecf202f 100644 --- a/backend/src/replication/StatisticsReplication.ts +++ b/backend/src/replication/StatisticsReplication.ts @@ -51,12 +51,12 @@ class StatisticsReplication { logger.info(`Statistics table is complete, no replication needed`, 'Replication'); return; } - + for (const interval of missingIntervals) { logger.debug(`Missing ${missingStatistics[interval].size} statistics rows in '${interval}' timespan`, 'Replication'); } logger.debug(`Fetching ${missingIntervals.join(', ')} statistics endpoints from trusted servers to fill ${totalMissing} rows missing in statistics`, 'Replication'); - + let totalSynced = 0; let totalMissed = 0; @@ -75,15 +75,15 @@ class StatisticsReplication { } private async $syncStatistics(interval: string, missingTimes: Set): Promise { - + let success = false; let synced = 0; - let missed = new Set(missingTimes); + const missed = new Set(missingTimes); const syncResult = await $sync(`/api/v1/statistics/${interval}`); if (syncResult && syncResult.data?.length) { success = true; - logger.info(`Fetched /api/v1/statistics/${interval} from ${syncResult.server}`); - + logger.info(`Fetched /api/v1/statistics/${interval} from ${syncResult.server}`); + for (const stat of syncResult.data) { const time = this.roundToNearestStep(stat.added, steps[interval]); if (missingTimes.has(time)) { @@ -129,7 +129,7 @@ class StatisticsReplication { startTime < now - day * 30 ? [now - day * 90, now - day * 30, '3m' ] : null, // from 3 months ago to 1 month ago = 2 hours granularity startTime < now - day * 90 ? [now - day * 180, now - day * 90, '6m' ] : null, // from 6 months ago to 3 months ago = 3 hours granularity startTime < now - day * 180 ? [now - day * 365 * 2, now - day * 180, '2y' ] : null, // from 2 years ago to 6 months ago = 8 hours granularity - startTime < now - day * 365 * 2 ? [startTime, now - day * 365 * 2, 'all'] : null, // from start of statistics to 2 years ago = 12 hours granularity + startTime < now - day * 365 * 2 ? [startTime, now - day * 365 * 2, 'all'] : null, // from start of statistics to 2 years ago = 12 hours granularity ]; for (const interval of intervals) { @@ -138,7 +138,7 @@ class StatisticsReplication { } missingStatistics[interval[2] as string] = await this.$getMissingStatisticsInterval(interval, startTime); } - + return missingStatistics; } catch (e: any) { logger.err(`Cannot fetch missing statistics times from db. Reason: ` + (e instanceof Error ? e.message : e)); @@ -169,17 +169,17 @@ class StatisticsReplication { if (timeSteps.length === 0) { return new Set(); } - + const roundedTimesAlreadyHere: number[] = Array.from(new Set(rows.map(row => this.roundToNearestStep(row.added, step)))); const missingTimes = timeSteps.filter(time => !roundedTimesAlreadyHere.includes(time)).filter((time, i, arr) => { // Remove outsiders if (i === 0) { - return arr[i + 1] === time + step + return arr[i + 1] === time + step; } else if (i === arr.length - 1) { return arr[i - 1] === time - step; } - return (arr[i + 1] === time + step) && (arr[i - 1] === time - step) + return (arr[i + 1] === time + step) && (arr[i - 1] === time - step); }); // Don't bother fetching if very few rows are missing diff --git a/backend/src/replication/replicator.ts b/backend/src/replication/replicator.ts index ac204efcc..df90a7d05 100644 --- a/backend/src/replication/replicator.ts +++ b/backend/src/replication/replicator.ts @@ -14,7 +14,7 @@ export async function $sync(path): Promise<{ data?: any, exists: boolean, server if (server === backendInfo.getBackendInfo().hostname) { continue; } - + try { const result = await query(`https://${server}${path}`); if (result) { diff --git a/backend/src/repositories/AccelerationRepository.ts b/backend/src/repositories/AccelerationRepository.ts index aa39c8929..76926839f 100644 --- a/backend/src/repositories/AccelerationRepository.ts +++ b/backend/src/repositories/AccelerationRepository.ts @@ -100,7 +100,7 @@ class AccelerationRepository { SELECT *, UNIX_TIMESTAMP(requested) as requested_timestamp, UNIX_TIMESTAMP(added) as block_timestamp FROM accelerations JOIN pools on pools.unique_id = accelerations.pool `; - let params: any[] = []; + const params: any[] = []; let hasFilter = false; if (interval && height === null) { @@ -163,7 +163,7 @@ class AccelerationRepository { SELECT SUM(boost_cost) as total_cost, COUNT(txid) as count FROM accelerations JOIN pools on pools.unique_id = accelerations.pool `; - let params: any[] = []; + const params: any[] = []; let hasFilter = false; if (interval) { @@ -346,7 +346,7 @@ class AccelerationRepository { const accelerationSummaries = accelerations.map(acc => ({ ...acc, pools: acc.pools, - })) + })); for (const acc of accelerations) { if (blockTxs[acc.txid] && acc.pools.includes(block.extras.pool.id)) { const tx = blockTxs[acc.txid]; diff --git a/backend/src/repositories/BlocksAuditsRepository.ts b/backend/src/repositories/BlocksAuditsRepository.ts index 3b3f79ce0..7250304c1 100644 --- a/backend/src/repositories/BlocksAuditsRepository.ts +++ b/backend/src/repositories/BlocksAuditsRepository.ts @@ -94,7 +94,7 @@ class BlocksAuditRepositories { JOIN blocks_templates ON blocks_templates.id = blocks_audits.hash WHERE blocks_audits.hash = ? `, [hash]); - + if (rows.length) { rows[0].unseenTxs = JSON.parse(rows[0].unseenTxs); rows[0].missingTxs = JSON.parse(rows[0].missingTxs); diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 2994dd8f4..8f2579b48 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -217,9 +217,9 @@ class BlocksRepository { /** * Save newly indexed data from core coinstatsindex - * - * @param utxoSetSize - * @param totalInputAmt + * + * @param utxoSetSize + * @param totalInputAmt */ public async $updateCoinStatsIndexData(blockHash: string, utxoSetSize: number, totalInputAmt: number @@ -245,9 +245,9 @@ class BlocksRepository { /** * Update missing fee amounts fields * - * @param blockHash - * @param feeAmtPercentiles - * @param medianFeeAmt + * @param blockHash + * @param feeAmtPercentiles + * @param medianFeeAmt */ public async $updateFeeAmounts(blockHash: string, feeAmtPercentiles, medianFeeAmt) : Promise { try { @@ -275,7 +275,7 @@ class BlocksRepository { // Ensure startHeight is the lower value and endHeight is the higher value const minHeight = Math.min(startHeight, endHeight); const maxHeight = Math.max(startHeight, endHeight); - + if (minHeight === maxHeight) { return []; } @@ -410,7 +410,7 @@ class BlocksRepository { */ public async $blockCountBetweenHeight(startHeight: number, endHeight: number): Promise { const params: any[] = []; - let query = `SELECT count(height) as blockCount + const query = `SELECT count(height) as blockCount FROM blocks WHERE height <= ${startHeight} AND height >= ${endHeight} AND stale = 0`; @@ -1028,9 +1028,9 @@ class BlocksRepository { /** * Save indexed median fee to avoid recomputing it later - * - * @param id - * @param feePercentiles + * + * @param id + * @param feePercentiles */ public async $saveFeePercentilesForBlockId(id: string, feePercentiles: number[]): Promise { try { @@ -1047,9 +1047,9 @@ class BlocksRepository { /** * Save indexed effective fee statistics - * - * @param id - * @param feeStats + * + * @param id + * @param feeStats */ public async $saveEffectiveFeeStats(id: string, feeStats: EffectiveFeeStats): Promise { try { @@ -1066,7 +1066,7 @@ class BlocksRepository { /** * Save coinbase addresses - * + * * @param id * @param addresses */ @@ -1085,7 +1085,7 @@ class BlocksRepository { /** * Save pool - * + * * @param id * @param poolId */ @@ -1104,8 +1104,8 @@ class BlocksRepository { /** * Save block first seen time - * - * @param id + * + * @param id */ public async $saveFirstSeenTime(id: string, firstSeen: number): Promise { try { @@ -1122,7 +1122,7 @@ class BlocksRepository { /** * Change which block at a height belongs to the canonical chain - * + * * @param hash * @param height */ @@ -1151,8 +1151,8 @@ class BlocksRepository { /** * Convert a mysql row block into a BlockExtended. Note that you * must provide the correct field into dbBlk object param - * - * @param dbBlk + * + * @param dbBlk */ private async formatDbBlockIntoExtendedBlock(dbBlk: DatabaseBlock): Promise { const blk: Partial = {}; diff --git a/backend/src/repositories/BlocksSummariesRepository.ts b/backend/src/repositories/BlocksSummariesRepository.ts index d0e3db848..4ab26d2dd 100644 --- a/backend/src/repositories/BlocksSummariesRepository.ts +++ b/backend/src/repositories/BlocksSummariesRepository.ts @@ -154,8 +154,8 @@ class BlocksSummariesRepository { /** * Get the fee percentiles if the block has already been indexed, [] otherwise - * - * @param id + * + * @param id */ public async $getFeePercentilesByBlockId(id: string): Promise { try { diff --git a/backend/src/repositories/HashratesRepository.ts b/backend/src/repositories/HashratesRepository.ts index 93aa2d53f..b1297bfda 100644 --- a/backend/src/repositories/HashratesRepository.ts +++ b/backend/src/repositories/HashratesRepository.ts @@ -215,7 +215,7 @@ class HashratesRepository { logger.err('Cannot delete latest hashrates data points. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); } } - + /** * Delete hashrates from the database from timestamp */ diff --git a/backend/src/repositories/PoolsRepository.ts b/backend/src/repositories/PoolsRepository.ts index c6625775d..b97fa951d 100644 --- a/backend/src/repositories/PoolsRepository.ts +++ b/backend/src/repositories/PoolsRepository.ts @@ -149,8 +149,8 @@ class PoolsRepository { /** * Insert a new mining pool in the database - * - * @param pool + * + * @param pool */ public async $insertNewMiningPool(pool: any, slug: string): Promise { try { @@ -166,10 +166,10 @@ class PoolsRepository { /** * Rename an existing mining pool - * + * * @param dbId * @param newSlug - * @param newName + * @param newName */ public async $renameMiningPool(dbId: number, newSlug: string, newName: string): Promise { try { @@ -186,9 +186,9 @@ class PoolsRepository { /** * Update an exisiting mining pool link - * - * @param dbId - * @param newLink + * + * @param dbId + * @param newLink */ public async $updateMiningPoolLink(dbId: number, newLink: string): Promise { try { @@ -206,10 +206,10 @@ class PoolsRepository { /** * Update an existing mining pool addresses or coinbase tags - * - * @param dbId - * @param addresses - * @param regexes + * + * @param dbId + * @param addresses + * @param regexes */ public async $updateMiningPoolTags(dbId: number, addresses: string, regexes: string): Promise { try { diff --git a/backend/src/repositories/PricesRepository.ts b/backend/src/repositories/PricesRepository.ts index e12027a74..236519420 100644 --- a/backend/src/repositories/PricesRepository.ts +++ b/backend/src/repositories/PricesRepository.ts @@ -179,7 +179,7 @@ class PricesRepository { prices[currency] = 0; } } - + try { if (!config.FIAT_PRICE.API_KEY) { // Store only the 7 main currencies await DB.query(` @@ -191,8 +191,8 @@ class PricesRepository { await DB.query(` INSERT INTO prices(time, USD, EUR, GBP, CAD, CHF, AUD, JPY, BGN, BRL, CNY, CZK, DKK, HKD, HRK, HUF, IDR, ILS, INR, ISK, KRW, MXN, MYR, NOK, NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, TRY, ZAR) VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ? , ?, ?, ?, ?, ?, ?, ?, ? , ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? , ? )`, - [time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY, prices.BGN, prices.BRL, prices.CNY, prices.CZK, prices.DKK, - prices.HKD, prices.HRK, prices.HUF, prices.IDR, prices.ILS, prices.INR, prices.ISK, prices.KRW, prices.MXN, prices.MYR, prices.NOK, prices.NZD, + [time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY, prices.BGN, prices.BRL, prices.CNY, prices.CZK, prices.DKK, + prices.HKD, prices.HRK, prices.HUF, prices.IDR, prices.ILS, prices.INR, prices.ISK, prices.KRW, prices.MXN, prices.MYR, prices.NOK, prices.NZD, prices.PHP, prices.PLN, prices.RON, prices.RUB, prices.SEK, prices.SGD, prices.THB, prices.TRY, prices.ZAR] ); } @@ -341,8 +341,8 @@ class PricesRepository { `); if (!Array.isArray(latestPrices)) { throw Error(`Cannot get single historical price from the database`); - } - + } + // Compute fiat exchange rates let latestPrice = latestPrices[0] as ApiPrice; if (!latestPrice || latestPrice.USD === -1) { @@ -350,8 +350,8 @@ class PricesRepository { } const computeFx = (usd: number, other: number): number => usd <= 0.05 ? 0 : Math.round(Math.max(other, 0) / usd * 100) / 100; - - const exchangeRates: ExchangeRates = config.FIAT_PRICE.API_KEY ? + + const exchangeRates: ExchangeRates = config.FIAT_PRICE.API_KEY ? { USDEUR: computeFx(latestPrice.USD, latestPrice.EUR), USDGBP: computeFx(latestPrice.USD, latestPrice.GBP), @@ -446,10 +446,10 @@ class PricesRepository { latestPrice = priceUpdater.getEmptyPricesObj(); } - const computeFx = (usd: number, other: number): number => + const computeFx = (usd: number, other: number): number => usd <= 0 ? 0 : Math.round(Math.max(other, 0) / usd * 100) / 100; - - const exchangeRates: ExchangeRates = config.FIAT_PRICE.API_KEY ? + + const exchangeRates: ExchangeRates = config.FIAT_PRICE.API_KEY ? { USDEUR: computeFx(latestPrice.USD, latestPrice.EUR), USDGBP: computeFx(latestPrice.USD, latestPrice.GBP), diff --git a/backend/src/rpc-api/index.ts b/backend/src/rpc-api/index.ts index 131e1a048..37f4e3e99 100644 --- a/backend/src/rpc-api/index.ts +++ b/backend/src/rpc-api/index.ts @@ -1,61 +1,61 @@ -var commands = require('./commands') -var rpc = require('./jsonrpc') +const commands = require('./commands'); +const rpc = require('./jsonrpc'); // ===----------------------------------------------------------------------===// // JsonRPC // ===----------------------------------------------------------------------===// function Client (opts) { // @ts-ignore - this.rpc = new rpc.JsonRPC(opts) + this.rpc = new rpc.JsonRPC(opts); } // ===----------------------------------------------------------------------===// // cmd // ===----------------------------------------------------------------------===// Client.prototype.cmd = function () { - var args = [].slice.call(arguments) - var cmd = args.shift() + const args = [].slice.call(arguments); + const cmd = args.shift(); - callRpc(cmd, args, this.rpc) -} + callRpc(cmd, args, this.rpc); +}; // ===----------------------------------------------------------------------===// // callRpc // ===----------------------------------------------------------------------===// function callRpc (cmd, args, rpc) { - var fn = args[args.length - 1] + let fn = args[args.length - 1]; // If the last argument is a callback, pop it from the args list if (typeof fn === 'function') { - args.pop() + args.pop(); } else { - fn = function () {} + fn = function () {}; } return rpc.call(cmd, args, function () { - var args = [].slice.call(arguments) + const args = [].slice.call(arguments); // @ts-ignore - args.unshift(null) + args.unshift(null); // @ts-ignore - fn.apply(this, args) + fn.apply(this, args); }, function (err) { - fn(err) - }) + fn(err); + }); } // ===----------------------------------------------------------------------===// // Initialize wrappers // ===----------------------------------------------------------------------===// (function () { - for (var protoFn in commands) { + for (const protoFn in commands) { (function (protoFn) { Client.prototype[protoFn] = function () { - var args = [].slice.call(arguments) - return callRpc(commands[protoFn], args, this.rpc) - } - })(protoFn) + const args = [].slice.call(arguments); + return callRpc(commands[protoFn], args, this.rpc); + }; + })(protoFn); } -})() +})(); // Export! module.exports.Client = Client; diff --git a/backend/src/rpc-api/jsonrpc.ts b/backend/src/rpc-api/jsonrpc.ts index 0bcbdc16c..c810cac0e 100644 --- a/backend/src/rpc-api/jsonrpc.ts +++ b/backend/src/rpc-api/jsonrpc.ts @@ -1,43 +1,43 @@ -var http = require('http') -var https = require('https') +const http = require('http'); +const https = require('https'); import { readFileSync } from 'fs'; -var JsonRPC = function (opts) { +const JsonRPC = function (opts) { // @ts-ignore - this.opts = opts || {} + this.opts = opts || {}; // @ts-ignore - this.http = this.opts.ssl ? https : http -} + this.http = this.opts.ssl ? https : http; +}; JsonRPC.prototype.call = function (method, params) { return new Promise((resolve, reject) => { - var time = Date.now() - var requestJSON + const time = Date.now(); + let requestJSON; if (Array.isArray(method)) { // multiple rpc batch call - requestJSON = [] + requestJSON = []; method.forEach(function (batchCall, i) { requestJSON.push({ id: time + '-' + i, method: batchCall.method, params: batchCall.params - }) - }) + }); + }); } else { // single rpc call requestJSON = { id: time, method: method, params: params - } + }; } // First we encode the request into JSON - requestJSON = JSON.stringify(requestJSON) + requestJSON = JSON.stringify(requestJSON); // prepare request options - var requestOptions = { + const requestOptions = { host: this.opts.host || 'localhost', port: this.opts.port || 8332, method: 'POST', @@ -48,11 +48,11 @@ JsonRPC.prototype.call = function (method, params) { }, agent: false, rejectUnauthorized: this.opts.ssl && this.opts.sslStrict !== false - } + }; if (this.opts.ssl && this.opts.sslCa) { - // @ts-ignore - requestOptions.ca = this.opts.sslCa + // @ts-ignore + requestOptions.ca = this.opts.sslCa; } // use HTTP auth if user and password set @@ -64,61 +64,61 @@ JsonRPC.prototype.call = function (method, params) { requestOptions.auth = this.cachedCookie; } else if (this.opts.user && this.opts.pass) { // @ts-ignore - requestOptions.auth = this.opts.user + ':' + this.opts.pass + requestOptions.auth = this.opts.user + ':' + this.opts.pass; } // Now we'll make a request to the server - var cbCalled = false - var request = this.http.request(requestOptions) + let cbCalled = false; + const request = this.http.request(requestOptions); // start request timeout timer - var reqTimeout = setTimeout(function () { - if (cbCalled) return - cbCalled = true - request.abort() - var err = new Error('ETIMEDOUT') + const reqTimeout = setTimeout(function () { + if (cbCalled) {return;} + cbCalled = true; + request.abort(); + const err = new Error('ETIMEDOUT'); // @ts-ignore - err.code = 'ETIMEDOUT' - reject(err) - }, this.opts.timeout || 30000) + err.code = 'ETIMEDOUT'; + reject(err); + }, this.opts.timeout || 30000); // set additional timeout on socket in case of remote freeze after sending headers request.setTimeout(this.opts.timeout || 30000, function () { - if (cbCalled) return - cbCalled = true - request.abort() - var err = new Error('ESOCKETTIMEDOUT') + if (cbCalled) {return;} + cbCalled = true; + request.abort(); + const err = new Error('ESOCKETTIMEDOUT'); // @ts-ignore - err.code = 'ESOCKETTIMEDOUT' - reject(err) - }) + err.code = 'ESOCKETTIMEDOUT'; + reject(err); + }); request.on('error', function (err) { - if (cbCalled) return - cbCalled = true - clearTimeout(reqTimeout) - reject(err) - }) + if (cbCalled) {return;} + cbCalled = true; + clearTimeout(reqTimeout); + reject(err); + }); request.on('response', (response) => { - clearTimeout(reqTimeout) + clearTimeout(reqTimeout); // We need to buffer the response chunks in a nonblocking way. - var buffer = '' + let buffer = ''; response.on('data', function (chunk) { - buffer = buffer + chunk - }) + buffer = buffer + chunk; + }); // When all the responses are finished, we decode the JSON and // depending on whether it's got a result or an error, we call // emitSuccess or emitError on the promise. response.on('end', () => { - var err + let err; - if (cbCalled) return - cbCalled = true + if (cbCalled) {return;} + cbCalled = true; try { - var decoded = JSON.parse(buffer) + var decoded = JSON.parse(buffer); } catch (e) { // if we authenticated using a cookie and it failed, read the cookie file again if ( @@ -129,19 +129,19 @@ JsonRPC.prototype.call = function (method, params) { } if (response.statusCode !== 200) { - err = new Error('Invalid params, response status code: ' + response.statusCode) - err.code = -32602 - reject(err) + err = new Error('Invalid params, response status code: ' + response.statusCode); + err.code = -32602; + reject(err); } else { - err = new Error('Problem parsing JSON response from server') - err.code = -32603 - reject(err) + err = new Error('Problem parsing JSON response from server'); + err.code = -32603; + reject(err); } - return + return; } if (!Array.isArray(decoded)) { - decoded = [decoded] + decoded = [decoded]; } // iterate over each response, normally there will be just one @@ -149,29 +149,29 @@ JsonRPC.prototype.call = function (method, params) { decoded.forEach(function (decodedResponse, i) { if (decodedResponse.hasOwnProperty('error') && decodedResponse.error != null) { if (reject) { - err = new Error(decodedResponse.error.message || '') + err = new Error(decodedResponse.error.message || ''); if (decodedResponse.error.code) { - err.code = decodedResponse.error.code + err.code = decodedResponse.error.code; } - reject(err) + reject(err); } } else if (decodedResponse.hasOwnProperty('result')) { // @ts-ignore - resolve(decodedResponse.result, response.headers) + resolve(decodedResponse.result, response.headers); } else { if (reject) { - err = new Error(decodedResponse.error.message || '') + err = new Error(decodedResponse.error.message || ''); if (decodedResponse.error.code) { - err.code = decodedResponse.error.code + err.code = decodedResponse.error.code; } - reject(err) + reject(err); } } - }) - }) - }) + }); + }); + }); request.end(requestJSON); }); -} +}; -module.exports.JsonRPC = JsonRPC +module.exports.JsonRPC = JsonRPC; diff --git a/backend/src/tasks/lightning/forensics.service.ts b/backend/src/tasks/lightning/forensics.service.ts index aa88f5bb4..47b7d6aa5 100644 --- a/backend/src/tasks/lightning/forensics.service.ts +++ b/backend/src/tasks/lightning/forensics.service.ts @@ -449,7 +449,7 @@ class ForensicsService { const initiatorSide = initiator === 'remote' ? prevRemote : prevLocal; prevChannel.closed_by = prevChannel[`node${initiatorSide}_public_key`]; } - + // save changes to the closing channel await channelsApi.$updateClosingInfo(prevChannel); } else { diff --git a/backend/src/tasks/lightning/network-sync.service.ts b/backend/src/tasks/lightning/network-sync.service.ts index da4eba170..f3a20cd22 100644 --- a/backend/src/tasks/lightning/network-sync.service.ts +++ b/backend/src/tasks/lightning/network-sync.service.ts @@ -47,7 +47,7 @@ class NetworkSyncService { await this.$lookUpCreationDateFromChain(); await this.$updateNodeFirstSeen(); await this.$scanForClosedChannels(); - + if (config.MEMPOOL.BACKEND === 'esplora') { // run forensics on new channels only await forensicsService.$runClosedChannelsForensics(true); @@ -226,7 +226,7 @@ class NetworkSyncService { if (channels.length > 0) { logger.debug(`Updated ${channels.length} channels' creation date`, logger.tags.ln); - } + } } catch (e) { logger.err(`$lookUpCreationDateFromChain() error: ${e instanceof Error ? e.message : e}`, logger.tags.ln); } diff --git a/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts b/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts index c279cfb60..a6c8b9a66 100644 --- a/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts +++ b/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts @@ -6,7 +6,7 @@ import logger from '../../../logger'; const fsPromises = promises; -const BLOCKS_CACHE_MAX_SIZE = 100; +const BLOCKS_CACHE_MAX_SIZE = 100; const CACHE_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/ln-funding-txs-cache.json'; class FundingTxFetcher { @@ -33,7 +33,7 @@ class FundingTxFetcher { return; } this.running = true; - + const globalTimer = new Date().getTime() / 1000; let cacheTimer = new Date().getTime() / 1000; let loggerTimer = new Date().getTime() / 1000; @@ -70,7 +70,7 @@ class FundingTxFetcher { this.running = false; } - + public async $fetchChannelOpenTx(channelId: string): Promise<{timestamp: number, txid: string, value: number} | null> { channelId = Common.channelIntegerIdToShortId(channelId); diff --git a/backend/src/tasks/lightning/sync-tasks/node-locations.ts b/backend/src/tasks/lightning/sync-tasks/node-locations.ts index 8e791859f..4eff70ab3 100644 --- a/backend/src/tasks/lightning/sync-tasks/node-locations.ts +++ b/backend/src/tasks/lightning/sync-tasks/node-locations.ts @@ -60,13 +60,13 @@ export async function $lookupNodeLocation(): Promise { if (city && (asn || isp)) { const query = ` - UPDATE nodes SET - as_number = ?, - city_id = ?, - country_id = ?, - subdivision_id = ?, - longitude = ?, - latitude = ?, + UPDATE nodes SET + as_number = ?, + city_id = ?, + country_id = ?, + subdivision_id = ?, + longitude = ?, + latitude = ?, accuracy_radius = ? WHERE public_key = ? `; diff --git a/backend/src/tasks/lightning/sync-tasks/stats-importer.ts b/backend/src/tasks/lightning/sync-tasks/stats-importer.ts index 86f891d59..8891bfc3a 100644 --- a/backend/src/tasks/lightning/sync-tasks/stats-importer.ts +++ b/backend/src/tasks/lightning/sync-tasks/stats-importer.ts @@ -99,7 +99,7 @@ class LightningStatsImporter { const feeRates: number[] = []; const baseFees: number[] = []; const alreadyCountedChannels = {}; - + const [channelsInDbRaw]: any[] = await DB.query(`SELECT short_id FROM channels`); const channelsInDb = {}; for (const channel of channelsInDbRaw) { @@ -145,7 +145,7 @@ class LightningStatsImporter { channels: 0, }; } - + if (!alreadyCountedChannels[short_id]) { capacity += Math.round(tx.value * 100000000); capacities.push(Math.round(tx.value * 100000000)); @@ -162,7 +162,7 @@ class LightningStatsImporter { if (policy && parseInt(policy.fee_rate_milli_msat, 10) < 5000) { avgFeeRate += parseInt(policy.fee_rate_milli_msat, 10); feeRates.push(parseInt(policy.fee_rate_milli_msat, 10)); - } + } if (policy && parseInt(policy.fee_base_msat, 10) < 5000) { avgBaseFee += parseInt(policy.fee_base_msat, 10); baseFees.push(parseInt(policy.fee_base_msat, 10)); @@ -388,7 +388,7 @@ class LightningStatsImporter { totalProcessed++; continue; } - + if (this.isIncorrectSnapshot(timestamp, graph)) { logger.debug(`Ignoring ${this.topologiesFolder}/${filename}, because we defined it as an incorrect snapshot`); ++totalProcessed; @@ -399,7 +399,7 @@ class LightningStatsImporter { logger.info(`Founds a topology file that we did not import. Importing historical lightning stats now.`, logger.tags.ln); logStarted = true; } - + const datestr = `${new Date(timestamp * 1000).toUTCString()} (${timestamp})`; logger.debug(`${datestr}: Found ${graph.nodes.length} nodes and ${graph.edges.length} channels`, logger.tags.ln); @@ -475,7 +475,7 @@ class LightningStatsImporter { fee_rate_milli_msat: edge.fee_proportional_millionths, max_htlc_msat: edge.htlc_maximum_msat, last_update: edge.timestamp, - disabled: false, + disabled: false, }, node2_policy: null, }); @@ -545,7 +545,7 @@ class LightningStatsImporter { // UNIX_TIMESTAMP(added) >= 1591142400 AND UNIX_TIMESTAMP(added) <= 1592006400 OR // UNIX_TIMESTAMP(added) >= 1632787200 AND UNIX_TIMESTAMP(added) <= 1633564800 OR // UNIX_TIMESTAMP(added) >= 1634256000 AND UNIX_TIMESTAMP(added) <= 1645401600 OR - // UNIX_TIMESTAMP(added) >= 1654992000 AND UNIX_TIMESTAMP(added) <= 1661472000 + // UNIX_TIMESTAMP(added) >= 1654992000 AND UNIX_TIMESTAMP(added) <= 1661472000 // ) } } diff --git a/backend/src/tasks/price-feeds/kraken-api.ts b/backend/src/tasks/price-feeds/kraken-api.ts index ebc784c6f..0c69ecf00 100644 --- a/backend/src/tasks/price-feeds/kraken-api.ts +++ b/backend/src/tasks/price-feeds/kraken-api.ts @@ -69,7 +69,7 @@ class KrakenApi implements PriceFeed { // CHF weekly price history goes back to timestamp 1575504000 (December 5, 2019) // AUD weekly price history goes back to timestamp 1591833600 (June 11, 2020) - let priceHistory: any = {}; // map: timestamp -> Prices + const priceHistory: any = {}; // map: timestamp -> Prices for (const currency of this.currencies) { const response = await query(this.urlHist.replace('{GRANULARITY}', '10080') + currency); diff --git a/backend/src/tasks/price-updater.ts b/backend/src/tasks/price-updater.ts index 16a33cfb6..f40fc7281 100644 --- a/backend/src/tasks/price-updater.ts +++ b/backend/src/tasks/price-updater.ts @@ -432,7 +432,7 @@ class PriceUpdater { this.additionalCurrenciesHistoryRunning = true; logger.debug(`Inserting missing historical conversion rates using conversions API to fill ${priceTimesToFill.length} rows`, logger.tags.mining); - let conversionRates: { [timestamp: number]: ConversionRates } = {}; + const conversionRates: { [timestamp: number]: ConversionRates } = {}; let totalInserted = 0; for (let i = 0; i < priceTimesToFill.length; i++) { @@ -464,7 +464,7 @@ class PriceUpdater { } const prices: ApiPrice = this.getEmptyPricesObj(); - + let willInsert = false; for (const conversionCurrency of this.newCurrencies.concat(missingLegacyCurrencies)) { if (conversionRates[yearMonthTimestamp][conversionCurrency] > 0 && priceTime.USD * conversionRates[yearMonthTimestamp][conversionCurrency] < MAX_PRICES[conversionCurrency]) { @@ -474,7 +474,7 @@ class PriceUpdater { prices[conversionCurrency] = 0; } } - + if (willInsert) { await PricesRepository.$saveAdditionalCurrencyPrices(priceTime.time, prices, missingLegacyCurrencies); ++totalInserted; diff --git a/backend/src/utils/bitcoin-script.ts b/backend/src/utils/bitcoin-script.ts index f463d8f76..117fa61a7 100644 --- a/backend/src/utils/bitcoin-script.ts +++ b/backend/src/utils/bitcoin-script.ts @@ -204,7 +204,7 @@ export function getVarIntLength(n: number): number { /** Extracts miner names from a DATUM coinbase transaction */ export function parseDATUMTemplateCreator(coinbaseRaw: string): string[] | null { - let bytes: number[] = []; + const bytes: number[] = []; for (let c = 0; c < coinbaseRaw.length; c += 2) { bytes.push(parseInt(coinbaseRaw.slice(c, c + 2), 16)); } diff --git a/backend/src/utils/format.ts b/backend/src/utils/format.ts index 63dc07ae4..ce23bc369 100644 --- a/backend/src/utils/format.ts +++ b/backend/src/utils/format.ts @@ -4,7 +4,7 @@ export function getBytesUnit(bytes: number): string { if (isNaN(bytes) || !isFinite(bytes)) { return 'B'; } - + let unitIndex = 0; while (unitIndex < byteUnits.length && bytes > 1024) { unitIndex++; @@ -18,7 +18,7 @@ export function formatBytes(bytes: number, toUnit: string, skipUnit = false): st if (isNaN(bytes) || !isFinite(bytes)) { return `${bytes}`; } - + let unitIndex = 0; while (unitIndex < byteUnits.length && (toUnit && byteUnits[unitIndex] !== toUnit || (!toUnit && bytes > 1024))) { unitIndex++; diff --git a/backend/src/utils/secp256k1.ts b/backend/src/utils/secp256k1.ts index 9e0f6dc3b..b95e1493b 100644 --- a/backend/src/utils/secp256k1.ts +++ b/backend/src/utils/secp256k1.ts @@ -49,7 +49,7 @@ export function isPoint(pointHex: string): boolean { } // Function modified slightly from noble-curves - + // Now we know that pointHex is a 33 or 65 byte hex string. const isCompressed = pointHex.length === 66; diff --git a/backend/testSetup.integration.ts b/backend/testSetup.integration.ts index 74efe871b..4ae0347cb 100644 --- a/backend/testSetup.integration.ts +++ b/backend/testSetup.integration.ts @@ -1,5 +1,5 @@ // Integration test setup - uses real implementations, not mocks -// +// // Note: We don't mock ./mempool-config.json here because: // 1. The MEMPOOL_CONFIG_FILE env var points to mempool-config.test.json // 2. config.ts will load that file via require() if env var is set From d9812c82b691a5ddc8bca0395710d688db387a06 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 5 Jan 2026 07:07:52 +0000 Subject: [PATCH 20/56] co-branded custom dashboards --- .../liquid-master-page.component.html | 52 +++++++++--------- .../liquid-master-page.component.scss | 13 +++++ .../master-page-preview.component.html | 8 ++- .../master-page/master-page.component.html | 54 +++++++++---------- .../master-page/master-page.component.scss | 13 +++++ .../master-page/master-page.component.ts | 2 +- .../components/tracker/tracker.component.html | 18 +++---- .../components/tracker/tracker.component.scss | 4 ++ frontend/src/app/master-page.module.ts | 4 +- .../src/app/services/enterprise.service.ts | 15 +++++- frontend/src/app/services/state.service.ts | 1 + 11 files changed, 107 insertions(+), 77 deletions(-) diff --git a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html index 10af378b1..e6b98f13e 100644 --- a/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html +++ b/frontend/src/app/components/liquid-master-page/liquid-master-page.component.html @@ -4,17 +4,17 @@