diff --git a/src/api/bigDipperApi.ts b/src/api/bigDipperApi.ts index c110a7a0..b280a5dc 100644 --- a/src/api/bigDipperApi.ts +++ b/src/api/bigDipperApi.ts @@ -16,13 +16,13 @@ export class BigDipperApi { constructor(public readonly graphql_client: GraphQLClient) {} async getTotalSupply(): Promise { - let query = `query TotalSupply { + const query = `query TotalSupply { supply { coins } }`; - let resp = await this.graphql_client.query<{ + const resp = await this.graphql_client.query<{ data: TotalSupplyResponse; }>(query); @@ -30,7 +30,7 @@ export class BigDipperApi { } getTotalStakedCoins = async (): Promise => { - let query = `query StakingInfo{ + const query = `query StakingInfo{ staking_pool { bonded_tokens } diff --git a/src/api/nodeApi.ts b/src/api/nodeApi.ts index 774edbca..22bb8418 100644 --- a/src/api/nodeApi.ts +++ b/src/api/nodeApi.ts @@ -4,22 +4,22 @@ export class NodeApi { constructor(public readonly base_rest_api_url: string) {} async getAccountInfo(address: string): Promise { - let resp = await fetch(`${this.base_rest_api_url}/cosmos/auth/v1beta1/accounts/${address}`); - let respJson = (await resp.json()) as { account: Account }; + const resp = await fetch(`${this.base_rest_api_url}/cosmos/auth/v1beta1/accounts/${address}`); + const respJson = (await resp.json()) as { account: Account }; return respJson.account; } async getAvailableBalance(address: string): Promise { - let resp = await fetch(`${this.base_rest_api_url}/cosmos/bank/v1beta1/balances/${address}`); - let respJson = (await resp.json()) as { balances: Coin[] }; + const resp = await fetch(`${this.base_rest_api_url}/cosmos/bank/v1beta1/balances/${address}`); + const respJson = (await resp.json()) as { balances: Coin[] }; return respJson.balances; } async distributionGetRewards(address: string): Promise { - let resp = await fetch(`${this.base_rest_api_url}/cosmos/distribution/v1beta1/delegators/${address}/rewards`); - let respJson = (await resp.json()) as RewardsResponse; + const resp = await fetch(`${this.base_rest_api_url}/cosmos/distribution/v1beta1/delegators/${address}/rewards`); + const respJson = (await resp.json()) as RewardsResponse; return Number(respJson?.total?.[0]?.amount ?? '0'); } diff --git a/src/database/scripts/initialDataFetch.ts b/src/database/scripts/initialDataFetch.ts index 0c3b721b..13cb5ca9 100644 --- a/src/database/scripts/initialDataFetch.ts +++ b/src/database/scripts/initialDataFetch.ts @@ -14,7 +14,7 @@ clientConfig.ssl = { ca: fs.readFileSync('/tmp/do-cert.pem').toString(), }; -let client = new Client(clientConfig); +const client = new Client(clientConfig); client.connect(); const db = drizzle(client, { logger: false }); diff --git a/src/database/scripts/seed.ts b/src/database/scripts/seed.ts index bc7c2496..f8fb6380 100644 --- a/src/database/scripts/seed.ts +++ b/src/database/scripts/seed.ts @@ -12,7 +12,7 @@ clientConfig.ssl = { ca: fs.readFileSync('/tmp/do-cert.pem').toString(), }; -let client = new Client(clientConfig); +const client = new Client(clientConfig); client.connect(); const db = drizzle(client, { logger: true }); diff --git a/src/handlers/analytics.ts b/src/handlers/analytics.ts index 510fa1a8..98727280 100644 --- a/src/handlers/analytics.ts +++ b/src/handlers/analytics.ts @@ -146,7 +146,7 @@ function parseQueryParams(url: URL): AnalyticsQueryParams { export async function handler( request: IRequest, env: Env, - ctx: ExecutionContext, + _ctx: ExecutionContext, network: Network, entityType?: EntityType ): Promise { diff --git a/src/handlers/circulatingSupply.ts b/src/handlers/circulatingSupply.ts index f40e83ab..da004989 100644 --- a/src/handlers/circulatingSupply.ts +++ b/src/handlers/circulatingSupply.ts @@ -1,7 +1,6 @@ -import { IRequest } from 'itty-router'; import { getCirculatingSupply } from '../helpers/circulating'; -export async function handler(request: IRequest, env: Env): Promise { +export async function handler(env: Env): Promise { try { const circulating_supply = await getCirculatingSupply(env); return new Response(circulating_supply.toString()); diff --git a/src/handlers/liquidBalance.ts b/src/handlers/liquidBalance.ts index 6be8eb01..5bf49785 100644 --- a/src/handlers/liquidBalance.ts +++ b/src/handlers/liquidBalance.ts @@ -11,7 +11,7 @@ export async function handler(request: IRequest, env: Env): Promise { throw new Error('No address specified or wrong address format.'); } - let api = new NodeApi(env.REST_API); + const api = new NodeApi(env.REST_API); const account = await api.getAccountInfo(address); if (!isVestingAccount(account['@type'])) { @@ -19,26 +19,26 @@ export async function handler(request: IRequest, env: Env): Promise { } if (isDelayedVestingAccount(account?.['@type'])) { - let balance = + const balance = account?.base_vesting_account?.base_account?.sequence !== '0' ? Number( (await (await api.getAvailableBalance(address)).find((b) => b.denom === 'ncheq')?.amount) ?? '0' ) : 0; - let rewards = Number((await await api.distributionGetRewards(address)) ?? '0'); - let delegated = Number( + const rewards = Number((await await api.distributionGetRewards(address)) ?? '0'); + const delegated = Number( account?.base_vesting_account?.delegated_free?.find((d) => d.denom === 'ncheq')?.amount ?? '0' ); return new Response(convertToMainTokenDenom(balance + rewards + delegated, env.TOKEN_EXPONENT)); } - let vested_coins = Number(calculateVesting(account)?.vested); - let balance = Number( + const vested_coins = Number(calculateVesting(account)?.vested); + const balance = Number( (await (await api.getAvailableBalance(address)).find((b) => b.denom === 'ncheq')?.amount) ?? '0' ); - let rewards = Number((await api.distributionGetRewards(address)) ?? '0'); - let liquid_coins = vested_coins + balance + rewards; + const rewards = Number((await api.distributionGetRewards(address)) ?? '0'); + const liquid_coins = vested_coins + balance + rewards; return new Response(convertToMainTokenDenom(liquid_coins, env.TOKEN_EXPONENT)); } diff --git a/src/handlers/totalBalance.ts b/src/handlers/totalBalance.ts index 41b089de..43649777 100644 --- a/src/handlers/totalBalance.ts +++ b/src/handlers/totalBalance.ts @@ -3,6 +3,6 @@ import { fetchAccountBalances } from '../helpers/balance'; export async function handler(request: IRequest, env: Env): Promise { const address = request.params?.['address']; - let account_balance_infos = await fetchAccountBalances(address!!, env); + const account_balance_infos = await fetchAccountBalances(address!, env); return new Response(account_balance_infos?.totalBalance.toString()); } diff --git a/src/handlers/totalStakedCoins.ts b/src/handlers/totalStakedCoins.ts index de8828a0..c7bbe275 100644 --- a/src/handlers/totalStakedCoins.ts +++ b/src/handlers/totalStakedCoins.ts @@ -1,13 +1,12 @@ -import { IRequest } from 'itty-router'; import { BigDipperApi } from '../api/bigDipperApi'; import { convertToMainTokenDenom } from '../helpers/currency'; import { GraphQLClient } from '../helpers/graphql'; -export async function handler(request: IRequest, env: Env): Promise { - let gql_client = new GraphQLClient(env.GRAPHQL_API); - let bd_api = new BigDipperApi(gql_client); +export async function handler(env: Env): Promise { + const gql_client = new GraphQLClient(env.GRAPHQL_API); + const bd_api = new BigDipperApi(gql_client); - let total_staked_coins = await bd_api.getTotalStakedCoins(); + const total_staked_coins = await bd_api.getTotalStakedCoins(); return new Response(convertToMainTokenDenom(Number(total_staked_coins), env.TOKEN_EXPONENT)); } diff --git a/src/handlers/totalSupply.ts b/src/handlers/totalSupply.ts index 397a1a61..f749e2fd 100644 --- a/src/handlers/totalSupply.ts +++ b/src/handlers/totalSupply.ts @@ -1,11 +1,10 @@ -import { IRequest } from 'itty-router'; import { BigDipperApi } from '../api/bigDipperApi'; import { convertToMainTokenDenom } from '../helpers/currency'; import { GraphQLClient } from '../helpers/graphql'; -export async function handler(request: IRequest, env: Env): Promise { - let gql_client = new GraphQLClient(env.GRAPHQL_API); - let bd_api = new BigDipperApi(gql_client); +export async function handler(env: Env): Promise { + const gql_client = new GraphQLClient(env.GRAPHQL_API); + const bd_api = new BigDipperApi(gql_client); const total_supply = await bd_api.getTotalSupply(); return new Response(convertToMainTokenDenom(total_supply, env.TOKEN_EXPONENT)); } diff --git a/src/handlers/vestedBalance.ts b/src/handlers/vestedBalance.ts index 7607e00f..82baca1f 100644 --- a/src/handlers/vestedBalance.ts +++ b/src/handlers/vestedBalance.ts @@ -11,14 +11,14 @@ export async function handler(request: IRequest, env: Env): Promise { throw new Error('No address specified or wrong address format.'); } - let api = new NodeApi(env.REST_API); + const api = new NodeApi(env.REST_API); const account = await api.getAccountInfo(address); if (!isVestingAccount(account['@type'])) { throw new Error(`Only vesting accounts are supported. Accounts type '${account['@type']}'.`); } - let vested_coins = calculateVesting(account)?.vested; + const vested_coins = calculateVesting(account)?.vested; - return new Response(convertToMainTokenDenom(vested_coins!!, env.TOKEN_EXPONENT)); + return new Response(convertToMainTokenDenom(vested_coins!, env.TOKEN_EXPONENT)); } diff --git a/src/handlers/vestingBalance.ts b/src/handlers/vestingBalance.ts index 9bb1d5b8..c97b0aea 100644 --- a/src/handlers/vestingBalance.ts +++ b/src/handlers/vestingBalance.ts @@ -11,13 +11,13 @@ export async function handler(request: IRequest, env: Env): Promise { throw new Error('No address specified or wrong address format.'); } - let api = new NodeApi(env.REST_API); + const api = new NodeApi(env.REST_API); const account = await api.getAccountInfo(address); if (!isVestingAccount(account['@type'])) { throw new Error(`Only vesting accounts are supported. Accounts type '${account['@type']}'.`); } - let vestingCoins = calculateVesting(account)?.vesting; - return new Response(convertToMainTokenDenom(vestingCoins!!, env.TOKEN_EXPONENT)); + const vestingCoins = calculateVesting(account)?.vesting; + return new Response(convertToMainTokenDenom(vestingCoins!, env.TOKEN_EXPONENT)); } diff --git a/src/handlers/webhookTriggers.ts b/src/handlers/webhookTriggers.ts index db67e9b9..e8759b8c 100644 --- a/src/handlers/webhookTriggers.ts +++ b/src/handlers/webhookTriggers.ts @@ -22,12 +22,6 @@ export async function syncIdentityData(env: Env) { function getHour(): number { // This function only works when CIRCULATING_SUPPLY_GROUPS is set to 24 - let hour = Number(new Date().getHours() + 1); // getHours() returns 0-23 + const hour = Number(new Date().getHours() + 1); // getHours() returns 0-23 return hour; } - -function getRandomGroup(group: number): number { - let min = 1; - let max = Math.floor(group); - return Math.floor(Math.random() * (max - min + 1)) + min; -} diff --git a/src/helpers/analytics.ts b/src/helpers/analytics.ts index 57976d73..c462ff51 100644 --- a/src/helpers/analytics.ts +++ b/src/helpers/analytics.ts @@ -9,7 +9,7 @@ import { denomMainnet, denomTestnet, } from '../database/schema'; -import { AnalyticsQueryParams, AnalyticsResponse } from '../types/analytics'; +import { AnalyticsQueryParams, AnalyticsResponse, AnalyticsItem } from '../types/analytics'; import { DrizzleClient } from '../database/client'; import { serializeBigInt } from './csv'; import { Network } from '../types/network'; @@ -74,7 +74,7 @@ export function buildQueryConditions( } // Format response -function formatResponse(items: any[], totalCount: number, params: AnalyticsQueryParams): AnalyticsResponse { +function formatResponse(items: AnalyticsItem[], totalCount: number, params: AnalyticsQueryParams): AnalyticsResponse { return { items: serializeBigInt(items), totalCount, diff --git a/src/helpers/circulating.ts b/src/helpers/circulating.ts index f106f0aa..e3c59de3 100644 --- a/src/helpers/circulating.ts +++ b/src/helpers/circulating.ts @@ -15,8 +15,8 @@ export async function updateCirculatingSupply(groupNumber: number, env: Env) { for (const key of cached.keys) { const parts = extractPrefixAndKey(key.name); - let addr = parts.address; - let grpN = parts.groupNumber; + const addr = parts.address; + const grpN = parts.groupNumber; const found = await env.CIRCULATING_SUPPLY_WATCHLIST.get(`group_${grpN}:${addr}`); if (found) { @@ -29,8 +29,9 @@ export async function updateCirculatingSupply(groupNumber: number, env: Env) { } } } - } catch (e) { - console.log('Error at: ', 'updateCirculatingSupply'); + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : String(error); + console.log(`Error updating circulating supply for group ${groupNumber}: ${errorMessage}`); } } @@ -43,15 +44,16 @@ export async function updateCachedBalance(addr: string, grpN: number, env: Env) await env.CIRCULATING_SUPPLY_WATCHLIST.put(`group_${grpN}:${addr}`, data); console.log(`account "${addr}" balance updated. (${data})`); - } catch (e: any) { - console.log(`error updateCachedBalance: ${e}`); + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : String(error); + console.log(`Error updating cached balance for address ${addr}: ${errorMessage}`); } } export async function getCirculatingSupply(env: Env): Promise { - let gql_client = new GraphQLClient(env.GRAPHQL_API); - let bd_api = new BigDipperApi(gql_client); - let total_supply_ncheq = await bd_api.getTotalSupply(); + const gql_client = new GraphQLClient(env.GRAPHQL_API); + const bd_api = new BigDipperApi(gql_client); + const total_supply_ncheq = await bd_api.getTotalSupply(); const total_supply = Number(convertToMainTokenDenom(total_supply_ncheq, env.TOKEN_EXPONENT)); try { @@ -59,7 +61,7 @@ export async function getCirculatingSupply(env: Env): Promise { console.log(`Total cached entries: ${cached.keys.length}`); let shareholders_total_balance = Number(0); for (const key of cached.keys) { - let data: AccountBalanceInfos | null = await env.CIRCULATING_SUPPLY_WATCHLIST.get(key.name, { + const data: AccountBalanceInfos | null = await env.CIRCULATING_SUPPLY_WATCHLIST.get(key.name, { type: 'json', }); @@ -71,9 +73,10 @@ export async function getCirculatingSupply(env: Env): Promise { console.log('Total supply', total_supply); console.log(`Watchlist total balance: ${shareholders_total_balance}`); - let circulating_supply = total_supply - shareholders_total_balance; + const circulating_supply = total_supply - shareholders_total_balance; return circulating_supply; - } catch (e: any) { - throw new Error(e.toString); + } catch (error: unknown) { + const errorMessage = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to calculate circulating supply: ${errorMessage}`); } } diff --git a/src/helpers/csv.ts b/src/helpers/csv.ts index c278c592..61aa028a 100644 --- a/src/helpers/csv.ts +++ b/src/helpers/csv.ts @@ -5,7 +5,7 @@ import { getTables, buildQueryConditions } from './analytics'; import { eq, and, desc, sql } from 'drizzle-orm'; // Convert data to CSV format -export function convertToCSV(data: any[]): string { +export function convertToCSV(data: Record[]): string { if (!data || !data.length) { return 'No data available'; } @@ -92,7 +92,7 @@ export function generateExportFilename( .substring(0, 255); // Limit filename length } -export function serializeBigInt(data: any): any { +export function serializeBigInt(data: T): T { return JSON.parse(JSON.stringify(data, (_, value) => (typeof value === 'bigint' ? value.toString() : value))); } @@ -145,14 +145,16 @@ export async function exportResourceAnalytics( // Execute query without pagination const items = await db .select({ + didId: tables.resource.didId, // Now first resourceId: tables.resource.resourceId, resourceType: tables.resource.resourceType, resourceName: tables.resource.resourceName, operationType: tables.operationTypes.friendlyOperationType, - didId: tables.resource.didId, + ledgerOperationType: tables.operationTypes.ledgerOperationType, feePayer: tables.resource.feePayer, amount: sql`${tables.resource.amount}::decimal / POW(10, ${tables.denom.exponent})`, denom: tables.denom.friendlyDenom, + ledgerDenom: tables.denom.ledgerDenom, blockHeight: tables.resource.blockHeight, transactionHash: tables.resource.transactionHash, createdAt: tables.resource.createdAt, @@ -184,16 +186,17 @@ export async function exportAllAnalytics( // Fetch DIDs const didItems = await db .select({ - type: sql`'DID'`.as('type'), // Add a type column to distinguish records - id: tables.did.didId, + type: sql`'DID'`.as('type'), didId: tables.did.didId, resourceId: sql`NULL`.as('resourceId'), resourceType: sql`NULL`.as('resourceType'), resourceName: sql`NULL`.as('resourceName'), operationType: tables.operationTypes.friendlyOperationType, + ledgerOperationType: tables.operationTypes.ledgerOperationType, feePayer: tables.did.feePayer, amount: sql`${tables.did.amount}::decimal / POW(10, ${tables.denom.exponent})`, denom: tables.denom.friendlyDenom, + ledgerDenom: tables.denom.ledgerDenom, blockHeight: tables.did.blockHeight, transactionHash: tables.did.transactionHash, createdAt: tables.did.createdAt, @@ -205,19 +208,20 @@ export async function exportAllAnalytics( .where(and(...didConditions)) .orderBy(desc(tables.did.createdAt)); - // Fetch Resources + // Fetch Resources with the same structure as DIDs for consistent headers const resourceItems = await db .select({ - type: sql`'Resource'`.as('type'), // Add a type column to distinguish records - id: tables.resource.resourceId, + type: sql`'Resource'`.as('type'), didId: tables.resource.didId, resourceId: tables.resource.resourceId, resourceType: tables.resource.resourceType, resourceName: tables.resource.resourceName, operationType: tables.operationTypes.friendlyOperationType, + ledgerOperationType: tables.operationTypes.ledgerOperationType, feePayer: tables.resource.feePayer, amount: sql`${tables.resource.amount}::decimal / POW(10, ${tables.denom.exponent})`, denom: tables.denom.friendlyDenom, + ledgerDenom: tables.denom.ledgerDenom, blockHeight: tables.resource.blockHeight, transactionHash: tables.resource.transactionHash, createdAt: tables.resource.createdAt, diff --git a/src/helpers/graphql.ts b/src/helpers/graphql.ts index f6b960f3..c522ede5 100644 --- a/src/helpers/graphql.ts +++ b/src/helpers/graphql.ts @@ -1,8 +1,10 @@ +import { GraphQLRequest, GraphQLResponseBase } from '../types/bigDipper'; + export class GraphQLClient { constructor(public readonly base_url: string) {} - async query(options: { query: string; variables?: any } | string): Promise { - let req: { query: string; variables?: any }; + async query(options: GraphQLRequest | string): Promise { + let req: GraphQLRequest; if (typeof options === 'string') { req = { query: options }; @@ -10,7 +12,7 @@ export class GraphQLClient { req = options; } - let resp = await fetch(this.base_url, { + const resp = await fetch(this.base_url, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -18,12 +20,12 @@ export class GraphQLClient { body: JSON.stringify(req), }); - let json = (await resp.json()) as any; + const json = (await resp.json()) as T & GraphQLResponseBase; if (json.errors) { throw new Error(`Query failed: ${JSON.stringify(json.errors)}`); } - return json as T; + return json; } } diff --git a/src/helpers/identity.ts b/src/helpers/identity.ts index 5920d0dc..35de3522 100644 --- a/src/helpers/identity.ts +++ b/src/helpers/identity.ts @@ -9,28 +9,21 @@ import { operationTypesMainnet, operationTypesTestnet, } from '../database/schema'; +import { DenomType } from '../types/bigDipper'; import { Network } from '../types/network'; -import { TransactionDetails } from '../types/bigDipper'; +import { DidTransactionDetails, ResourceTransactionDetails } from '../types/bigDipper'; import { eq, and, max } from 'drizzle-orm'; import { Client } from 'pg'; -import { dbInit, dbClose } from '../database/client'; +import { dbInit, dbClose, DrizzleClient } from '../database/client'; import { GraphQLClient } from './graphql'; interface DbInstance { - db: any; + db: DrizzleClient; client: Client; } -// Define table mappings based on network type -const TABLES: Record< - Network, - { - did: any; - resource: any; - denom: any; - operationTypes: any; - } -> = { +// Define table mappings based on network type without explicit type aliases +const TABLES = { [Network.MAINNET]: { did: didMainnet, resource: resourceMainnet, @@ -142,7 +135,7 @@ export class SyncService { console.log(`Total DIDs processed: ${totalProcessed}, skipped: ${totalSkipped}`); } - private async insertDid(tx: TransactionDetails) { + private async insertDid(tx: DidTransactionDetails) { try { console.log( `Processing DID: tx=${tx.transactionHash}, did=${tx.didId}, type=${tx.operationType}, height=${tx.blockHeight}` @@ -172,7 +165,7 @@ export class SyncService { .where( and( eq(tables.did.transactionHash, tx.transactionHash), - eq(tables.did.operationType, opType[0].id), + eq(tables.did.operationType, BigInt(opType[0].id)), eq(tables.did.didId, tx.didId) ) ) @@ -205,7 +198,7 @@ export class SyncService { const denomRecord = await this.db .select() .from(tables.denom) - .where(eq(tables.denom.ledgerDenom, tx.denom || 'ncheq')) + .where(eq(tables.denom.ledgerDenom, tx.denom as DenomType)) .limit(1); if (denomRecord.length === 0) { @@ -217,12 +210,12 @@ export class SyncService { // Insert DID data try { - const insertResult = await this.db.insert(tables.did).values({ + await this.db.insert(tables.did).values({ didId: tx.didId, - operationType: opType[0].id, + operationType: BigInt(opType[0].id), feePayer: tx.feePayer, amount: BigInt(tx.amount), - denom: denomRecord[0].id, + denom: BigInt(denomRecord[0].id), blockHeight: BigInt(tx.blockHeight), transactionHash: tx.transactionHash, createdAt: new Date(tx.timestamp), @@ -334,7 +327,7 @@ export class SyncService { console.log(`Total Resources processed: ${totalProcessed}, skipped: ${totalSkipped}`); } - private async insertResource(tx: TransactionDetails): Promise { + private async insertResource(tx: ResourceTransactionDetails): Promise { try { console.log( `Processing Resource: tx=${tx.transactionHash}, resource=${tx.resourceId}, type=${tx.operationType}, height=${tx.blockHeight}` @@ -364,7 +357,7 @@ export class SyncService { .where( and( eq(tables.resource.transactionHash, tx.transactionHash), - eq(tables.resource.operationType, opType[0].id), + eq(tables.resource.operationType, BigInt(opType[0].id)), eq(tables.resource.resourceId, tx.resourceId) ) ) @@ -399,7 +392,7 @@ export class SyncService { const denomRecord = await this.db .select() .from(tables.denom) - .where(eq(tables.denom.ledgerDenom, tx.denom || 'ncheq')) + .where(eq(tables.denom.ledgerDenom, tx.denom as DenomType)) .limit(1); if (denomRecord.length === 0) { @@ -415,11 +408,11 @@ export class SyncService { resourceId: tx.resourceId, resourceType: tx.resourceType, resourceName: tx.resourceName, - operationType: opType[0].id, + operationType: BigInt(opType[0].id), didId: tx.didId, feePayer: tx.feePayer, amount: BigInt(tx.amount), - denom: denomRecord[0].id, + denom: BigInt(denomRecord[0].id), blockHeight: BigInt(tx.blockHeight), transactionHash: tx.transactionHash, createdAt: new Date(tx.timestamp), diff --git a/src/helpers/kv.ts b/src/helpers/kv.ts index 25b82ea5..93bc316f 100644 --- a/src/helpers/kv.ts +++ b/src/helpers/kv.ts @@ -1,7 +1,7 @@ export function extractPrefixAndKey(key: string) { const parts = key.split(':'); - let addr = parts[1]; - let grpN = Number(parts[0].split('_')[1]); + const addr = parts[1]; + const grpN = Number(parts[0].split('_')[1]); return { address: addr, groupNumber: grpN, diff --git a/src/index.ts b/src/index.ts index 730ff61b..a80120f8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,14 +10,14 @@ import { webhookTriggers } from './handlers/webhookTriggers'; import { registerAnalyticsRoutes } from './routes/analytics'; function registerRoutes(router: ReturnType, env: Env, ctx: ExecutionContext) { - router.get('/', (request) => totalSupplyHandler(request, env)); + router.get('/', () => totalSupplyHandler(env)); router.get('/balances/liquid/:address', (request) => liquidBalanceHandler(request, env)); router.get('/balances/total/:address', (request) => totalBalanceHandler(request, env)); router.get('/balances/vested/:address', (request) => vestedBalanceHandler(request, env)); router.get('/balances/vesting/:address', (request) => vestingBalanceHandler(request, env)); - router.get('/supply/circulating', (request) => circulatingSupplyHandler(request, env)); - router.get('/supply/staked', (request) => totalStakedCoinsHandler(request, env)); - router.get('/supply/total', (request) => totalSupplyHandler(request, env)); + router.get('/supply/circulating', () => circulatingSupplyHandler(env)); + router.get('/supply/staked', () => totalStakedCoinsHandler(env)); + router.get('/supply/total', () => totalSupplyHandler(env)); // Register analytics routes registerAnalyticsRoutes(router, env, ctx); @@ -36,7 +36,7 @@ export default { registerRoutes(router, env, ctx); return router.handle(request).catch((error) => handleError(error)); }, - async scheduled(controller: ScheduledController, env: Env, ctx: ExecutionContext) { + async scheduled(_controller: ScheduledController, env: Env, _ctx: ExecutionContext) { return await webhookTriggers(env); }, }; diff --git a/src/routes/analytics.ts b/src/routes/analytics.ts index ce46a850..b15c6af8 100644 --- a/src/routes/analytics.ts +++ b/src/routes/analytics.ts @@ -1,11 +1,18 @@ -import { IRequest } from 'itty-router'; +import { IRequest, Router } from 'itty-router'; import { handler as handleAnalyticsRequest } from '../handlers/analytics'; -import { Network, VALID_NETWORKS, EntityType, VALID_ENTITY_TYPES, VALID_ANALYTICS_PATHS } from '../types/network'; +import { + Network, + VALID_NETWORKS, + EntityType, + VALID_ENTITY_TYPES, + VALID_ANALYTICS_PATHS, + AnalyticsPathType, +} from '../types/network'; /** * Registers analytics-related routes to the router */ -export function registerAnalyticsRoutes(router: any, env: Env, ctx: ExecutionContext) { +export function registerAnalyticsRoutes(router: ReturnType, env: Env, ctx: ExecutionContext) { // Base analytics endpoint router.get('/analytics/:network', (request: IRequest) => { const { network } = request.params; @@ -41,7 +48,7 @@ export function registerAnalyticsRoutes(router: any, env: Env, ctx: ExecutionCon } // Validate path - if (!VALID_ANALYTICS_PATHS.includes(path as any)) { + if (!VALID_ANALYTICS_PATHS.includes(path as AnalyticsPathType)) { return new Response( JSON.stringify({ error: `Invalid path. Use ${VALID_ANALYTICS_PATHS.join(', ')}.`, diff --git a/src/types/analytics.ts b/src/types/analytics.ts index dcc5580c..4e8ad38e 100644 --- a/src/types/analytics.ts +++ b/src/types/analytics.ts @@ -12,8 +12,52 @@ export interface AnalyticsQueryParams { limit: number; } +// Base interface for common analytics item properties +export interface BaseAnalyticsItem { + operationType: string; + feePayer: string; + amount: string | number; + denom: string; + blockHeight: bigint | number; + transactionHash: string; + createdAt: Date | string; + success: boolean; +} + +// DID-specific analytics item +export interface DidAnalyticsItem { + didId: string; + operationType: string | null; + feePayer: string; + amount: unknown; + denom: string | null; + blockHeight: bigint; + transactionHash: string; + createdAt: Date; + success: boolean; +} + +// Resource-specific analytics item +export interface ResourceAnalyticsItem { + resourceId: string; + resourceType: string; + resourceName: string; + operationType: string | null; + didId: string | null; + feePayer: string; + amount: unknown; + denom: string | null; + blockHeight: bigint; + transactionHash: string; + createdAt: Date; + success: boolean; +} + +// Combined type for analytics items +export type AnalyticsItem = DidAnalyticsItem | ResourceAnalyticsItem; + export interface AnalyticsResponse { - items: any[]; + items: AnalyticsItem[]; totalCount: number; page: number; limit: number; diff --git a/src/types/bigDipper.ts b/src/types/bigDipper.ts index d98f2941..ee2b2da3 100644 --- a/src/types/bigDipper.ts +++ b/src/types/bigDipper.ts @@ -72,7 +72,7 @@ export interface ResourcesResponse { message: Message[]; } -export interface TransactionDetails { +export interface DidTransactionDetails { transactionHash: string; blockHeight: number; operationType: OperationType; @@ -81,9 +81,21 @@ export interface TransactionDetails { feePayer: string; amount: string; denom: string; - resourceId?: string; - resourceType?: string; - resourceName?: string; + success: boolean; +} + +export interface ResourceTransactionDetails { + transactionHash: string; + blockHeight: number; + operationType: OperationType; + timestamp: string; + didId: string; + feePayer: string; + amount: string; + denom: string; + resourceId: string; + resourceType: string; + resourceName: string; success: boolean; } @@ -109,3 +121,15 @@ export enum FriendlyOperationType { DEACTIVATE_DID = 'deactivateDid', CREATE_RESOURCE = 'createResource', } + +// GraphQL related types +export type GraphQLVariables = Record; + +export interface GraphQLRequest { + query: string; + variables?: GraphQLVariables; +} + +export interface GraphQLResponseBase { + errors?: Array<{ message: string; locations?: unknown[]; path?: string[]; extensions?: unknown }>; +} diff --git a/src/types/node.ts b/src/types/node.ts index 0d1320e8..befe0ca7 100644 --- a/src/types/node.ts +++ b/src/types/node.ts @@ -102,7 +102,16 @@ export interface UnbondingResponse { }; } +// Define the structure of rewards record +interface ValidatorRewards { + validator_address: string; + reward: { + denom: string; + amount: string; + }[]; +} + export interface RewardsResponse { - rewards: Record[]; + rewards: ValidatorRewards[]; total: Coin[]; } diff --git a/src/worker-types.d.ts b/src/worker-types.d.ts index d98e8f7c..06809db6 100644 --- a/src/worker-types.d.ts +++ b/src/worker-types.d.ts @@ -23,7 +23,7 @@ declare global { } interface ExecutionContext { - waitUntil(promise: Promise): void; + waitUntil(promise: Promise): void; passThroughOnException(): void; } }