From 56a066179ddea28da6dd6baa285ec7c7a2ad228f Mon Sep 17 00:00:00 2001 From: Igor Papandinas <26460174+ipapandinas@users.noreply.github.com> Date: Wed, 30 Sep 2026 17:54:15 +0100 Subject: [PATCH] maintenance --- .../firebase-hosting-pull-request.yml | 2 +- .github/workflows/firebase-merge.yml | 7 +- .github/workflows/pr_action.yml | 18 +- .gitignore | 1 + package.json | 7 +- public/swagger.json | 676 +---------- scripts/smoke.sh | 59 + src/client/BaseApi.ts | 25 + src/container.ts | 2 - src/containertypes.ts | 3 - src/controllers/BurnController.ts | 30 +- src/controllers/ControllerBase.ts | 10 + src/controllers/DappsStakingController.ts | 30 +- src/controllers/DappsStakingV3Controller.ts | 477 +------- src/controllers/TokenStatsController.ts | 17 +- src/data/dappStakingSnapshot.astar.json | 1004 +++++++++++++++++ src/data/dappStakingSnapshot.shibuya.json | 115 ++ src/data/dappStakingSnapshot.shiden.json | 151 +++ src/index.ts | 7 +- src/services/BurnService.ts | 40 - src/services/CoinGeckoPriceProvider.ts | 28 +- src/services/DappStakingV3IndexerBase.ts | 17 - src/services/DappsStakingEvents.ts | 650 +---------- src/services/ServiceBase.ts | 9 + src/services/StatsService.ts | 39 +- yarn.lock | 11 +- 26 files changed, 1535 insertions(+), 1900 deletions(-) create mode 100755 scripts/smoke.sh create mode 100644 src/data/dappStakingSnapshot.astar.json create mode 100644 src/data/dappStakingSnapshot.shibuya.json create mode 100644 src/data/dappStakingSnapshot.shiden.json delete mode 100644 src/services/BurnService.ts delete mode 100644 src/services/DappStakingV3IndexerBase.ts diff --git a/.github/workflows/firebase-hosting-pull-request.yml b/.github/workflows/firebase-hosting-pull-request.yml index 067aea7..c685ffd 100644 --- a/.github/workflows/firebase-hosting-pull-request.yml +++ b/.github/workflows/firebase-hosting-pull-request.yml @@ -16,7 +16,7 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: FirebaseExtended/action-hosting-deploy@v0 with: repoToken: '${{ secrets.GITHUB_TOKEN }}' diff --git a/.github/workflows/firebase-merge.yml b/.github/workflows/firebase-merge.yml index 0ac94a4..b85f55c 100644 --- a/.github/workflows/firebase-merge.yml +++ b/.github/workflows/firebase-merge.yml @@ -10,7 +10,10 @@ jobs: build_and_deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24.x - run: npm install -g yarn - run: yarn - name: Deploy Firebase Hosting @@ -21,7 +24,7 @@ jobs: channelId: live projectId: astar-token-api - name: Deploy Firebase Function - uses: w9jds/firebase-action@v13.0.3 + uses: w9jds/firebase-action@v15.32.0 with: args: deploy --only functions --debug env: diff --git a/.github/workflows/pr_action.yml b/.github/workflows/pr_action.yml index debe6df..c10e290 100644 --- a/.github/workflows/pr_action.yml +++ b/.github/workflows/pr_action.yml @@ -7,11 +7,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [20.x] + node-version: [24.x] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: unit_test @@ -24,11 +24,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [20.x] + node-version: [24.x] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: check_style @@ -41,11 +41,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [20.x] + node-version: [24.x] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: build diff --git a/.gitignore b/.gitignore index 83a12c8..2689d13 100644 --- a/.gitignore +++ b/.gitignore @@ -154,3 +154,4 @@ out .firebase/ .runtimeconfig.json *_dapps.json +.secret.local diff --git a/package.json b/package.json index e58a94d..467961e 100644 --- a/package.json +++ b/package.json @@ -31,10 +31,11 @@ "lint:check": "eslint '*/**/*.{js,ts}' && prettier -c .", "test": "jest", "swagger-autogen": "node src/swagger.js", - "deploy": "firebase deploy" + "deploy": "firebase deploy", + "smoke": "scripts/smoke.sh" }, "engines": { - "node": "20" + "node": "24" }, "license": "MIT", "devDependencies": { @@ -78,7 +79,7 @@ "express": "^4.18.2", "express-validator": "^7.0.1", "firebase-admin": "^11.10.1", - "firebase-functions": "^4.4.1", + "firebase-functions": "^4.9.0", "inversify": "^6.0.1", "reflect-metadata": "^0.1.13", "swagger-autogen": "^2.23.5", diff --git a/public/swagger.json b/public/swagger.json index 4894a30..cfbfa5c 100644 --- a/public/swagger.json +++ b/public/swagger.json @@ -301,33 +301,6 @@ } } }, - "/api/v1/{network}/token/supply-history/": { - "get": { - "tags": [ - "Token" - ], - "description": "Retreives total supply history at the beginning of a new dApp staking era for a given network and period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar, shiden, shibuya", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, "/api/v1/{network}/dapps-staking/apr": { "get": { "tags": [ @@ -384,47 +357,6 @@ } } }, - "/api/v1/{network}/dapps-staking/tvl/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves dapps staking TVL for a given network and period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar, shiden, shibuya, rocstar", - "enum": [ - "astar", - "shiden", - "shibuya", - "rocstar" - ] - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 7 days 30 days, 90 days, 1 year", - "enum": [ - "7 days", - "30 days", - "90 days", - "1 year" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, "/api/v1/{network}/dapps-staking/earned/{address}": { "get": { "tags": [ @@ -680,209 +612,24 @@ } } }, - "/api/v3/{network}/dapps-staking/tvl/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves dapps staking TVL for a given network and period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year", - "enum": [ - "1 day", - "7 days", - "30 days", - "90 days", - "1 year" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/stakers-total/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves dapps staking Total Value Staked and Total Number of Unique Stakers for a given network and period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year", - "enum": [ - "1 day", - "7 days", - "30 days", - "90 days", - "1 year" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/lockers-total/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves dapps staking Total Value Locked and Total Number of Unique Lockers for a given network and period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year", - "enum": [ - "1 day", - "7 days", - "30 days", - "90 days", - "1 year" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/lockers-and-stakers-total/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves dapps staking Total Value Locked & Staked and Total Number of Unique Lockers & Stakers for a given network and period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year", - "enum": [ - "1 day", - "7 days", - "30 days", - "90 days", - "1 year" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/stakerscount/{contractAddress}/{period}": { + "/api/v3/{network}/dapps-staking/chaindapps": { "get": { "tags": [ "Dapps Staking" ], - "description": "Retrieves dapps staking stakers count for a given network and period.", + "description": "Retrieves list of dapps (basic info) registered for dapps staking", "parameters": [ { "name": "network", "in": "path", "required": true, "type": "string", - "description": "The network name. Supported networks: astar", + "description": "The network name. Supported networks: astar, shiden, shibuya", "enum": [ "astar", "shiden", "shibuya" ] - }, - { - "name": "contractAddress", - "in": "path", - "required": true, - "type": "string", - "description": "Contract address to get stats for" - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year", - "enum": [ - "1 day", - "7 days", - "30 days", - "90 days", - "1 year" - ] } ], "responses": { @@ -892,19 +639,19 @@ } } }, - "/api/v3/{network}/dapps-staking/stakerslist/{contractAddress}": { + "/api/v3/{network}/dapps-staking/stake-info/{address}": { "get": { "tags": [ "Dapps Staking" ], - "description": "Retrieves dapps staking stakers list for a given network and period.", + "description": "Retrieves the amount of stake of participant", "parameters": [ { "name": "network", "in": "path", "required": true, "type": "string", - "description": "The network name. Supported networks: astar", + "description": "The network name. Supported networks: astar, shiden, shibuya", "enum": [ "astar", "shiden", @@ -912,109 +659,7 @@ ] }, { - "name": "contractAddress", - "in": "path", - "required": true, - "type": "string", - "description": "Contract address to get stats for" - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/stakerscount-total/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves total stakers count for a given network and period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year", - "enum": [ - "1 day", - "7 days", - "30 days", - "90 days", - "1 year" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/chaindapps": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves list of dapps (basic info) registered for dapps staking", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar, shiden, shibuya", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/stake-info/{address}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves the amount of stake of participant", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar, shiden, shibuya", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "address", + "name": "address", "in": "path", "required": true, "type": "string", @@ -1028,313 +673,6 @@ } } }, - "/api/v3/{network}/dapps-staking/stats/dapp/{contractAddress}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves raw stats of dapps staking events with types for a given smart contract address.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar" - ] - }, - { - "name": "contractAddress", - "in": "path", - "required": true, - "type": "string", - "description": "Smart Contract address to get stats for" - }, - { - "name": "startDate", - "in": "query", - "description": "Start date for filtering the staking events (inclusive). Format: YYYY-MM-DD", - "required": true, - "type": "string", - "format": "date" - }, - { - "name": "endDate", - "in": "query", - "description": "End date for filtering the staking events (inclusive). Format: YYYY-MM-DD", - "required": true, - "type": "string", - "format": "date" - }, - { - "name": "limit", - "in": "query", - "description": "Number of records to retrieve per page. Defaults to 100 if not provided.", - "required": false, - "type": "integer", - "format": "int32", - "default": 100 - }, - { - "name": "offset", - "in": "query", - "description": "Number of records to skip for pagination. Defaults to 0 if not provided.", - "required": false, - "type": "integer", - "format": "int32", - "default": 0 - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/stats/aggregated/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves aggregated stats of dapps staking events for a given period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar" - ] - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 7 days 30 days, 90 days, 1 year", - "enum": [ - "7 days", - "30 days", - "90 days", - "1 year" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/rewards/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves dapps staking rewards for a given network and period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year", - "enum": [ - "1 day", - "7 days", - "30 days", - "90 days", - "1 year" - ] - }, - { - "name": "transaction", - "in": "query", - "description": "The Reward Event transaction type. Supported values: Reward, BonusReward, DAppReward", - "required": false, - "type": "string", - "enum": [ - "Reward", - "BonusReward", - "DAppReward" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/rewards-aggregated/{address}/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves dapps staking rewards for a given network and period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "address", - "in": "path", - "required": true, - "type": "string", - "description": "User address or contract address who received rewards" - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year", - "enum": [ - "1 day", - "7 days", - "30 days", - "90 days", - "1 year" - ] - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/period-aggregated/{period}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves aggregated period data (stakes and rewards per dApp) for the given dApp staking period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "period", - "in": "path", - "required": true, - "type": "string", - "description": "dApp staking period number." - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/staker-aggregated/{address}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves aggregated period data for the given staker containing all stakes and rewards per period.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "address", - "in": "path", - "required": true, - "type": "string", - "description": "Staker address." - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v3/{network}/dapps-staking/staker-aggregated-total/{address}": { - "get": { - "tags": [ - "Dapps Staking" - ], - "description": "Retrieves aggregated period data for the given staker containing sum of all rewards claimed and the current period stake.", - "parameters": [ - { - "name": "network", - "in": "path", - "required": true, - "type": "string", - "description": "The network name. Supported networks: astar", - "enum": [ - "astar", - "shiden", - "shibuya" - ] - }, - { - "name": "address", - "in": "path", - "required": true, - "type": "string", - "description": "Staker address." - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, "/api/v3/{network}/dapps-staking/get-period-range/{period}": { "get": { "tags": [ diff --git a/scripts/smoke.sh b/scripts/smoke.sh new file mode 100755 index 0000000..cb7a2ee --- /dev/null +++ b/scripts/smoke.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# Smoke test the token API against a deployment. +# +# Usage: scripts/smoke.sh +# Emulator: scripts/smoke.sh http://127.0.0.1:5001/astar-token-api/us-central1/app/api +# Staging: scripts/smoke.sh https://astar-token-api-staging.web.app/api +# Prod: scripts/smoke.sh https://api.astar.network/api +set -uo pipefail + +BASE="${1:?base url required, e.g. https://api.astar.network/api}" +BASE="${BASE%/}" +FAILED=0 + +# check [jq assertion on the body] +check() { + local path="$1" expected="$2" assertion="${3:-}" + local response body status + response="$(curl -s -m 60 -w $'\n%{http_code}' "$BASE/$path")" + status="${response##*$'\n'}" + body="${response%$'\n'*}" + + if [[ "$status" != "$expected" ]]; then + printf 'FAIL %-58s status %s, expected %s: %.120s\n' "$path" "$status" "$expected" "$body" + FAILED=1 + elif [[ -n "$assertion" ]] && ! jq -e "$assertion" <<<"$body" >/dev/null 2>&1; then + printf 'FAIL %-58s assertion "%s": %.120s\n' "$path" "$assertion" "$body" + FAILED=1 + else + printf 'ok %-58s %s\n' "$path" "$status" + fi +} + +# Token stats consumed by CoinGecko / CMC and the portal. +check 'v1/astar/token/circulation' 200 '. > 0' +check 'astar/token/stats' 200 '.circulatingSupply > 0' +check 'v1/shiden/token/circulation' 200 '. > 0' +check 'v1/token/price/ASTR' 200 '. > 0' +check 'v1/astar/token/extendedstats' 200 '.[0].price > 0' + +# dApp staking routes kept after the indexer retirement. +for network in astar shiden shibuya; do + check "v3/$network/dapps-staking/chaindapps" 200 \ + 'map(select(.state == "Registered")) | length > 0 and length <= 16' + check "v3/$network/dapps-staking/get-period-range/1" 200 '.start > 0 and .end > .start' +done +check 'v3/astar/dapps-staking/stake-info/YYd75rUp18RPGa7NSeDX1hEKFo35o4rPcceseiFnSYopidY' 200 + +# Portal dApp registry (Firebase). +check 'v1/astar/dapps-staking/dappssimple' 200 'length > 0' + +# Routes retired with the indexer must answer 410. +check 'v3/astar/dapps-staking/stakerslist/0x0000000000000000000000000000000000000000' 410 +check 'v3/astar/dapps-staking/tvl/7%20days' 410 +check 'v3/astar/dapps-staking/period-aggregated/1' 410 +check 'v1/astar/dapps-staking/tvl/7%20days' 410 +check 'v1/astar/burn/events' 410 +check 'v1/astar/token/supply-history' 410 + +exit "$FAILED" diff --git a/src/client/BaseApi.ts b/src/client/BaseApi.ts index dfd2853..197d5c9 100644 --- a/src/client/BaseApi.ts +++ b/src/client/BaseApi.ts @@ -35,6 +35,13 @@ export interface DappInfoV3 extends Struct { state: string; } +export type IntegratedDapp = { + contractAddress: string; + dappId: number; + owner: string; + beneficiary: string | null; +}; + export interface PalletDappStakingV3ProtocolState extends Struct { era: Compact; nextEraStart: Compact; @@ -94,6 +101,7 @@ export interface IAstarApi { getApiPromise(): Promise; getStakerInfo(address: string): Promise; getProtocolState(): Promise; + getIntegratedDapps(): Promise; } export class BaseApi implements IAstarApi { @@ -240,6 +248,23 @@ export class BaseApi implements IAstarApi { return await this._api.query.dappStaking.activeProtocolState(); } + public async getIntegratedDapps(): Promise { + await this.ensureConnection(); + const entries = await this._api.query.dappStaking.integratedDApps.entries(); + + return entries.map(([key, value]) => { + const contract = key.args[0].toJSON() as { evm?: string; wasm?: string }; + const info = value.toJSON() as { id: number; owner: string; rewardBeneficiary: string | null }; + + return { + contractAddress: contract.evm?.toLowerCase() ?? contract.wasm ?? '', + dappId: info.id, + owner: info.owner, + beneficiary: info.rewardBeneficiary ?? null, + }; + }); + } + public async getStakerInfo(address: string): Promise { await this.ensureConnection(); let ss558Address = address; diff --git a/src/container.ts b/src/container.ts index 7808b8f..88978b1 100644 --- a/src/container.ts +++ b/src/container.ts @@ -45,7 +45,6 @@ import { import { BluezNftService, INftService } from './services/NftService'; import { NftController } from './controllers/NftController'; import { TokenStatsControllerV2 } from './controllers/TokenStatsControllerV2'; -import { BurnService, IBurnService } from './services/BurnService'; import { BurnController } from './controllers/BurnController'; const container = new Container(); @@ -77,7 +76,6 @@ container.bind(ContainerTypes.ApiFactory).to(ApiFactory).inSingleto container.bind(ContainerTypes.StatsService).to(StatsService).inSingletonScope(); container.bind(ContainerTypes.DappsStakingEvents).to(DappsStakingEvents).inSingletonScope(); -container.bind(ContainerTypes.BurnService).to(BurnService).inSingletonScope(); container .bind(ContainerTypes.DappsStakingService) diff --git a/src/containertypes.ts b/src/containertypes.ts index 9073dde..d699d1c 100644 --- a/src/containertypes.ts +++ b/src/containertypes.ts @@ -1,5 +1,3 @@ -import { BurnService } from './services/BurnService'; - export const ContainerTypes = { Controller: 'Controller', StatsService: 'StatsService', @@ -18,5 +16,4 @@ export const ContainerTypes = { DappRadarService: 'DappRadarService', GiantSquidService: 'GiantSquidService', BluezNftService: 'BluezNftService', - BurnService: 'BurnService', }; diff --git a/src/controllers/BurnController.ts b/src/controllers/BurnController.ts index bb11d45..e6a1ece 100644 --- a/src/controllers/BurnController.ts +++ b/src/controllers/BurnController.ts @@ -1,38 +1,16 @@ import express, { Request, Response } from 'express'; -import { inject, injectable } from 'inversify'; +import { injectable } from 'inversify'; import { ControllerBase } from './ControllerBase'; import { IControllerBase } from './IControllerBase'; -import { ContainerTypes } from '../containertypes'; -import { IBurnService } from '../services/BurnService'; -import { NetworkType } from '../networks'; @injectable() export class BurnController extends ControllerBase implements IControllerBase { - constructor(@inject(ContainerTypes.BurnService) private _burnService: IBurnService) { - super(); - } - public register(app: express.Application): void { /** - * @description Burn events route + * @description Burn events route. Retired together with the dApp staking indexer. */ - app.route('/api/v1/:network/burn/events').get(async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves burn events for a given network.' - #swagger.tags = ['Burn'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar, shiden, shibuya', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - */ - try { - const network = req.params.network as NetworkType; - res.json(await this._burnService.getBurnEvents(network)); - } catch (err) { - this.handleError(res, err as Error); - } + app.route('/api/v1/:network/burn/events').get(async (_req: Request, res: Response) => { + this.handleRetired(res); }); } } diff --git a/src/controllers/ControllerBase.ts b/src/controllers/ControllerBase.ts index 24d1738..3646ce7 100644 --- a/src/controllers/ControllerBase.ts +++ b/src/controllers/ControllerBase.ts @@ -14,4 +14,14 @@ export class ControllerBase { const NOT_FOUND_STATUS = 404; res.status(NOT_FOUND_STATUS).send('Dapp not found'); } + + /** + * Responds to routes backed by the retired dApp staking indexer. + */ + protected handleRetired(res: Response) { + const GONE_STATUS = 410; + res.status(GONE_STATUS).json({ + message: 'This endpoint has been retired. Query the chain directly for current dApp staking state.', + }); + } } diff --git a/src/controllers/DappsStakingController.ts b/src/controllers/DappsStakingController.ts index a90a4fd..3bc82e3 100644 --- a/src/controllers/DappsStakingController.ts +++ b/src/controllers/DappsStakingController.ts @@ -14,7 +14,6 @@ import { IStatsIndexerService } from '../services/StatsIndexerService'; import { ControllerBase } from './ControllerBase'; import { IControllerBase } from './IControllerBase'; import { IGiantSquidService } from '../services/GiantSquidService'; -import { IDappsStakingEvents } from '../services/DappsStakingEvents'; @injectable() export class DappsStakingController extends ControllerBase implements IControllerBase { @@ -24,7 +23,6 @@ export class DappsStakingController extends ControllerBase implements IControlle @inject(ContainerTypes.DappsStakingStatsService) private _statsService: IDappsStakingStatsService, @inject(ContainerTypes.DappRadarService) private _dappRadarService: IDappRadarService, @inject(ContainerTypes.GiantSquidService) private _giantSquidService: IGiantSquidService, - @inject(ContainerTypes.DappsStakingEvents) private _eventsService: IDappsStakingEvents, ) { super(); } @@ -83,31 +81,11 @@ export class DappsStakingController extends ControllerBase implements IControlle }); /** - * @description Dapps staking TVL route v1. + * @description Dapps staking TVL route v1. Retired together with the dApp staking indexer. */ - app.route('/api/v1/:network/dapps-staking/tvl/:period').get(async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves dapps staking TVL for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar, shiden, shibuya, rocstar', - required: true, - enum: ['astar', 'shiden', 'shibuya', 'rocstar'] - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 7 days 30 days, 90 days, 1 year', - required: true, - enum: ['7 days', '30 days', '90 days', '1 year'] - } - */ - res.json( - await this._eventsService.getDappStakingTvl( - req.params.network as NetworkType, - req.params.period as PeriodType, - ), - ); + app.route('/api/v1/:network/dapps-staking/tvl/:period').get(async (_req: Request, res: Response) => { + // #swagger.ignore = true + this.handleRetired(res); }); app.route('/api/v1/:network/dapps-staking/earned/:address').get(async (req: Request, res: Response) => { diff --git a/src/controllers/DappsStakingV3Controller.ts b/src/controllers/DappsStakingV3Controller.ts index 8d6e6c1..7a7f8d2 100644 --- a/src/controllers/DappsStakingV3Controller.ts +++ b/src/controllers/DappsStakingV3Controller.ts @@ -2,10 +2,30 @@ import express, { Request, Response } from 'express'; import { injectable, inject } from 'inversify'; import { ContainerTypes } from '../containertypes'; import { NetworkType } from '../networks'; -import { PeriodType } from '../services/ServiceBase'; import { ControllerBase } from './ControllerBase'; import { IControllerBase } from './IControllerBase'; -import { IDappsStakingEvents, RewardEventType } from '../services/DappsStakingEvents'; +import { IDappsStakingEvents } from '../services/DappsStakingEvents'; + +/** + * Routes backed by the retired dApp staking indexer. Kept registered so callers get an explicit 410 + * instead of a 404 or stale data. + */ +const RETIRED_ROUTES = [ + '/api/v3/:network/dapps-staking/tvl/:period', + '/api/v3/:network/dapps-staking/stakers-total/:period', + '/api/v3/:network/dapps-staking/lockers-total/:period', + '/api/v3/:network/dapps-staking/lockers-and-stakers-total/:period', + '/api/v3/:network/dapps-staking/stakerscount/:contractAddress/:period', + '/api/v3/:network/dapps-staking/stakerslist/:contractAddress', + '/api/v3/:network/dapps-staking/stakerscount-total/:period', + '/api/v3/:network/dapps-staking/stats/dapp/:contractAddress', + '/api/v3/:network/dapps-staking/stats/aggregated/:period', + '/api/v3/:network/dapps-staking/rewards/:period', + '/api/v3/:network/dapps-staking/rewards-aggregated/:address/:period', + '/api/v3/:network/dapps-staking/period-aggregated/:period', + '/api/v3/:network/dapps-staking/staker-aggregated/:address', + '/api/v3/:network/dapps-staking/staker-aggregated-total/:address', +]; @injectable() export class DappsStakingV3Controller extends ControllerBase implements IControllerBase { @@ -14,197 +34,6 @@ export class DappsStakingV3Controller extends ControllerBase implements IControl } public register(app: express.Application): void { - /** - * @description Dapps staking TVL route v3. - */ - app.route('/api/v3/:network/dapps-staking/tvl/:period').get(async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves dapps staking TVL for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year', - required: true, - enum: ['1 day', '7 days', '30 days', '90 days', '1 year'] - } - */ - res.json( - await this._dappsStakingEvents.getDappStakingTvl( - req.params.network as NetworkType, - req.params.period as PeriodType, - ), - ); - }); - - app.route('/api/v3/:network/dapps-staking/stakers-total/:period').get(async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves dapps staking Total Value Staked and Total Number of Unique Stakers for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year', - required: true, - enum: ['1 day', '7 days', '30 days', '90 days', '1 year'] - } - */ - res.json( - await this._dappsStakingEvents.getDappStakingStakersTotal( - req.params.network as NetworkType, - req.params.period as PeriodType, - ), - ); - }); - - app.route('/api/v3/:network/dapps-staking/lockers-total/:period').get(async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves dapps staking Total Value Locked and Total Number of Unique Lockers for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year', - required: true, - enum: ['1 day', '7 days', '30 days', '90 days', '1 year'] - } - */ - res.json( - await this._dappsStakingEvents.getDappStakingLockersTotal( - req.params.network as NetworkType, - req.params.period as PeriodType, - ), - ); - }); - - app.route('/api/v3/:network/dapps-staking/lockers-and-stakers-total/:period').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves dapps staking Total Value Locked & Staked and Total Number of Unique Lockers & Stakers for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year', - required: true, - enum: ['1 day', '7 days', '30 days', '90 days', '1 year'] - } - */ - res.json( - await this._dappsStakingEvents.getDappStakingLockersAndStakersTotal( - req.params.network as NetworkType, - req.params.period as PeriodType, - ), - ); - }, - ); - - app.route('/api/v3/:network/dapps-staking/stakerscount/:contractAddress/:period').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves dapps staking stakers count for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['contractAddress'] = { - in: 'path', - description: 'Contract address to get stats for', - required: true - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year', - required: true, - enum: ['1 day', '7 days', '30 days', '90 days', '1 year'] - } - */ - res.json( - await this._dappsStakingEvents.getDappStakingStakersCount( - req.params.network as NetworkType, - req.params.contractAddress as string, - req.params.period as PeriodType, - ), - ); - }, - ); - - app.route('/api/v3/:network/dapps-staking/stakerslist/:contractAddress').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves dapps staking stakers list for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['contractAddress'] = { - in: 'path', - description: 'Contract address to get stats for', - required: true - } - */ - res.json( - await this._dappsStakingEvents.getDappStakingStakersList( - req.params.network as NetworkType, - req.params.contractAddress as string, - ), - ); - }, - ); - - app.route('/api/v3/:network/dapps-staking/stakerscount-total/:period').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves total stakers count for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year', - required: true, - enum: ['1 day', '7 days', '30 days', '90 days', '1 year'] - } - */ - res.json( - await this._dappsStakingEvents.getDappStakingStakersCountTotal( - req.params.network as NetworkType, - req.params.period as PeriodType, - ), - ); - }, - ); - app.route('/api/v3/:network/dapps-staking/chaindapps').get(async (req: Request, res: Response) => { /* #swagger.description = 'Retrieves list of dapps (basic info) registered for dapps staking' @@ -243,262 +72,6 @@ export class DappsStakingV3Controller extends ControllerBase implements IControl ); }); - app.route('/api/v3/:network/dapps-staking/stats/dapp/:contractAddress').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves raw stats of dapps staking events with types for a given smart contract address.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar'] - } - #swagger.parameters['contractAddress'] = { - in: 'path', - description: 'Smart Contract address to get stats for', - required: true - } - #swagger.parameters['startDate'] = { - in: 'query', - description: 'Start date for filtering the staking events (inclusive). Format: YYYY-MM-DD', - required: true, - type: 'string', - format: 'date' - } - #swagger.parameters['endDate'] = { - in: 'query', - description: 'End date for filtering the staking events (inclusive). Format: YYYY-MM-DD', - required: true, - type: 'string', - format: 'date' - } - #swagger.parameters['limit'] = { - in: 'query', - description: 'Number of records to retrieve per page. Defaults to 100 if not provided.', - required: false, - type: 'integer', - format: 'int32', - default: 100 - } - #swagger.parameters['offset'] = { - in: 'query', - description: 'Number of records to skip for pagination. Defaults to 0 if not provided.', - required: false, - type: 'integer', - format: 'int32', - default: 0 - } - */ - const startDate = req.query.startDate; - const endDate = req.query.endDate; - const limit = parseInt(req.query.limit as string, 10) || 100; // Default to 100 if not provided - const offset = parseInt(req.query.offset as string, 10) || 0; // Default to 0 if not provided - - try { - res.json( - await this._dappsStakingEvents.getStakingEvents( - req.params.network as NetworkType, - req.params.contractAddress, - startDate as string, - endDate as string, - limit as number, - offset as number, - ), - ); - } catch (err) { - this.handleError(res, err as Error); - } - }, - ); - - app.route('/api/v3/:network/dapps-staking/stats/aggregated/:period').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves aggregated stats of dapps staking events for a given period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar'] - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 7 days 30 days, 90 days, 1 year', - required: true, - enum: ['7 days', '30 days', '90 days', '1 year'] - } - */ - try { - res.json( - await this._dappsStakingEvents.getAggregatedData( - req.params.network as NetworkType, - req.params.period as PeriodType, - ), - ); - } catch (err) { - this.handleError(res, err as Error); - } - }, - ); - - app.route('/api/v3/:network/dapps-staking/rewards/:period').get(async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves dapps staking rewards for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year', - required: true, - enum: ['1 day', '7 days', '30 days', '90 days', '1 year'] - } - #swagger.parameters['transaction'] = { - in: 'query', - description: 'The Reward Event transaction type. Supported values: Reward, BonusReward, DAppReward', - required: false, - type: 'string', - enum: ['Reward', 'BonusReward', 'DAppReward'] - } - */ - res.json( - await this._dappsStakingEvents.getDappStakingRewards( - req.params.network as NetworkType, - req.params.period as PeriodType, - req.query.transaction as RewardEventType, - ), - ); - }); - - app.route('/api/v3/:network/dapps-staking/rewards-aggregated/:address/:period').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves dapps staking rewards for a given network and period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['address'] = { - in: 'path', - description: 'User address or contract address who received rewards', - required: true - } - #swagger.parameters['period'] = { - in: 'path', - description: 'The period type. Supported values: 1 day, 7 days, 30 days, 90 days, 1 year', - required: true, - enum: ['1 day', '7 days', '30 days', '90 days', '1 year'] - } - */ - res.json( - await this._dappsStakingEvents.getDappStakingRewardsAggregated( - req.params.network as NetworkType, - req.params.address as string, - req.params.period as PeriodType, - ), - ); - }, - ); - - app.route('/api/v3/:network/dapps-staking/period-aggregated/:period').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves aggregated period data (stakes and rewards per dApp) for the given dApp staking period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['period'] = { - in: 'path', - description: 'dApp staking period number.', - required: true, - } - */ - try { - res.json( - await this._dappsStakingEvents.getAggregatedPeriodData( - req.params.network as NetworkType, - Number(req.params.period), - ), - ); - } catch (err) { - this.handleError(res, err as Error); - } - }, - ); - - app.route('/api/v3/:network/dapps-staking/staker-aggregated/:address').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves aggregated period data for the given staker containing all stakes and rewards per period.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['address'] = { - in: 'path', - description: 'Staker address.', - required: true, - } - */ - try { - res.json( - await this._dappsStakingEvents.getAggregatedStakerData( - req.params.network as NetworkType, - req.params.address, - ), - ); - } catch (err) { - this.handleError(res, err as Error); - } - }, - ); - - app.route('/api/v3/:network/dapps-staking/staker-aggregated-total/:address').get( - async (req: Request, res: Response) => { - /* - #swagger.description = 'Retrieves aggregated period data for the given staker containing sum of all rewards claimed and the current period stake.' - #swagger.tags = ['Dapps Staking'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - #swagger.parameters['address'] = { - in: 'path', - description: 'Staker address.', - required: true, - } - */ - try { - res.json( - await this._dappsStakingEvents.getTotalAggregatedStakerData( - req.params.network as NetworkType, - req.params.address, - ), - ); - } catch (err) { - this.handleError(res, err as Error); - } - }, - ); - app.route('/api/v3/:network/dapps-staking/get-period-range/:period').get( async (req: Request, res: Response) => { /* @@ -528,5 +101,11 @@ export class DappsStakingV3Controller extends ControllerBase implements IControl } }, ); + + RETIRED_ROUTES.forEach((route) => { + app.route(route).get(async (_req: Request, res: Response) => { + this.handleRetired(res); + }); + }); } } diff --git a/src/controllers/TokenStatsController.ts b/src/controllers/TokenStatsController.ts index 2b781f3..3f10dee 100644 --- a/src/controllers/TokenStatsController.ts +++ b/src/controllers/TokenStatsController.ts @@ -274,20 +274,11 @@ export class TokenStatsController extends ControllerBase implements IControllerB }); /** - * @description Total issuance history. + * @description Total issuance history. Retired together with the dApp staking indexer. */ - app.route('/api/v1/:network/token/supply-history/').get(async (req: Request, res: Response) => { - /* - #swagger.description = 'Retreives total supply history at the beginning of a new dApp staking era for a given network and period.' - #swagger.tags = ['Token'] - #swagger.parameters['network'] = { - in: 'path', - description: 'The network name. Supported networks: astar, shiden, shibuya', - required: true, - enum: ['astar', 'shiden', 'shibuya'] - } - */ - res.json(await this._statsService.getTotalIssuanceHistory(req.params.network as NetworkType)); + app.route('/api/v1/:network/token/supply-history/').get(async (_req: Request, res: Response) => { + // #swagger.ignore = true + this.handleRetired(res); }); } } diff --git a/src/data/dappStakingSnapshot.astar.json b/src/data/dappStakingSnapshot.astar.json new file mode 100644 index 0000000..8a9d4cc --- /dev/null +++ b/src/data/dappStakingSnapshot.astar.json @@ -0,0 +1,1004 @@ +{ + "indexedToBlock": 13704051, + "votingStartBlocks": [ + 5514935, + 6393334, + 7271734, + 8150134, + 9085519, + 10860078, + 12616878 + ], + "unregisteredDapps": [ + { + "contractAddress": "0x1d10ceef0c43897aa9d16745bfbdeb49ebaf2b09", + "dappId": 36, + "beneficiary": null, + "owner": "XLtah1f9vJzWKE4Sbck851ArDQus1hAEaN6jtJcNQRujcDB", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1733303292000", + "unregistrationBlockNumber": 7595123 + }, + { + "contractAddress": "0x695cef87e396c9101212c19261728022705d7d69", + "dappId": 18, + "beneficiary": null, + "owner": "aLd6WKj9yLaGNzDqhnXFmgDvM4MWJqNBcN2gjatusB9eijH", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x158a08bcfd8821ba5ed252fd6b13d7013455b2a2", + "dappId": 62, + "beneficiary": null, + "owner": "aPUYjN4yYazE7uYxfYZ5eT6a2211ZYANTaK4HUUqPm3LFgR", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1732624206000", + "unregistrationBlockNumber": 7539623 + }, + { + "contractAddress": "0xed3e34fbe7b453bc5f7d263f42a2c28fb974d207", + "dappId": 47, + "beneficiary": null, + "owner": "ZZZgswWp73ymRVpMu84bNfQERLyV9XR6T6DrozRxMdwT6Ez", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1763139168000", + "unregistrationBlockNumber": 11065942 + }, + { + "contractAddress": "0x50a64d05bb8618d8d96a83cbbb12b3044ec3489a", + "dappId": 50, + "beneficiary": null, + "owner": "ZvS4S5tJfj1RLV8tqhZ31fEKmUgYivC8NZaRjmhoAEPFRoS", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1763560530000", + "unregistrationBlockNumber": 11133492 + }, + { + "contractAddress": "0x2efbe87a44ac19b6ec50d26218e6d05f2a1a28de", + "dappId": 7, + "beneficiary": null, + "owner": "bBzijVAQduMX9qXpyUhjE1KmToEgnKGnYLsACctqiBZZ5jR", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1765809600000", + "unregistrationBlockNumber": 11489803 + }, + { + "contractAddress": "0xa99ee26419c8bd8dc776934df2c00649e132d674", + "dappId": 61, + "beneficiary": null, + "owner": "WwjA4NLgbAKgapEvKf86LNk7gcqSQhsNUTN2AXSc6JPjQf4", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1763560506000", + "unregistrationBlockNumber": 11133489 + }, + { + "contractAddress": "0xc8b9dbcd14c122764e17ba686ab6448e9d5a0c3d", + "dappId": 32, + "beneficiary": null, + "owner": "aWCuUe7wCp3N6ir1f2sgvFPtmBxopnPh1LNwErQ4YqHAfAE", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x4926de018c54511ce2d3be1a0e646725f57155e6", + "dappId": 27, + "beneficiary": null, + "owner": "YCx2LEvMzjG7tBbdbfRNTsexU3FvTjZG3PN4bmJ5nx28XtB", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x862e9ed0e5643dceb579fc31d59c6113ce2790d7", + "dappId": 15, + "beneficiary": null, + "owner": "bETxXC8XYCa7ZA3WWA1X1j5P5yZMMkpVBuLRjwBBKPb8LoK", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1763560758000", + "unregistrationBlockNumber": 11133531 + }, + { + "contractAddress": "ZdpeaiK28o6DzkdVJardFTZEJTAHKG3HgJn5ZPgsPh345Hg", + "dappId": 33, + "beneficiary": null, + "owner": "WYYVuTdvqyhJbRApoZnVExN6BnLpehFn9kmnJpQwjz12bn3", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xabf7230e022c9146df9b4dbed97e73cf61d612b8", + "dappId": 60, + "beneficiary": null, + "owner": "Wwfs24NNBLsdN9BHHj29spDsq5vkjk771dxPvMrXwraLywn", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1763139186000", + "unregistrationBlockNumber": 11065945 + }, + { + "contractAddress": "0x569b344ad6bf087a285f0d415d0066028921d873", + "dappId": 48, + "beneficiary": null, + "owner": "YFdx1HN4Xma2BzaceHA6vpAYbt397DZnDqDnvuDePYMwhKc", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1734909390000", + "unregistrationBlockNumber": 7725600 + }, + { + "contractAddress": "0x74cc66cd0cf57bb2a0f237c89bcf8db92d3721a8", + "dappId": 37, + "beneficiary": null, + "owner": "XMAHssEGJvaFyvXYYmuWDXvzCx4oLY5tGnvPLkviMVW4AYd", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1768935936000", + "unregistrationBlockNumber": 11973476 + }, + { + "contractAddress": "0x51a6ca8dbfea1b19b15037460c14f4b0f80496d7", + "dappId": 23, + "beneficiary": null, + "owner": "ZoByK2wayrCHie2GstYZYoKggwF6X1o1NJuXWYmB7ySosV5", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1741392840000", + "unregistrationBlockNumber": 8254748 + }, + { + "contractAddress": "0x79f916baa98323814d406a67e954cc08ed14a7b8", + "dappId": 49, + "beneficiary": null, + "owner": "be8WtwsrvLUrJ5tA5Ht3BjKpajBMkRtYmURTa7BqNB6QZUA", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1737387240000", + "unregistrationBlockNumber": 7927200 + }, + { + "contractAddress": "0xcb1c5353097da08b665c6d4395104afe6374b509", + "dappId": 0, + "beneficiary": null, + "owner": "XdFFaA9S31uQ9upPyKBGXcrYhFN7jtBkDYLDbDfc1VKaV8W", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1765809618000", + "unregistrationBlockNumber": 11489807 + }, + { + "contractAddress": "a8SVGV6X5vpZyq85A9mscME9Y7k91LGbhfpB7KjcbtDDUHK", + "dappId": 58, + "beneficiary": null, + "owner": "ZNr4n9qc5fAap57oqoSazLpqqauQLzCTVXfKgKJsBp8t4Gr", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1738004640000", + "unregistrationBlockNumber": 7977600 + }, + { + "contractAddress": "0x03065e84748a9e4a1aebef15ac89da1cdf18b202", + "dappId": 22, + "beneficiary": null, + "owner": "a9w3moGheemy9PwBDrpvUrQKhbY3Hpzc8fGGEH3TjpiJ7Pp", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1733407284000", + "unregistrationBlockNumber": 7603592 + }, + { + "contractAddress": "0x8bedbe92a8c139932853eca70cc2586f9aef04ed", + "dappId": 26, + "beneficiary": null, + "owner": "aNkovLnKi2q5KLTyjvQFShdemhaQ1mwGcXDkdf81hvLMopX", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1745943240000", + "unregistrationBlockNumber": 8628648 + }, + { + "contractAddress": "0x843f83a60e1b5a3b6437f60439f0398ad788505c", + "dappId": 29, + "beneficiary": null, + "owner": "aLLhj6x213r7hDM9VVjJdLuw7NCJYznnDakEAa7mZTTGZaN", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x7b2152e51130439374672af463b735a59a47ea85", + "dappId": 39, + "beneficiary": null, + "owner": "ashiYo9RUjSj2f5hUbZY83FCy1ePkf54SFzD1CsZTgmC4qi", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x733ebcc6df85f8266349defd0980f8ced9b45f35", + "dappId": 64, + "beneficiary": null, + "owner": "ZP8rbjrkyf5Qkjr32fEy3n6av2nPzHh6Egv62Vu8kgEwZ8Z", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x4271bd392c0ea7a668025a29287ae8be4efd865e", + "dappId": 63, + "beneficiary": null, + "owner": "XAAqKgEAdKw3N6tLuJM8RhiGE4DLwSxigGqahF5UBzfFcKL", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x8b5d62f396ca3c6cf19803234685e693733f9779", + "dappId": 56, + "beneficiary": null, + "owner": "W3RJVe6n1i3sFhbitDYHBJqq5aQt1F3vi2384tSdccuZxEp", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x992bad137fc8a50a486b5c6375f581964b4a15fc", + "dappId": 31, + "beneficiary": null, + "owner": "ZwDkW3D3Z417kFDSh6ez9xhUWpTn1c1DAKZHUQCZXZeMqFN", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xc5b016c5597d298fe9ed22922ce290a048aa5b75", + "dappId": 12, + "beneficiary": null, + "owner": "Wmh1EtzS55Yu7nxMmszk2z7oPwbhDpzVn4v6hAnVTfGHcRY", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "0xc4335b1b76fa6d52877b3046eca68f6e708a27dd", + "dappId": 40, + "beneficiary": null, + "owner": "b9AB1qFXsw81RuTBQ1sCP6PQ6k27QXWoe7VHrv9m6iwmBRK", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x190da1b9fa124bd872e9166ba3c7dd656a11e8f8", + "dappId": 21, + "beneficiary": null, + "owner": "YkVPYjv5SgqRUqi67eqsKxGDv5XRdRspgLJEwWPBmuKj86y", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1739236452000", + "unregistrationBlockNumber": 8078400 + }, + { + "contractAddress": "0xa5efb5bf75bbb607dc243707a83f2af5ed4e9813", + "dappId": 67, + "beneficiary": null, + "owner": "ZqpPKt2sk2Xwd1YgYq8UvPF3JJDJ7XcEKFCcybYTeYDaigC", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1760398296000", + "unregistrationBlockNumber": 10617487 + }, + { + "contractAddress": "0x8489f4554790f5a103f2b0398537eaee68b73884", + "dappId": 53, + "beneficiary": null, + "owner": "WGYLrLw8TPjp1ynU9AiwZtanc7B2CMtB43ssKmawDwfoUsZ", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1746519432000", + "unregistrationBlockNumber": 8675301 + }, + { + "contractAddress": "XRhquqkD8yxYNjQWNb3NGZ7ypxpNwxpA6hWAD3QBh4vTFJW", + "dappId": 57, + "beneficiary": null, + "owner": "Z72w8QNfMmbvq6VJ82yPd2giVHezNtpzVc3ZeSbCPu5j5EV", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1736775072000", + "unregistrationBlockNumber": 7877397 + }, + { + "contractAddress": "0x96fb7eb4419fccf7fd97fc6e39ee1f0541c12508", + "dappId": 6, + "beneficiary": null, + "owner": "b1xCL3XGCjLrS2aZnUifnpuK9gCepGcsWboffjaR4F3tVuP", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x71abbdbb8cce734263414b9e93afb8250b18bc1a", + "dappId": 59, + "beneficiary": null, + "owner": "b1ymfVcP5vsT2ZPAWwVs6e2ecNWdFTGWfB8vzWixnyYacam", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xa782e40252e557d9e270650243546dbcd879d995", + "dappId": 66, + "beneficiary": null, + "owner": "YQ3S4AGrjyMndkjJuzup1fsDHYsD6EZ9BSkhzkFtNRhjDS2", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x322ab0bad883bde616208f04dab264c86a9b0765", + "dappId": 2, + "beneficiary": null, + "owner": "ZRJ4wcGuf9KFqg1NB6wPctUwd7WcHo9LdBFzskEdSqiH52t", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x22e1aa6bafb9965523cc33a5bfd2e4d3326a23e4", + "dappId": 1, + "beneficiary": null, + "owner": "anXvpdbMqS46xWb4tsF7BAhVwHsbwG3bmMCFQF2ddSsod9g", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xcca488aeef7a1d5c633f877453784f025e7cf160", + "dappId": 13, + "beneficiary": null, + "owner": "aChCmpvZat1Khi1QhnBs93ouXKodCGGNshiLaQ4e6QRRDEQ", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x70d264472327b67898c919809a9dc4759b6c0f27", + "dappId": 42, + "beneficiary": null, + "owner": "YewXn3eSdX5XKqwem27dXnbsWPtFsnzgXfdX6iNVUEGmPtw", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1764684342000", + "unregistrationBlockNumber": 11310360 + }, + { + "contractAddress": "WW4zHhyvhfWbDtt7nushXbp4gEYr7xqXijUZDAGXuLzMAm9", + "dappId": 28, + "beneficiary": null, + "owner": "YkqeedMEm6i8fFiwgbA4AHKespArFCfi8j3znqqx5wtEyPy", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x0c5e3eaf962085821261cd7147d7b9815e8809cf", + "dappId": 44, + "beneficiary": null, + "owner": "aG8tpBgh6MHcAPGBj2Z8sVVXTD4tyQi76twHhcvvsSAi9sK", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "bYLgJmSkWd4S4pTEacF2sNBWFeM4bNerS27FgNVcC9SqRE4", + "dappId": 5, + "beneficiary": null, + "owner": "Zxqwap9tKnSaJuzoGzPrYzf13pZ63XUEngv8nVRxvopnW5N", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1746699216000", + "unregistrationBlockNumber": 8688397 + }, + { + "contractAddress": "acy3gmgpSdvn6qL1oMKsNJdsZfXKF6uKLT1hjcX73MWUZh3", + "dappId": 43, + "beneficiary": null, + "owner": "a2AGGzXzeNRUoh19nBVh5zYWF8KmMzu8iSoYA6DZcvpQNqG", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1760398314000", + "unregistrationBlockNumber": 10617490 + }, + { + "contractAddress": "0x6d47349ce5bae5394730125e55f086d0c863f01f", + "dappId": 3, + "beneficiary": null, + "owner": "YJRfL8FvfVLnvnKwvBWr1Bnav1SH4WztHhwspeAD29mt6xa", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xb0a74ee0732efb430a0c07dc8a93c104033c6eaa", + "dappId": 30, + "beneficiary": null, + "owner": "XoDc3yb69d2XUCP8LYjHn2j6r9Xx1P8PKHWFcsb3Z1mfkSL", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "0x2fb9a49579073725453981b786a141f748beec67", + "dappId": 45, + "beneficiary": null, + "owner": "ZCn6kTLHMRJCJrC88DegLh2jMuPxTCdxQZ4fMmHjceoWQCC", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1760398278000", + "unregistrationBlockNumber": 10617484 + }, + { + "contractAddress": "0x7bae21fb8408d534adfefcb46371c3576a1d5717", + "dappId": 10, + "beneficiary": null, + "owner": "YFZUVr9JRE3AMZ8CTjedJkvv9E7q2jcEvQJ8Y9vBgRYhPWc", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1745508732000", + "unregistrationBlockNumber": 8592894 + }, + { + "contractAddress": "0xa82a8c0a75a7180c14533f274f84547355faa726", + "dappId": 19, + "beneficiary": null, + "owner": "YkU1KaPGRg4cYusMxsjDwk7NofLHjo6KjiPLjdQBHRXg7uw", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "0xa1019535e6b364523949eaf45f4b17521c1cb074", + "dappId": 38, + "beneficiary": null, + "owner": "bEKpmuoP86E9JSA5kzLHkFA9R2FHWyoX6dKX3XtvtL3rnKJ", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x431d5dff03120afa4bdf332c61a6e1766ef37bdb", + "dappId": 24, + "beneficiary": null, + "owner": "ZUo6331Sq9Fbt4Smx3XBuC2PBEV8s6sXkaJxUawgUqmRYfg", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "Yi5DLYWxrqzCoGT2xcUM4qLAfRyhN2tqWjMkaEc5MeFkp1j", + "dappId": 41, + "beneficiary": null, + "owner": "W351MEYyAqZbNWpAtrEcrDBx6HJkRgyh2qac5XuEpbhB1mr", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xa0e232d596d6838d39ddde9b63916b42246be15e", + "dappId": 54, + "beneficiary": null, + "owner": "b449sv9HhoTkrBor6Y6GPgv77mfqANCfXAi716sDN7BWm6t", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x7672f18994d876a319502f356efea726c4354f39", + "dappId": 51, + "beneficiary": null, + "owner": "YXPD211sCj2gjrePAzsTtusqBbXmHp9A56whRXonz97TGKu", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "0xa602d021da61ec4cc44dedbd4e3090a05c97a435", + "dappId": 14, + "beneficiary": null, + "owner": "WdwRSePZTEa61BJNqu3cmoMiTE4ukp3xHKnNvP1mtugKL52", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "0xdd3983f649fc07e4f25dae90bea84feb92aaad45", + "dappId": 25, + "beneficiary": null, + "owner": "ajJpRp9SHeXCq9iimZcexBE7YmFmTQJEKzBVjpbbyHooHut", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1764684294000", + "unregistrationBlockNumber": 11310352 + }, + { + "contractAddress": "0x2b1fe33cb7264dba6331f54012f04133395fde44", + "dappId": 55, + "beneficiary": null, + "owner": "akY75uY98EaMe18NidbpEkJeRZFUurtY3w9hK5jchDgAUxe", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x77ca5df58607a6e57e537f0492bd82e932fee7ac", + "dappId": 34, + "beneficiary": null, + "owner": "Vwi8eqao6gxRK7xE2ENf6etbiQu4VHrbVhXK3HjN9jivSWw", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xc3e407a23e02ecf53348d3634f9c2ffe8028d204", + "dappId": 8, + "beneficiary": null, + "owner": "aBxULEP834pdox7KEgP6fsEcA2cZArb2komDnMDLa9Ft6Va", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xe785a37c9d5f3377cbb5b8bf7e9db03ddd440449", + "dappId": 46, + "beneficiary": null, + "owner": "ZWu5X7Sb83u3cEefQ8hG8MwLeoha4UbpZQbnNjXJAiG1Vaf", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xfade3a4ecd0a6c7ac9c3ba2ea644a824b7a091bb", + "dappId": 65, + "beneficiary": null, + "owner": "XG2PtNBzbVf2wzjZv5oAtmhxA6XQsc5bTHrsFpvDWX7kw4v", + "state": "Unregistered", + "registeredAt": "1707811524207", + "registrationBlockNumber": 5522123, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xdcc0da7d6f04a95e3a4534e5e24850efcd2f9b35", + "dappId": 68, + "beneficiary": null, + "owner": "XXKdnQR2V4wozs8N2eJWZVRGRc2Juk8r8Frk2zKdTVHKFrR", + "state": "Unregistered", + "registeredAt": "1708067940855", + "registrationBlockNumber": 5543157, + "unregisteredAt": "1764955704000", + "unregistrationBlockNumber": 11353427 + }, + { + "contractAddress": "0xd843daaaef666b89b013f12741b3a60a4ea87e5c", + "dappId": 69, + "beneficiary": null, + "owner": "YiU2bZn5gikmvEPetzexzewVBC8AypsXa2izAF1ULWr6Goj", + "state": "Unregistered", + "registeredAt": "1708068660747", + "registrationBlockNumber": 5543216, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x46c759fc44edb4faa60a76a11898477f9b8d822d", + "dappId": 70, + "beneficiary": null, + "owner": "XDTAqd8vCpX1mDbU6Bb3jjBYBPCb9UiW5DiyAQvDykfkJ7Q", + "state": "Unregistered", + "registeredAt": "1708089096341", + "registrationBlockNumber": 5544898, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x48b380aa4c3b82c4a88548335b948c8199fa98b1", + "dappId": 71, + "beneficiary": null, + "owner": "aja8WxDTzNkxttWGv4ndFXWgYmfFcvDyE3AQKikrrcPQnTj", + "state": "Unregistered", + "registeredAt": "1708774812429", + "registrationBlockNumber": 5601328, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xa094e566b61b3c2d88acf7cc15e3dd0fa83f32af", + "dappId": 72, + "beneficiary": null, + "owner": "WW2CMXcn7UfnUAcDfUBHzJHAtoBdTV4r2V9eayeTWmSo277", + "state": "Unregistered", + "registeredAt": "1708924140659", + "registrationBlockNumber": 5613619, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x26c89cfc3323cb4054be1df2d9c4a3eedb3368da", + "dappId": 73, + "beneficiary": null, + "owner": "aRxv5MQtqoYjW3UFV6gxE3TbWuNnXeXLnirLufHVD9LiE4x", + "state": "Unregistered", + "registeredAt": "1709057166380", + "registrationBlockNumber": 5624554, + "unregisteredAt": "1736147064000", + "unregistrationBlockNumber": 7826400 + }, + { + "contractAddress": "0x32f35525bb480375064b989b9b41bc47e0d01faa", + "dappId": 75, + "beneficiary": null, + "owner": "WgYKr9CH2YLR8b51Bk1Dhv1Gu5biJbJWUywx5M179Jz9iCX", + "state": "Unregistered", + "registeredAt": "1709546214256", + "registrationBlockNumber": 5663401, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xd2c2e0f97800a909e819beb08b43127ae217f6db", + "dappId": 76, + "beneficiary": null, + "owner": "bFLVPSesYZ7s9NhV7kHFjy73gBcg9uHCCFwenVY9ADgrbv9", + "state": "Unregistered", + "registeredAt": "1710313693192", + "registrationBlockNumber": 5726097, + "unregisteredAt": "1739236452000", + "unregistrationBlockNumber": 8078400 + }, + { + "contractAddress": "0xfbc8cc3a9078037efe8531e9236dc6d6234da118", + "dappId": 77, + "beneficiary": null, + "owner": "YfoeeXCWhWKQiRPCSbzTuXMVwGu8CiQ477NUPtgwc9e1Uvd", + "state": "Unregistered", + "registeredAt": "1710313789343", + "registrationBlockNumber": 5726105, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x544b7fa4a8e2c301ef82b0e0848d5b68ac1e3a49", + "dappId": 78, + "beneficiary": null, + "owner": "ZSJ2vBeKwDWU5C2K3DWj9RZji41XJXZXGXKNoGS166AvLUt", + "state": "Unregistered", + "registeredAt": "1710803208716", + "registrationBlockNumber": 5766280, + "unregisteredAt": "1741392840000", + "unregistrationBlockNumber": 8254748 + }, + { + "contractAddress": "0x49c321e734b9e431fb4dabbe406859cf11f0c3b6", + "dappId": 79, + "beneficiary": "ZS5kTRJnHVV5BMHr86UaCL52DS8h5foESPqacw98UedNar9", + "owner": "YwFEDzuShMsPXz595B3oDuA1U3CNFyVYwRH7g5Pc8aNALnA", + "state": "Unregistered", + "registeredAt": "1711436628441", + "registrationBlockNumber": 5818312, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x98aaf31e5ddd49b2465c15165815608ecec48a11", + "dappId": 80, + "beneficiary": null, + "owner": "ZPmHgnThUcWs9nEfhWBcwR3ZyEB8r75yiBiuf8bkf7F4kTT", + "state": "Unregistered", + "registeredAt": "1711436880376", + "registrationBlockNumber": 5818333, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "0x00000000001594c61dd8a6804da9ab58ed2483ce", + "dappId": 81, + "beneficiary": null, + "owner": "a2P3V2oZLhRVUkCPfBBtxjwvey8eLQh9yNksgQ8A5z9FFBu", + "state": "Unregistered", + "registeredAt": "1713852000324", + "registrationBlockNumber": 6016802, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x9f5b097ad23e2cf4f34e502a3e41d941678877dc", + "dappId": 82, + "beneficiary": null, + "owner": "WEJoHYriUUSGCXXkU1Z5EnAvQJi9t8iGEQxsxonkCpeLQAB", + "state": "Unregistered", + "registeredAt": "1713852060185", + "registrationBlockNumber": 6016807, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "WVD7TgCncPKbWs84E66jLrycP2ZaAXdiDJpgKx6LT3ZopCp", + "dappId": 83, + "beneficiary": null, + "owner": "W8MKkyFyKWdfVtvYgkGwqekMcX9dDXESTyLxsjmzEpP9dLg", + "state": "Unregistered", + "registeredAt": "1714705560409", + "registrationBlockNumber": 6086899, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "0xae1bb2090fb748dd28e82cb632206836d9ef3c85", + "dappId": 84, + "beneficiary": null, + "owner": "a5EXW8GyHar3K1ZPa7yVPnqRoMbVdRUvdcgA4iQjwwsecFC", + "state": "Unregistered", + "registeredAt": "1717401558445", + "registrationBlockNumber": 6309043, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xc3a0dd8465dd41c8ffcf03906b80b5b7d148ea1c", + "dappId": 85, + "beneficiary": null, + "owner": "atCf32Kgj3WkhyP5d5w7fgeWRSJg3jo49gqkaJB13osT19F", + "state": "Unregistered", + "registeredAt": "1717675320285", + "registrationBlockNumber": 6331588, + "unregisteredAt": "1760407476000", + "unregistrationBlockNumber": 10618999 + }, + { + "contractAddress": "0x9640da05bee2d15cad7fc21691d36e88c7782fac", + "dappId": 86, + "beneficiary": null, + "owner": "XMFNZARStPoCbLfiuFgSrB1rDyjmE8n2qEeL7S6UqeqCYSv", + "state": "Unregistered", + "registeredAt": "1718373618352", + "registrationBlockNumber": 6388890, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x4dbd6a4a6896dad6a3c11ce9f32cc4d6ce5b97be", + "dappId": 87, + "beneficiary": null, + "owner": "Zy89RtxHhimk8LNtjc3ZMC7oZvPxCs38zd7XE3mPXXvu7RH", + "state": "Unregistered", + "registeredAt": "1718373666304", + "registrationBlockNumber": 6388894, + "unregisteredAt": "1773134784000", + "unregistrationBlockNumber": 12576129 + }, + { + "contractAddress": "0xd44c09269d195f3b2ddf4238d2444da19599dc56", + "dappId": 88, + "beneficiary": null, + "owner": "YtdyHZ5wSkofE5SK6N7EAT6k9h16cX4aG5DEvWSwSbbokVq", + "state": "Unregistered", + "registeredAt": "1718938920262", + "registrationBlockNumber": 6435447, + "unregisteredAt": "1741392840000", + "unregistrationBlockNumber": 8254748 + }, + { + "contractAddress": "0x78472344de9ef8d4fdf0deb0df1ebdadc895b440", + "dappId": 89, + "beneficiary": null, + "owner": "WSwZvpj7u9VdrzfJXnrE5GHgi74LWSato6jsegZeaKEdg1A", + "state": "Unregistered", + "registeredAt": "1719586957535", + "registrationBlockNumber": 6488383, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xa5d07a1804f60a663b5a7eb10b9d0e74ed3547a5", + "dappId": 90, + "beneficiary": null, + "owner": "axptnJsnUWuxtbVQpdnuLZvLYKhfjU9LswJwiByAuz35zvD", + "state": "Unregistered", + "registeredAt": "1720059726580", + "registrationBlockNumber": 6527444, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x89ed50cec44a3db4186ba54cdf575ec140937c55", + "dappId": 91, + "beneficiary": null, + "owner": "aCVweEHsJYeE7gbd88zvccqBX53PEttrdwJYLRydFrXiRCA", + "state": "Unregistered", + "registeredAt": "1721238900733", + "registrationBlockNumber": 6624686, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xb0369b70ab98dcd40188b6cf2b2b002d74e1c42a", + "dappId": 92, + "beneficiary": null, + "owner": "ZLktMBPpV8KUGNADv5sVKzA5p8cLoLWfZGLB4VsgAW6ebSN", + "state": "Unregistered", + "registeredAt": "1722080160450", + "registrationBlockNumber": 6692833, + "unregisteredAt": "1768844718000", + "unregistrationBlockNumber": 11960113 + }, + { + "contractAddress": "0xc273ea964b5c975fdbba9df9624649f1038aaf9b", + "dappId": 93, + "beneficiary": null, + "owner": "YMRAQJDvfcouYYZMQWktKcdiBCGfUHMTSC1Sbrf3t29CY7M", + "state": "Unregistered", + "registeredAt": "1722080214351", + "registrationBlockNumber": 6692836, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "WW2BUUnJiZZQ4B3qKwbBRfYPDWR8GsqhqmQdt3NiRESLDfo", + "dappId": 94, + "beneficiary": null, + "owner": "Yqsi4q2qYPHhujTNqceFq5KpF6bbptHzh8U9BkVjvae6XQE", + "state": "Unregistered", + "registeredAt": "1723291344000", + "registrationBlockNumber": 6784838, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xa3d21742eefd831ffbb4238ca1c6b42ec389f748", + "dappId": 98, + "beneficiary": null, + "owner": "ZCP2QWT5px4MmWMJQnoigj4p3khJb8qjfSYCtt6wyT1gCpe", + "state": "Unregistered", + "registeredAt": "1750954176000", + "registrationBlockNumber": 9097542, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x6bdb6a1f51e81d5009b3397d17023f1f97f88b57", + "dappId": 100, + "beneficiary": null, + "owner": "XkwVwK13seJPaBaPWVQbZczras19x3kaJGk3y1tqeFG9NpT", + "state": "Unregistered", + "registeredAt": "1754551848000", + "registrationBlockNumber": 9673457, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0xee5f0fe1d30080f6b6e8bfc0eca039534f4fd237", + "dappId": 105, + "beneficiary": null, + "owner": "WQ213eB6Sxjxk9MqPgsBD21HTC3fntoLVn3yQSB21fBRhYU", + "state": "Unregistered", + "registeredAt": "1760431260000", + "registrationBlockNumber": 10622879, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + }, + { + "contractAddress": "0x13ec6b98362e43add08f7cc4f6befd02fa52ee01", + "dappId": 106, + "beneficiary": null, + "owner": "Zf7bccadVBoMSdghNw4kfz88EP92KzCcYsDAWu4AW7WSk44", + "state": "Unregistered", + "registeredAt": "1762455732000", + "registrationBlockNumber": 10954234, + "unregisteredAt": "1772180358000", + "unregistrationBlockNumber": 12437988 + } + ] +} diff --git a/src/data/dappStakingSnapshot.shibuya.json b/src/data/dappStakingSnapshot.shibuya.json new file mode 100644 index 0000000..6669469 --- /dev/null +++ b/src/data/dappStakingSnapshot.shibuya.json @@ -0,0 +1,115 @@ +{ + "indexedToBlock": 13318981, + "votingStartBlocks": [ + 5335616, + 5386015, + 5436415, + 5486815, + 5537215, + 5587615, + 5638015, + 5688415, + 5738815, + 5789215, + 5839615, + 5890015, + 5940415, + 5990815, + 6041215, + 6091615, + 6142015, + 6192415, + 6242815, + 6293215, + 6343615, + 6394015, + 6444415, + 6494815, + 6545215, + 6595615, + 6646015, + 6696415, + 6746815, + 6797215, + 6847615, + 6898015, + 6948415, + 6998815, + 7049215, + 7118307, + 7219107, + 7319907, + 7420707, + 7521507, + 7622307, + 7723107, + 7823907, + 7924707, + 8025507, + 8126307, + 8227107, + 8327907, + 8428707, + 8529507, + 8630307, + 8731107, + 8831907, + 8932707, + 9033507, + 9134307, + 9235107, + 9335907, + 9436707, + 9537507, + 9638307, + 9739107, + 9839907, + 9940707, + 10041507, + 10142307, + 10243107, + 10343907, + 10444707, + 10545507, + 10646307, + 10747107, + 10847907, + 10948707, + 11049507, + 11150307, + 11251107, + 11351907, + 11452707, + 11553507, + 11654307, + 11755107, + 11855907, + 11956707, + 12057507, + 12158307, + 12259107, + 12359907, + 12460707, + 12561507, + 12662307, + 12763107, + 12863907, + 12964707, + 13065507, + 13166307, + 13267107 + ], + "unregisteredDapps": [ + { + "contractAddress": "0xf3824888ecca4514dd776f0db38d6530ab8fb280", + "dappId": 1, + "beneficiary": null, + "owner": "YDFDMh78emMcyN67CtwiiKrCWH6tDNVPcKeEUckY9YjRdPe", + "state": "Unregistered", + "registeredAt": "1703139738073", + "registrationBlockNumber": 5335633, + "unregisteredAt": "1706261058121", + "unregistrationBlockNumber": 5593086 + } + ] +} diff --git a/src/data/dappStakingSnapshot.shiden.json b/src/data/dappStakingSnapshot.shiden.json new file mode 100644 index 0000000..7c6e55a --- /dev/null +++ b/src/data/dappStakingSnapshot.shiden.json @@ -0,0 +1,151 @@ +{ + "indexedToBlock": 15889477, + "votingStartBlocks": [ + 5876079, + 6315278, + 6754478, + 7193678, + 7632878, + 8468349, + 9346749, + 10225149, + 11103549, + 11981949, + 12860349, + 13738749 + ], + "unregisteredDapps": [ + { + "contractAddress": "0x602332522f85c2fc29603f1e26ff4a0a9b390ff2", + "dappId": 2, + "beneficiary": null, + "owner": "YhG92xFnS9G31SboDjBuLp799CmGzLHyJnL9EcECtTQ5mas", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0x2b9a7085afba278bec6bbffb399a3c042ed05046", + "dappId": 0, + "beneficiary": null, + "owner": "akZKtCjvFvTMfKayv6Uw8ARPiHKUgQqLtuyURhjxZv3D5z3", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0x4ffa8531733be6a390d884c597238d1067fa88ec", + "dappId": 5, + "beneficiary": null, + "owner": "XyKWzYcgR24MBZNHVLrGMDXT4iZY3dsB6oRdhpyU1vuZPhR", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0x0a5d6a6a34145b6e93611dac828d2a386caafaf5", + "dappId": 13, + "beneficiary": null, + "owner": "XMrzzASqaPj6mzR47z4wGuumGvhs72Lcn68vAP7mTWUWefX", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0xb4be4e9b44e3b2fcb63fe96f0117740240a54c73", + "dappId": 15, + "beneficiary": null, + "owner": "WtyKQ9HVKiwszrDj5PkFNbwLWfmuSny3QznFKBpwXRVDhKP", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0xb715b849cd7d8794fe29e3363efa8c419a68f6aa", + "dappId": 16, + "beneficiary": null, + "owner": "YonjJybdevn8u4bVTgJhv5rijbyKxfSRj7tVYS9NC9xoB5q", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0x072416b9df2382a62df34956dffb7b0addf668f9", + "dappId": 20, + "beneficiary": null, + "owner": "ZvZjsmsGmLcD5RyWBgdrhamT2pdYrfTxNoHPdRz2CwFtJzm", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0xec6b921f67e58028c903cd5f96c65847c42e5fc7", + "dappId": 23, + "beneficiary": null, + "owner": "XFgNUQh8Ad83sRXsvUEjiaruvsru7SFPUC766fBXPiA9QAj", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0x8a74b5ee7b1f5c058a83d4c675e267fd000730dc", + "dappId": 24, + "beneficiary": null, + "owner": "YefVfauiCA24uDLENbTxp952LVU8Lvb7BqneNZkZE7ErE5J", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0xe0f41a9626ade6c2bfaade6e497dc584bc3e9dc5", + "dappId": 25, + "beneficiary": null, + "owner": "XM8yY9rZaGHj6LEKwjMwS2KFysqAvpRmwgVFA3q8kKtkosi", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0xae4fe19acd45e405c4cfbea281c7a3af20a10849", + "dappId": 6, + "beneficiary": null, + "owner": "ZRajKEZjoosLP6S8Kepq9mhwpPh2DrrAJCF72fJVZkuSWpn", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + }, + { + "contractAddress": "0x4d4e6e07d480f3aae931c31430bc61ea7ef29052", + "dappId": 10, + "beneficiary": null, + "owner": "ahKpuUxwS8qWzETuurEJFwJHJgVdEHMYQvaUWSDknbQGFBE", + "state": "Unregistered", + "registeredAt": "1707296190398", + "registrationBlockNumber": 5876089, + "unregisteredAt": "1771423242000", + "unregistrationBlockNumber": 13786940 + } + ] +} diff --git a/src/index.ts b/src/index.ts index 87364f7..2f232dd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import '@polkadot/api-augment'; import express from 'express'; import bodyParser from 'body-parser'; import * as functions from 'firebase-functions'; +import { defineSecret } from 'firebase-functions/params'; import cors from 'cors'; import container from './container'; import { IControllerBase } from './controllers/IControllerBase'; @@ -20,5 +21,7 @@ app.use(cors()); const controllers: IControllerBase[] = container.getAll(ContainerTypes.Controller); controllers.forEach((controller) => controller.register(app)); -functions.runWith({ memory: '2GB' }); -exports.app = functions.https.onRequest(app); +// Exposed to the function as process.env.COINGECKO_API_KEY. +const coingeckoApiKey = defineSecret('COINGECKO_API_KEY'); + +exports.app = functions.runWith({ secrets: [coingeckoApiKey] }).https.onRequest(app); diff --git a/src/services/BurnService.ts b/src/services/BurnService.ts deleted file mode 100644 index 0101458..0000000 --- a/src/services/BurnService.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { injectable } from 'inversify'; -import { NetworkType } from '../networks'; -import axios from 'axios'; -import { DappStakingV3IndexerBase } from './DappStakingV3IndexerBase'; - -export type BurnEvent = { - blockNumber: number; - timestamp: number; - amount: bigint; - user: string; -}; - -export interface IBurnService { - getBurnEvents(network: NetworkType): Promise; -} - -@injectable() -export class BurnService extends DappStakingV3IndexerBase implements IBurnService { - public async getBurnEvents(network: NetworkType): Promise { - this.GuardNetwork(network); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - burns(orderBy: id_ASC) { - blockNumber - timestamp - user - amount - } - }`, - }); - - return result.data.data.burns; - } catch (e) { - console.error(e); - return []; - } - } -} diff --git a/src/services/CoinGeckoPriceProvider.ts b/src/services/CoinGeckoPriceProvider.ts index e9ee539..592f117 100644 --- a/src/services/CoinGeckoPriceProvider.ts +++ b/src/services/CoinGeckoPriceProvider.ts @@ -1,4 +1,4 @@ -import axios from 'axios'; +import axios, { AxiosRequestConfig } from 'axios'; import { injectable } from 'inversify'; import { IPriceProvider, TokenInfo } from './IPriceProvider'; @@ -7,6 +7,21 @@ import { IPriceProvider, TokenInfo } from './IPriceProvider'; */ type CoinGeckoTokenInfo = { id: string; symbol: string; name: string }; +// Symbols are not unique on CoinGecko, so native tokens are mapped explicitly. +const KNOWN_TOKEN_IDS: Record = { + astr: 'astar', + sdn: 'shiden', +}; + +/** + * CoinGecko demo API key, bound from Secret Manager (see src/index.ts). + * The keyless public API is heavily rate limited from shared cloud IPs. + */ +const getRequestOptions = (): AxiosRequestConfig => { + const apiKey = process.env.COINGECKO_API_KEY; + return apiKey ? { headers: { 'x-cg-demo-api-key': apiKey } } : {}; +}; + @injectable() export class CoinGeckoPriceProvider implements IPriceProvider { public static BaseUrl = 'https://api.coingecko.com/api/v3'; @@ -17,7 +32,7 @@ export class CoinGeckoPriceProvider implements IPriceProvider { if (tokenSymbol) { const url = `${CoinGeckoPriceProvider.BaseUrl}/simple/price?ids=${tokenSymbol}&vs_currencies=${currency}`; - const result = await axios.get(url); + const result = await axios.get(url, getRequestOptions()); if (result.data[tokenSymbol]) { const price = result.data[tokenSymbol][currency]; @@ -35,7 +50,7 @@ export class CoinGeckoPriceProvider implements IPriceProvider { if (tokenSymbol) { const url = `${CoinGeckoPriceProvider.BaseUrl}/simple/price?ids=${tokenSymbol}&vs_currencies=${currencies}`; - const result = await axios.get(url); + const result = await axios.get(url, getRequestOptions()); for (const [key, _] of prices) { if (result.data[tokenSymbol]) { @@ -58,6 +73,11 @@ export class CoinGeckoPriceProvider implements IPriceProvider { } private async getTokenId(symbol: string): Promise { + const knownId = KNOWN_TOKEN_IDS[symbol.toLowerCase()]; + if (knownId) { + return knownId; + } + if (!CoinGeckoPriceProvider.tokens) { // Cache received data since token list is a quite big. CoinGeckoPriceProvider.tokens = await this.getTokenList(); @@ -68,7 +88,7 @@ export class CoinGeckoPriceProvider implements IPriceProvider { private async getTokenList(): Promise { const url = `${CoinGeckoPriceProvider.BaseUrl}/coins/list`; - const result = await axios.get(url); + const result = await axios.get(url, getRequestOptions()); return result.data; } diff --git a/src/services/DappStakingV3IndexerBase.ts b/src/services/DappStakingV3IndexerBase.ts deleted file mode 100644 index b3b1398..0000000 --- a/src/services/DappStakingV3IndexerBase.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Guard } from '../guard'; -import { NetworkType } from '../networks'; -import { ServiceBase } from './ServiceBase'; - -export class DappStakingV3IndexerBase extends ServiceBase { - protected GuardNetwork(network: NetworkType) { - Guard.ThrowIfUndefined('network', network); - if (!['shibuya', 'shiden', 'astar'].includes(network)) { - throw new Error(`This method is not supported for the network ${network}`); - } - } - - protected getApiUrl(network: NetworkType): string { - // For local development: `http://localhost:4350/graphql`; - return `https://astar-network.squids.live/dapps-staking-indexer-${network}/v/v15/graphql`; - } -} diff --git a/src/services/DappsStakingEvents.ts b/src/services/DappsStakingEvents.ts index 125d8d7..a45d718 100644 --- a/src/services/DappsStakingEvents.ts +++ b/src/services/DappsStakingEvents.ts @@ -1,51 +1,47 @@ import { injectable, inject } from 'inversify'; -import axios from 'axios'; -import { formatEther } from 'ethers'; import type { NetworkType } from '../networks'; import { Guard } from '../guard'; -import type { TotalAmountCount, Triplet, Pair, PeriodType, StakerAmount } from './ServiceBase'; import type { IApiFactory } from '../client/ApiFactory'; import { ContainerTypes } from '../containertypes'; -import type { - DappStakingEventData, - DappStakingEventResponse, - DappStakingAggregatedData, - DappStakingAggregatedResponse, - PeriodDataResponse, - StakerPeriodDataResponse, - StakerPeriodTotalResponse, -} from './DappStaking/ResponseData'; -import type { IStatsIndexerService } from './StatsIndexerService'; -import { DappStakingV3IndexerBase } from './DappStakingV3IndexerBase'; +import { ServiceBase } from './ServiceBase'; +import { CacheService } from './CacheService'; +import astarSnapshot from '../data/dappStakingSnapshot.astar.json'; +import shidenSnapshot from '../data/dappStakingSnapshot.shiden.json'; +import shibuyaSnapshot from '../data/dappStakingSnapshot.shibuya.json'; export interface IDappsStakingEvents { - getDapps(network: NetworkType): Promise<[]>; - getStakingEvents( - network: NetworkType, - address: string, - startDate: string, - endDate: string, - limit?: number, - offset?: number, - ): Promise; - getAggregatedData(network: NetworkType, period: PeriodType): Promise; - getDappStakingTvl(network: NetworkType, period: PeriodType): Promise; - getDappStakingStakersCount(network: NetworkType, contractAddress: string, period: PeriodType): Promise; + getDapps(network: NetworkType): Promise; getParticipantStake(network: NetworkType, address: string): Promise; - getDappStakingStakersCountTotal(network: NetworkType, period: PeriodType): Promise; - getDappStakingStakersTotal(network: NetworkType, period: PeriodType): Promise; - getDappStakingLockersTotal(network: NetworkType, period: PeriodType): Promise; - getDappStakingLockersAndStakersTotal(network: NetworkType, period: PeriodType): Promise; - getDappStakingRewards(network: NetworkType, period: PeriodType, transaction: RewardEventType): Promise; - getDappStakingRewardsAggregated(network: NetworkType, address: string, period: PeriodType): Promise; - getDappStakingStakersList(network: NetworkType, contractAddress: string): Promise; - getAggregatedPeriodData(network: NetworkType, period: number): Promise; - getAggregatedStakerData(network: NetworkType, stakerAddress: string): Promise; - getTotalAggregatedStakerData(network: NetworkType, stakerAddress: string): Promise; getPeriodBlockRange(network: NetworkType, period: number): Promise<{ start: number; end?: number }>; } -export type RewardEventType = 'Reward' | 'BonusReward' | 'DAppReward'; +export type DappData = { + contractAddress: string; + dappId: number; + owner: string; + beneficiary: string | null; + state: 'Registered' | 'Unregistered'; + registeredAt?: string; + registrationBlockNumber?: number; + unregisteredAt?: string; + unregistrationBlockNumber?: number; +}; + +type Snapshot = { + indexedToBlock: number; + votingStartBlocks: number[]; + unregisteredDapps: DappData[]; +}; + +/** + * Last data exported from the retired dApp staking indexer (Subsquid), used for history that cannot be + * read from the chain: period boundaries and dApps unregistered before the snapshot block. + */ +const SNAPSHOTS: Record = { + astar: astarSnapshot as Snapshot, + shiden: shidenSnapshot as Snapshot, + shibuya: shibuyaSnapshot as Snapshot, +}; declare global { interface BigInt { @@ -57,59 +53,11 @@ BigInt.prototype.toJSON = function () { }; @injectable() -export class DappsStakingEvents extends DappStakingV3IndexerBase implements IDappsStakingEvents { - constructor( - @inject(ContainerTypes.ApiFactory) private _apiFactory: IApiFactory, - @inject(ContainerTypes.StatsIndexerService) private _statsService: IStatsIndexerService, - ) { - super(); - } - - public async getStakingEvents( - network: NetworkType, - contractAddress: string, - startDate: string, - endDate: string, - limit?: number, - offset?: number, - ): Promise { - Guard.ThrowIfUndefined('network', network); - Guard.ThrowIfUndefined('contractAddress', contractAddress); - Guard.ThrowIfUndefined('startDate', startDate); - Guard.ThrowIfUndefined('endDate', endDate); - - if (network !== 'astar') { - return []; - } +export class DappsStakingEvents extends ServiceBase implements IDappsStakingEvents { + private readonly dappsCache = new CacheService(10 * 60 * 1000); - const start = new Date(startDate); - const end = new Date(endDate); - - const query = `query MyQuery { - stakingEvents(where: { - contractAddress_eq: "${contractAddress}", - timestamp_gte: "${start.getTime()}", - timestamp_lte: "${end.getTime()}" - }, - orderBy: blockNumber_DESC, - limit: ${limit}, - offset: ${offset}) { - amount - blockNumber - contractAddress - id - timestamp - transaction - userAddress - } - }`; - - const result = await axios.post(this.getApiUrl(network), { - operationName: 'MyQuery', - query, - }); - - return result.data.data.stakingEvents; + constructor(@inject(ContainerTypes.ApiFactory) private _apiFactory: IApiFactory) { + super(); } public async getParticipantStake(network: NetworkType, address: string): Promise { @@ -127,524 +75,44 @@ export class DappsStakingEvents extends DappStakingV3IndexerBase implements IDap } } - public async getAggregatedData(network: NetworkType, period: PeriodType): Promise { - Guard.ThrowIfUndefined('network', network); - - if (network !== 'astar') { - return []; - } - - const range = this.getDateRange(period); - - const query = `query MyQuery { - groupedStakingEvents(where: { - timestamp_gte: "${range.start.getTime()}", - timestamp_lte: "${range.end.getTime()}" - }, orderBy: timestamp_DESC) { - amount - id - timestamp - transaction - } - }`; - - const result = await axios.post(this.getApiUrl(network), { - operationName: 'MyQuery', - query, - }); - - return result.data.data.groupedStakingEvents; - } - - public async getDappStakingTvl(network: NetworkType, period: PeriodType): Promise { + public async getDapps(network: NetworkType): Promise { this.GuardNetwork(network); - const range = this.getDateRange(period); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - tvlAggregatedDailies( - orderBy: id_ASC - where: { id_gte: "${range.start.getTime()}", id_lte: "${range.end.getTime()}" } - ) { - id - tvl - usdPrice - } - }`, - }); - - const indexedTvl = result.data.data.tvlAggregatedDailies.map( - (node: { id: string; tvl: number; usdPrice: number }) => { - return [node.id, node.usdPrice * Number(formatEther(node.tvl.toString()))]; - }, - ); - - // Concat TVL from staking v2 if needed. - const missingDays = this.getPeriodDurationInDays(period) - indexedTvl.length; - let v2tvl: Pair[] = []; - if (missingDays > 0) { - const v2data = await this._statsService.getDappStakingTvl(network, period); - v2tvl = v2data.slice(-Math.min(missingDays, v2data.length)); - } - - return v2tvl.concat(indexedTvl); - } catch (e) { - console.error(e); - return []; - } - } - - public async getDappStakingRewards( - network: NetworkType, - period: PeriodType, - transaction: RewardEventType, - ): Promise { - this.GuardNetwork(network); - - const range = this.getDateRange(period); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query MyQuery { - rewardEvents( - where: { - timestamp_gte: "${range.start.getTime()}", - timestamp_lte: "${range.end.getTime()}", - ${transaction ? `transaction_in: [${transaction}]}` : '}'} - orderBy: id_ASC) { - amount - blockNumber - contractAddress - era - id - period - tierId - timestamp - transaction - userAddress - } - }`, - }); - - return result.data.data.rewardEvents; - } catch (e) { - console.error(e); - return []; + const cacheItem = this.dappsCache.getItem(network); + if (cacheItem && !this.dappsCache.isExpired(cacheItem)) { + return cacheItem.data; } - } - - public async getDappStakingRewardsAggregated( - network: NetworkType, - address: string, - period: PeriodType, - ): Promise { - this.GuardNetwork(network); - - const range = this.getDateRange(period); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - rewardAggregatedDailies( - orderBy: timestamp_DESC - where: { - beneficiary_eq: "${address}" - timestamp_gte: "${range.start.getTime()}" - timestamp_lte: "${range.end.getTime()}" - } - ) { - amount - timestamp - } - }`, - }); - - const stakersCount = result.data.data.rewardAggregatedDailies.map( - (node: { timestamp: string; amount: number }) => { - return [node.timestamp, node.amount]; - }, - ); - - return stakersCount; - } catch (e) { - console.error(e); - return []; - } - } - - public async getDappStakingStakersCount( - network: NetworkType, - contractAddress: string, - period: PeriodType, - ): Promise { - this.GuardNetwork(network); - - const range = this.getDateRange(period); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - dappAggregatedDailies( - orderBy: timestamp_DESC - where: { - dappAddress_eq: "${contractAddress}" - timestamp_gte: "${range.start.getTime()}" - timestamp_lte: "${range.end.getTime()}" - } - ) { - stakersCount - timestamp - } - }`, - }); - - const stakersCount = result.data.data.dappAggregatedDailies.map( - (node: { timestamp: string; stakersCount: number }) => { - return [node.timestamp, node.stakersCount]; - }, - ); - - return stakersCount; - } catch (e) { - console.error(e); - return []; - } - } - - public async getDappStakingStakersList(network: NetworkType, contractAddress: string): Promise { - this.GuardNetwork(network); - Guard.ThrowIfUndefined('contractAddress', contractAddress); - - // Fetch current period - const api = this._apiFactory.getApiInstance(network); - const protocolState = await api.getProtocolState(); - const period = protocolState.periodInfo.number.toNumber(); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - stakes( - where: { - period_eq: ${period}, - dappAddress_eq: "${contractAddress}" - } - ) { - stakerAddress - stakerAddressEvm - amount - } - }`, - }); - - const sumsByStaker: { - [key: string]: { amount: bigint; stakerAddress: string; stakerAddressEvm?: string }; - } = result.data.data.stakes.reduce( - ( - acc: { [key: string]: { amount: bigint; stakerAddress: string; stakerAddressEvm?: string } }, - { stakerAddress, stakerAddressEvm, amount }: StakerAmount, - ) => { - if (!acc[stakerAddress]) { - acc[stakerAddress] = { amount: BigInt(0), stakerAddress, stakerAddressEvm }; - } - acc[stakerAddress].amount += BigInt(amount); - return acc; - }, - {}, - ); - - const stakersList: StakerAmount[] = Object.entries(sumsByStaker) - .map(([_, stake]) => stake) - .filter((s) => s.amount !== BigInt(0)); - - return stakersList; - } catch (e) { - console.error(e); - return []; - } - } - - public async getDappStakingStakersCountTotal(network: NetworkType, period: PeriodType): Promise { - this.GuardNetwork(network); - - const range = this.getDateRange(period); try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - stakersCountAggregatedDailies( - orderBy: id_DESC - where: { - id_gte: "${range.start.getTime()}" - id_lte: "${range.end.getTime()}" - } - ) { - stakersCount - stakersAmount - id - } - }`, - }); - - const stakersCount = result.data.data.stakersCountAggregatedDailies.map( - (node: { id: string; stakersCount: number; stakersAmount: number }) => { - return [node.id, node.stakersCount, node.stakersAmount]; - }, - ); - - return stakersCount; - } catch (e) { - console.error(e); - return []; - } - } - - public async getDappStakingStakersTotal(network: NetworkType, period: PeriodType): Promise { - this.GuardNetwork(network); - - const range = this.getDateRange(period); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - stakersCountAggregatedDailies( - orderBy: id_DESC - where: { - id_gte: "${range.start.getTime()}" - id_lte: "${range.end.getTime()}" - } - ) { - date: id - count: stakersCount - amount: stakersAmount - } - }`, - }); - - const results: Triplet[] = result.data.data.stakersCountAggregatedDailies; - return results; - } catch (e) { - console.error(e); - return []; - } - } - - public async getDappStakingLockersTotal(network: NetworkType, period: PeriodType): Promise { - this.GuardNetwork(network); - - const range = this.getDateRange(period); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - tvlAggregatedDailies( - orderBy: id_DESC - where: { id_gte: "${range.start.getTime()}", id_lte: "${range.end.getTime()}" } - ) { - date: id - count: lockersCount - amount: tvl - } - }`, - }); - - const results: Triplet[] = result.data.data.tvlAggregatedDailies; - return results; - } catch (e) { - console.error(e); - return []; - } - } - - public async getDappStakingLockersAndStakersTotal( - network: NetworkType, - period: PeriodType, - ): Promise { - this.GuardNetwork(network); - - const range = this.getDateRange(period); - - const query = `query { - tvlAggregatedDailies( - orderBy: id_DESC - where: { id_gte: "${range.start.getTime()}", id_lte: "${range.end.getTime()}" } - ) { - date: id - count: lockersCount - amount: tvl - } - stakersCountAggregatedDailies( - orderBy: id_DESC - where: { id_gte: "${range.start.getTime()}", id_lte: "${range.end.getTime()}" } - ) { - date: id - count: stakersCount - amount: stakersAmount - } - }`; - - try { - const result = await axios.post(this.getApiUrl(network), { query }); - - const combinedData: TotalAmountCount[] = []; - - const lockersData: Triplet[] = result.data.data.tvlAggregatedDailies; - const stakersData: Triplet[] = result.data.data.stakersCountAggregatedDailies; - const lockersMap = new Map(lockersData.map((item) => [item.date, item])); - const stakersMap = new Map(stakersData.map((item) => [item.date, item])); - - const allIds = new Set([...lockersMap.keys(), ...stakersMap.keys()]); - - allIds.forEach((date) => { - combinedData.push({ - date, - tvl: lockersMap.has(date) ? lockersMap.get(date)?.amount : undefined, - lockersCount: lockersMap.has(date) ? lockersMap.get(date)?.count : undefined, - tvs: stakersMap.has(date) ? stakersMap.get(date)?.amount : undefined, - stakersCount: stakersMap.has(date) ? stakersMap.get(date)?.count : undefined, - }); - }); - - return combinedData; - } catch (e) { - console.error(e); - return []; - } - } - - public async getDapps(network: NetworkType): Promise<[]> { - this.GuardNetwork(network); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - dapps (orderBy: registeredAt_ASC) { - contractAddress: id - dappId - beneficiary - owner - state - stakersCount - registeredAt - registrationBlockNumber - unregisteredAt - unregistrationBlockNumber - } - }`, - }); - - return result.data.data.dapps; - } catch (e) { - console.error(e); - return []; - } - } - - public async getAggregatedPeriodData(network: NetworkType, period: number): Promise { - this.GuardNetwork(network); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - stakesPerDapAndPeriods(where: {period_eq: ${period}}) { - dappAddress - rewardAmount - stakeAmount - } - }`, - }); - - return result.data.data.stakesPerDapAndPeriods; - } catch (e) { - console.error(e); - return []; - } - } - - public async getAggregatedStakerData( - network: NetworkType, - stakerAddress: string, - ): Promise { - Guard.ThrowIfUndefined('stakerAddress', stakerAddress); - this.GuardNetwork(network); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - stakesPerStakerAndPeriods(where: {stakerAddress_eq: "${stakerAddress}"}) { - stakerAddress - period - stakeAmount - stakerRewardAmount - bonusRewardAmount - } - }`, - }); - - return result.data.data.stakesPerStakerAndPeriods; + const api = this._apiFactory.getApiInstance(network); + const registered: DappData[] = (await api.getIntegratedDapps()).map((dapp) => ({ + ...dapp, + state: 'Registered', + })); + const dapps = registered.concat(SNAPSHOTS[network].unregisteredDapps); + this.dappsCache.setItem(network, dapps); + + return dapps; } catch (e) { console.error(e); - return []; + return cacheItem?.data ?? []; } } - public async getTotalAggregatedStakerData( - network: NetworkType, - stakerAddress: string, - ): Promise { - this.GuardNetwork(network); - - const data = await this.getAggregatedStakerData(network, stakerAddress); - let maxPeriod = -1; - const total = data.reduce( - (acc, item) => { - if (item.period > maxPeriod) { - acc.currentStake = BigInt(item.stakeAmount); - maxPeriod = item.period; - } - acc.totalStakerRewardsClaimed += BigInt(item.stakerRewardAmount); - acc.totalBonusRewardsClaimed += BigInt(item.bonusRewardAmount); - return acc; - }, - { - currentStake: BigInt(0), - totalBonusRewardsClaimed: BigInt(0), - totalStakerRewardsClaimed: BigInt(0), - stakerAddress, - }, - ); - - return total; - } - public async getPeriodBlockRange(network: NetworkType, period: number): Promise<{ start: number; end?: number }> { this.GuardNetwork(network); if (period <= 0) { throw new Error('Period must be greater than 0'); } - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - subperiods(orderBy: timestamp_ASC, where: {type_eq: Voting}) { - blockNumber - } - }`, - }); - - const subperiods = result.data.data.subperiods; - if (period > subperiods.length) { - throw new Error(`Season ${period} not found`); - } - - return { - start: subperiods[period - 1].blockNumber, - end: subperiods[period]?.blockNumber - 1, - }; - } catch (e) { - console.error(e); - throw new Error('Unable to fetch season block range from a node.'); + const starts = SNAPSHOTS[network].votingStartBlocks; + if (period > starts.length) { + throw new Error(`Season ${period} not found`); } + + return { + start: starts[period - 1], + end: starts[period] ? starts[period] - 1 : undefined, + }; } } diff --git a/src/services/ServiceBase.ts b/src/services/ServiceBase.ts index 350689d..652ab49 100644 --- a/src/services/ServiceBase.ts +++ b/src/services/ServiceBase.ts @@ -1,4 +1,6 @@ import { injectable } from 'inversify'; +import { Guard } from '../guard'; +import { NetworkType } from '../networks'; export type PeriodType = '1 day' | '7 days' | '30 days' | '90 days' | '1 year'; export type PeriodTypeEra = '7 eras' | '30 eras' | '90 eras' | 'all'; @@ -43,4 +45,11 @@ export abstract class ServiceBase { return numberOfDays; } + + protected GuardNetwork(network: NetworkType) { + Guard.ThrowIfUndefined('network', network); + if (!['shibuya', 'shiden', 'astar'].includes(network)) { + throw new Error(`This method is not supported for the network ${network}`); + } + } } diff --git a/src/services/StatsService.ts b/src/services/StatsService.ts index b7c2627..723ed73 100644 --- a/src/services/StatsService.ts +++ b/src/services/StatsService.ts @@ -7,16 +7,9 @@ import { NetworkType } from '../networks'; import { addressesToExclude } from './AddressesToExclude'; import { AccountData } from '../models/AccountData'; import { Guard } from '../guard'; -import { DappStakingV3IndexerBase } from './DappStakingV3IndexerBase'; -import axios from 'axios'; +import { ServiceBase } from './ServiceBase'; import { IPriceProvider } from './IPriceProvider'; -export type TotalSupply = { - block: number; - timestamp: number; - balance: bigint; -}; - export type ExtendedTokenStats = { symbol: string; currencyCode: string; @@ -33,7 +26,6 @@ export interface IStatsService { getTokenStats(network: NetworkType): Promise; getTokenStatsExtended(network: NetworkType, currencies: string[]): Promise; getTotalSupply(network: NetworkType): Promise; - getTotalIssuanceHistory(network: NetworkType): Promise; } const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -42,7 +34,7 @@ const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); /** * Token statistics calculation service. */ -export class StatsService extends DappStakingV3IndexerBase implements IStatsService { +export class StatsService extends ServiceBase implements IStatsService { constructor( @inject(ContainerTypes.ApiFactory) private _apiFactory: IApiFactory, @inject(ContainerTypes.PriceProvider) private _coinGeckoPriceProvider: IPriceProvider, @@ -152,33 +144,6 @@ export class StatsService extends DappStakingV3IndexerBase implements IStatsServ } } - public async getTotalIssuanceHistory(network: NetworkType): Promise { - this.GuardNetwork(network); - - try { - const result = await axios.post(this.getApiUrl(network), { - query: `query { - totalIssuances(orderBy: id_ASC) { - id - timestamp - balance - } - }`, - }); - - return result.data.data.totalIssuances.map((item: { id: string; timestamp: string; balance: string }) => { - return { - block: Number(item.id), - timestamp: Number(item.timestamp), - balance: BigInt(item.balance), - }; - }); - } catch (e) { - console.error(e); - return []; - } - } - private getTotalBalanceToExclude(balances: AccountData[]): BN { const sum = balances .map((balance) => { diff --git a/yarn.lock b/yarn.lock index a0aaea8..ef5dc7d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4474,16 +4474,15 @@ firebase-admin@^11.10.1: "@google-cloud/firestore" "^6.6.0" "@google-cloud/storage" "^6.9.5" -firebase-functions@^4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/firebase-functions/-/firebase-functions-4.4.1.tgz#209fa3a157476722382e71782fe3375b78a529ff" - integrity sha512-3no53Lg12ToNlPSgLZtAFLQAz6si7ilHvzO8NC3/2EybyUwegpj5YhHwNiCw839lmAWp3znjATJDTvADFiZMrg== +firebase-functions@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/firebase-functions/-/firebase-functions-4.9.0.tgz#7b3580a2374dab705f3b7d2a5bf4597489ef74be" + integrity sha512-IqxOEsVAWGcRv9KRGzWQR5mOFuNsil3vsfkRPPiaV1U/ATC27/jbahh4z8I4rW8Xqa6cQE5xqnw0ueyMH7i7Ag== dependencies: "@types/cors" "^2.8.5" "@types/express" "4.17.3" cors "^2.8.5" express "^4.17.1" - node-fetch "^2.6.7" protobufjs "^7.2.2" flat-cache@^3.0.4: @@ -6066,7 +6065,7 @@ node-domexception@^1.0.0: resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-fetch@^2.6.1, node-fetch@^2.6.7: +node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==