From eff56a7fcfe672bef5f52692f3d249cab523f6a1 Mon Sep 17 00:00:00 2001 From: Nicole O'Brien Date: Tue, 27 Feb 2024 10:08:38 +0000 Subject: [PATCH 1/6] refactor: query parameters on base api add: make paginated request on explorer api Co-authored-by: Tuditi --- .../network/classes/evm-explorer-api.class.ts | 49 ++++++++++++++++--- .../shared/src/lib/core/tide/apis/tide.api.ts | 8 ++- packages/shared/src/lib/core/utils/api.ts | 31 ++++++++++-- .../src/lib/core/utils/types/api.types.ts | 1 + .../shared/src/lib/core/utils/types/index.ts | 1 + packages/shared/src/lib/core/utils/url.ts | 3 +- 6 files changed, 76 insertions(+), 17 deletions(-) create mode 100644 packages/shared/src/lib/core/utils/types/api.types.ts diff --git a/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts b/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts index 9b06c043f5..88eeee938d 100644 --- a/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts +++ b/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts @@ -1,17 +1,54 @@ import { NftStandard } from '@core/nfts/enums' import { TokenStandard } from '@core/token/enums' +import { QueryParameters } from '@core/utils' import { BaseApi } from '@core/utils/api' - import { DEFAULT_EXPLORER_URLS } from '../constants' import { IExplorerApi, IExplorerAsset, IExplorerAssetMetadata } from '../interfaces' -import { NetworkId } from '../types' +import { SupportedNetworkId } from '../enums' + +interface INextPageParams { + block_number: number + index: number + items_count: number +} + +interface IPaginationResponse { + items: T[] + next_page_params: INextPageParams | null +} export class EvmExplorerApi extends BaseApi implements IExplorerApi { - constructor(networkId: NetworkId) { + constructor(networkId: SupportedNetworkId) { const explorerUrl = DEFAULT_EXPLORER_URLS[networkId] super(`${explorerUrl}/api/v2`) } + private async makePaginatedRequest( + api: BaseApi, + path: string, + queryParameters: QueryParameters, + items: T[] = [], + nextPageParameters: INextPageParams | null = null + ): Promise { + if (!nextPageParameters) { + return Promise.resolve(items) + } + return this.get>(path, { ...queryParameters, ...nextPageParameters }).then( + (response) => { + if (!response) { + return Promise.resolve(items) + } + return this.makePaginatedRequest( + api, + path, + queryParameters, + items.concat(response.items), + response.next_page_params + ) + } + ) + } + async getAssetMetadata(assetAddress: string): Promise { const response = await this.get(`tokens/${assetAddress}`) if (response) { @@ -25,9 +62,9 @@ export class EvmExplorerApi extends BaseApi implements IExplorerApi { standard: TokenStandard.Erc20 | NftStandard.Erc721 = TokenStandard.Erc20 ): Promise { const tokenType = standard.replace('ERC', 'ERC-') - const response = await this.get<{ items: IExplorerAsset[]; next_page_params: unknown }>( - `addresses/${address}/tokens?type=${tokenType}` - ) + const response = await this.get>(`addresses/${address}/tokens`, { + token_type: tokenType, + }) if (response) { return (response?.items ?? []).map((asset) => ({ ...asset, diff --git a/packages/shared/src/lib/core/tide/apis/tide.api.ts b/packages/shared/src/lib/core/tide/apis/tide.api.ts index 780a88bee4..0312139097 100644 --- a/packages/shared/src/lib/core/tide/apis/tide.api.ts +++ b/packages/shared/src/lib/core/tide/apis/tide.api.ts @@ -1,5 +1,5 @@ import { INftAttribute } from '@core/nfts' -import { BaseApi, buildQueryParametersFromObject } from '@core/utils' +import { BaseApi } from '@core/utils' import { TIDE_API_BASE_URL } from '../constants' import { TideApiEndpoint } from '../enums' import { ITideLeaderboardItem, ITideUserPosition } from '../interfaces' @@ -82,10 +82,8 @@ export class TideApi extends BaseApi { projectId: number, queryParams?: ProjectLeaderboardQueryParams ): Promise { - const path = `${TideApiEndpoint.Project}/${projectId}/leaderboard?${ - queryParams ? buildQueryParametersFromObject(queryParams) : '' - }` - const response = await this.get(path) + const path = `${TideApiEndpoint.Project}/${projectId}/leaderboard` + const response = await this.get(path, queryParams) return response } diff --git a/packages/shared/src/lib/core/utils/api.ts b/packages/shared/src/lib/core/utils/api.ts index bfffcaf1a8..609fac64ba 100644 --- a/packages/shared/src/lib/core/utils/api.ts +++ b/packages/shared/src/lib/core/utils/api.ts @@ -1,3 +1,6 @@ +import { QueryParameters } from './types' +import { buildQueryParametersFromObject } from './url' + interface IApiRequestOptions { disableCors?: boolean } @@ -9,15 +12,29 @@ export class BaseApi { this._baseUrl = baseUrl } - protected get(path: string, options?: IApiRequestOptions): Promise { - return this.makeRequest(path, '', options) + protected get( + path: string, + queryParameters?: QueryParameters, + options?: IApiRequestOptions + ): Promise { + return this.makeRequest(path, queryParameters, undefined, options) } - protected post(path: string, body: string, options?: IApiRequestOptions): Promise { - return this.makeRequest(path, body, options) + protected post( + path: string, + queryParameters?: QueryParameters, + body?: string, + options?: IApiRequestOptions + ): Promise { + return this.makeRequest(path, queryParameters, body, options) } - private async makeRequest(path: string, body?: string, options?: IApiRequestOptions): Promise { + private async makeRequest( + path: string, + queryParameters?: QueryParameters, + body?: string, + options?: IApiRequestOptions + ): Promise { try { const requestInit: RequestInit = { method: body ? 'POST' : 'GET', @@ -28,6 +45,10 @@ export class BaseApi { ...(body && { body }), ...(options?.disableCors && { mode: 'no-cors' }), } + if (queryParameters) { + const queryParametersString = buildQueryParametersFromObject(queryParameters) + path = `${path}?${queryParametersString}` + } const response = await fetch(`${this._baseUrl}/${path}`, requestInit) return (await response.json()) as T } catch (err) { diff --git a/packages/shared/src/lib/core/utils/types/api.types.ts b/packages/shared/src/lib/core/utils/types/api.types.ts new file mode 100644 index 0000000000..7fb05ab28b --- /dev/null +++ b/packages/shared/src/lib/core/utils/types/api.types.ts @@ -0,0 +1 @@ +export type QueryParameters = Record diff --git a/packages/shared/src/lib/core/utils/types/index.ts b/packages/shared/src/lib/core/utils/types/index.ts index ccaa2d5c5f..deda6f81da 100644 --- a/packages/shared/src/lib/core/utils/types/index.ts +++ b/packages/shared/src/lib/core/utils/types/index.ts @@ -1,3 +1,4 @@ +export * from './api.types' export * from './currencies.type' export * from './duration.type' export * from './exchange-rates.type' diff --git a/packages/shared/src/lib/core/utils/url.ts b/packages/shared/src/lib/core/utils/url.ts index 10dd8a7455..a0a4cf8ee7 100644 --- a/packages/shared/src/lib/core/utils/url.ts +++ b/packages/shared/src/lib/core/utils/url.ts @@ -1,4 +1,5 @@ import { stripSpaces, stripTrailingSlash } from './string' +import { QueryParameters } from './types' export function cleanUrl( url: string, @@ -23,7 +24,7 @@ export function cleanUrl( return cleanedUrl } -export function buildQueryParametersFromObject(obj: Record): string { +export function buildQueryParametersFromObject(obj: QueryParameters): string { return Object.keys(obj) .map( (key) => From 74a4f5c83e575171e13911cde69f11aae03686b6 Mon Sep 17 00:00:00 2001 From: Nicole O'Brien Date: Tue, 27 Feb 2024 10:17:39 +0000 Subject: [PATCH 2/6] fix: paginated request logic --- .../network/classes/evm-explorer-api.class.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts b/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts index 88eeee938d..8afdbd7e05 100644 --- a/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts +++ b/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts @@ -23,14 +23,13 @@ export class EvmExplorerApi extends BaseApi implements IExplorerApi { super(`${explorerUrl}/api/v2`) } - private async makePaginatedRequest( - api: BaseApi, + private async makePaginatedGetRequest( path: string, - queryParameters: QueryParameters, + queryParameters?: QueryParameters, items: T[] = [], - nextPageParameters: INextPageParams | null = null + nextPageParameters?: INextPageParams | null ): Promise { - if (!nextPageParameters) { + if (nextPageParameters === null) { return Promise.resolve(items) } return this.get>(path, { ...queryParameters, ...nextPageParameters }).then( @@ -38,8 +37,7 @@ export class EvmExplorerApi extends BaseApi implements IExplorerApi { if (!response) { return Promise.resolve(items) } - return this.makePaginatedRequest( - api, + return this.makePaginatedGetRequest( path, queryParameters, items.concat(response.items), @@ -62,9 +60,8 @@ export class EvmExplorerApi extends BaseApi implements IExplorerApi { standard: TokenStandard.Erc20 | NftStandard.Erc721 = TokenStandard.Erc20 ): Promise { const tokenType = standard.replace('ERC', 'ERC-') - const response = await this.get>(`addresses/${address}/tokens`, { - token_type: tokenType, - }) + const path = `addresses/${address}/tokens` + const response = await this.get>(path, { token_type: tokenType }) if (response) { return (response?.items ?? []).map((asset) => ({ ...asset, From d23da23250dad4c315f166b9ecd02510190ba590 Mon Sep 17 00:00:00 2001 From: Nicole O'Brien Date: Tue, 27 Feb 2024 10:39:44 +0000 Subject: [PATCH 3/6] refactor: move evm explorer to blockscout module --- .../blockscout/api/blockscout.api.ts} | 27 ++++++++++++------- .../src/lib/auxiliary/blockscout/api/index.ts | 1 + .../interfaces/blockscout-api.interface.ts | 12 +++++++++ .../blockscout-asset-metadata.interface.ts} | 2 +- .../interfaces/blockscout-asset.interface.ts | 9 +++++++ .../auxiliary/blockscout/interfaces/index.ts | 3 +++ .../actions/checkForUntrackedTokens.ts | 7 ++--- .../src/lib/core/network/classes/index.ts | 1 - .../interfaces/explorer-api.interface.ts | 12 --------- .../interfaces/explorer-asset.interface.ts | 9 ------- .../nfts/actions/checkForUntrackedNfts.ts | 11 ++++---- 11 files changed, 53 insertions(+), 41 deletions(-) rename packages/shared/src/lib/{core/network/classes/evm-explorer-api.class.ts => auxiliary/blockscout/api/blockscout.api.ts} (65%) create mode 100644 packages/shared/src/lib/auxiliary/blockscout/api/index.ts create mode 100644 packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-api.interface.ts rename packages/shared/src/lib/{core/network/interfaces/explorer-asset-metadata.interface.ts => auxiliary/blockscout/interfaces/blockscout-asset-metadata.interface.ts} (85%) create mode 100644 packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-asset.interface.ts create mode 100644 packages/shared/src/lib/auxiliary/blockscout/interfaces/index.ts delete mode 100644 packages/shared/src/lib/core/network/interfaces/explorer-api.interface.ts delete mode 100644 packages/shared/src/lib/core/network/interfaces/explorer-asset.interface.ts diff --git a/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts b/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts similarity index 65% rename from packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts rename to packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts index 8afdbd7e05..348d61f4f9 100644 --- a/packages/shared/src/lib/core/network/classes/evm-explorer-api.class.ts +++ b/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts @@ -2,9 +2,10 @@ import { NftStandard } from '@core/nfts/enums' import { TokenStandard } from '@core/token/enums' import { QueryParameters } from '@core/utils' import { BaseApi } from '@core/utils/api' -import { DEFAULT_EXPLORER_URLS } from '../constants' -import { IExplorerApi, IExplorerAsset, IExplorerAssetMetadata } from '../interfaces' -import { SupportedNetworkId } from '../enums' +import { DEFAULT_EXPLORER_URLS } from '@core/network/constants' +import { SupportedNetworkId } from '@core/network/enums' +import { IBlockscoutApi, IBlockscoutAsset, IBlockscoutAssetMetadata } from '../interfaces' +import { NetworkId } from '@core/network/types' interface INextPageParams { block_number: number @@ -17,9 +18,9 @@ interface IPaginationResponse { next_page_params: INextPageParams | null } -export class EvmExplorerApi extends BaseApi implements IExplorerApi { - constructor(networkId: SupportedNetworkId) { - const explorerUrl = DEFAULT_EXPLORER_URLS[networkId] +export class BlockscoutApi extends BaseApi implements IBlockscoutApi { + constructor(networkId: NetworkId) { + const explorerUrl = DEFAULT_EXPLORER_URLS[networkId as SupportedNetworkId] super(`${explorerUrl}/api/v2`) } @@ -47,8 +48,8 @@ export class EvmExplorerApi extends BaseApi implements IExplorerApi { ) } - async getAssetMetadata(assetAddress: string): Promise { - const response = await this.get(`tokens/${assetAddress}`) + async getAssetMetadata(assetAddress: string): Promise { + const response = await this.get(`tokens/${assetAddress}`) if (response) { response.type = response.type.replace('-', '') as TokenStandard.Erc20 | NftStandard.Erc721 return response @@ -58,10 +59,10 @@ export class EvmExplorerApi extends BaseApi implements IExplorerApi { async getAssetsForAddress( address: string, standard: TokenStandard.Erc20 | NftStandard.Erc721 = TokenStandard.Erc20 - ): Promise { + ): Promise { const tokenType = standard.replace('ERC', 'ERC-') const path = `addresses/${address}/tokens` - const response = await this.get>(path, { token_type: tokenType }) + const response = await this.get>(path, { token_type: tokenType }) if (response) { return (response?.items ?? []).map((asset) => ({ ...asset, @@ -74,4 +75,10 @@ export class EvmExplorerApi extends BaseApi implements IExplorerApi { return [] } } + + async getTransactionsForAddress(address: string): Promise { + const path = `addresses/${address}/transactions` + const items = await this.makePaginatedGetRequest(path) + return items + } } diff --git a/packages/shared/src/lib/auxiliary/blockscout/api/index.ts b/packages/shared/src/lib/auxiliary/blockscout/api/index.ts new file mode 100644 index 0000000000..9c3b613282 --- /dev/null +++ b/packages/shared/src/lib/auxiliary/blockscout/api/index.ts @@ -0,0 +1 @@ +export * from './blockscout.api' diff --git a/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-api.interface.ts b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-api.interface.ts new file mode 100644 index 0000000000..53e5115265 --- /dev/null +++ b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-api.interface.ts @@ -0,0 +1,12 @@ +import { NftStandard } from '@core/nfts/enums' +import { TokenStandard } from '@core/token/enums' +import { IBlockscoutAsset } from './blockscout-asset.interface' +import { IBlockscoutAssetMetadata } from './blockscout-asset-metadata.interface' + +export interface IBlockscoutApi { + getAssetMetadata(assetAddress: string): Promise + getAssetsForAddress( + address: string, + tokenStandard?: TokenStandard.Erc20 | NftStandard.Erc721 + ): Promise +} diff --git a/packages/shared/src/lib/core/network/interfaces/explorer-asset-metadata.interface.ts b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-asset-metadata.interface.ts similarity index 85% rename from packages/shared/src/lib/core/network/interfaces/explorer-asset-metadata.interface.ts rename to packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-asset-metadata.interface.ts index 1952408e7b..6c67bc5929 100644 --- a/packages/shared/src/lib/core/network/interfaces/explorer-asset-metadata.interface.ts +++ b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-asset-metadata.interface.ts @@ -1,5 +1,5 @@ // snake_case returned by the API -export interface IExplorerAssetMetadata { +export interface IBlockscoutAssetMetadata { address: string circulating_market_cap: string decimals: number diff --git a/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-asset.interface.ts b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-asset.interface.ts new file mode 100644 index 0000000000..5ebb40c5fe --- /dev/null +++ b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-asset.interface.ts @@ -0,0 +1,9 @@ +import { IBlockscoutAssetMetadata } from './blockscout-asset-metadata.interface' + +// snake_case returned by the API +export interface IBlockscoutAsset { + token: IBlockscoutAssetMetadata + token_id: string + token_instance: unknown + value: string +} diff --git a/packages/shared/src/lib/auxiliary/blockscout/interfaces/index.ts b/packages/shared/src/lib/auxiliary/blockscout/interfaces/index.ts new file mode 100644 index 0000000000..88bc1c3053 --- /dev/null +++ b/packages/shared/src/lib/auxiliary/blockscout/interfaces/index.ts @@ -0,0 +1,3 @@ +export * from './blockscout-api.interface' +export * from './blockscout-asset.interface' +export * from './blockscout-asset-metadata.interface' diff --git a/packages/shared/src/lib/core/layer-2/actions/checkForUntrackedTokens.ts b/packages/shared/src/lib/core/layer-2/actions/checkForUntrackedTokens.ts index 20106ade3f..a0b7ef96de 100644 --- a/packages/shared/src/lib/core/layer-2/actions/checkForUntrackedTokens.ts +++ b/packages/shared/src/lib/core/layer-2/actions/checkForUntrackedTokens.ts @@ -1,9 +1,10 @@ import { IAccountState } from '@core/account/interfaces' -import { EvmExplorerApi, EvmNetworkId } from '@core/network' +import { EvmNetworkId } from '@core/network' import { getNetwork } from '@core/network/stores' import { TokenStandard, TokenTrackingStatus } from '@core/token' import { addNewTrackedTokenToActiveProfile, hasTokenBeenUntracked } from '@core/wallet/actions' import { BASE_TOKEN_CONTRACT_ADDRESS } from '../constants' +import { BlockscoutApi } from '@auxiliary/blockscout/api' export function checkForUntrackedTokens(account: IAccountState, addPreviouslyUntracked?: boolean): void { const chains = getNetwork()?.getChains() @@ -14,9 +15,9 @@ export function checkForUntrackedTokens(account: IAccountState, addPreviouslyUnt return } const networkId = chain.getConfiguration().id - const explorerApi = new EvmExplorerApi(networkId) + const blockscoutApi = new BlockscoutApi(networkId) - const tokens = await explorerApi.getAssetsForAddress(evmAddress) + const tokens = await blockscoutApi.getAssetsForAddress(evmAddress) const untrackedTokensToTrack = tokens.filter( ({ token }) => addPreviouslyUntracked || !hasTokenBeenUntracked(token.address.toLowerCase(), networkId) ) diff --git a/packages/shared/src/lib/core/network/classes/index.ts b/packages/shared/src/lib/core/network/classes/index.ts index bbca6f250e..0710e6657d 100644 --- a/packages/shared/src/lib/core/network/classes/index.ts +++ b/packages/shared/src/lib/core/network/classes/index.ts @@ -1,3 +1,2 @@ -export * from './evm-explorer-api.class' export * from './iscp-chain.class' export * from './stardust-network.class' diff --git a/packages/shared/src/lib/core/network/interfaces/explorer-api.interface.ts b/packages/shared/src/lib/core/network/interfaces/explorer-api.interface.ts deleted file mode 100644 index b219a55a0a..0000000000 --- a/packages/shared/src/lib/core/network/interfaces/explorer-api.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { NftStandard } from '@core/nfts/enums' -import { TokenStandard } from '@core/token/enums' -import { IExplorerAsset } from './explorer-asset.interface' -import { IExplorerAssetMetadata } from './explorer-asset-metadata.interface' - -export interface IExplorerApi { - getAssetMetadata(assetAddress: string): Promise - getAssetsForAddress( - address: string, - tokenStandard?: TokenStandard.Erc20 | NftStandard.Erc721 - ): Promise -} diff --git a/packages/shared/src/lib/core/network/interfaces/explorer-asset.interface.ts b/packages/shared/src/lib/core/network/interfaces/explorer-asset.interface.ts deleted file mode 100644 index 9a7c8e10c9..0000000000 --- a/packages/shared/src/lib/core/network/interfaces/explorer-asset.interface.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { IExplorerAssetMetadata } from './explorer-asset-metadata.interface' - -// snake_case returned by the API -export interface IExplorerAsset { - token: IExplorerAssetMetadata - token_id: string - token_instance: unknown - value: string -} diff --git a/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts b/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts index 9471b0399b..19fe0c48d5 100644 --- a/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts +++ b/packages/shared/src/lib/core/nfts/actions/checkForUntrackedNfts.ts @@ -1,8 +1,7 @@ import { IAccountState } from '@core/account/interfaces' import { ContractType } from '@core/layer-2/enums' -import { EvmExplorerApi } from '@core/network/classes' import { getNetwork } from '@core/network/stores' -import { IChain, IExplorerAsset } from '@core/network/interfaces' +import { IChain } from '@core/network/interfaces' import features from '@features/features' import { NftStandard } from '../enums' @@ -13,6 +12,8 @@ import { addNftsToDownloadQueue } from './addNftsToDownloadQueue' import { Nft } from '../interfaces' import { addNewTrackedNftToActiveProfile } from './addNewTrackedNftToActiveProfile' import { TokenTrackingStatus } from '@core/token' +import { IBlockscoutAsset } from '@auxiliary/blockscout/interfaces' +import { BlockscoutApi } from '@auxiliary/blockscout/api' export async function checkForUntrackedNfts(account: IAccountState): Promise { if (!features?.collectibles?.erc721?.enabled) { @@ -28,9 +29,9 @@ export async function checkForUntrackedNfts(account: IAccountState): Promise { const { token, value } = asset From b2d1f718e61f56e23693dd8d67ff98a63ffaea7a Mon Sep 17 00:00:00 2001 From: Nicole O'Brien Date: Tue, 27 Feb 2024 10:59:21 +0000 Subject: [PATCH 4/6] fix: imports --- packages/shared/src/lib/core/network/interfaces/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/shared/src/lib/core/network/interfaces/index.ts b/packages/shared/src/lib/core/network/interfaces/index.ts index 71e0401773..6ff8524eba 100644 --- a/packages/shared/src/lib/core/network/interfaces/index.ts +++ b/packages/shared/src/lib/core/network/interfaces/index.ts @@ -6,9 +6,6 @@ export * from './chain.interface' export * from './client-options.interface' export * from './connected-chain.interface' export * from './evm-addresses.interface' -export * from './explorer-api.interface' -export * from './explorer-asset-metadata.interface' -export * from './explorer-asset.interface' export * from './gas-fee-policy.interface' export * from './gas-limits.interface' export * from './network-status.interface' From 4d4f3a93da31bcdaa99017921bc52916b6e604c9 Mon Sep 17 00:00:00 2001 From: Nicole O'Brien Date: Tue, 27 Feb 2024 10:59:56 +0000 Subject: [PATCH 5/6] feat: add blockscout transaction interface --- .../blockscout/api/blockscout.api.ts | 6 +- .../interfaces/blockscout-api.interface.ts | 2 + .../blockscout-transaction.interface.ts | 81 +++++++++++++++++++ .../auxiliary/blockscout/interfaces/index.ts | 1 + 4 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-transaction.interface.ts diff --git a/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts b/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts index 348d61f4f9..3bd07f5628 100644 --- a/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts +++ b/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts @@ -4,7 +4,7 @@ import { QueryParameters } from '@core/utils' import { BaseApi } from '@core/utils/api' import { DEFAULT_EXPLORER_URLS } from '@core/network/constants' import { SupportedNetworkId } from '@core/network/enums' -import { IBlockscoutApi, IBlockscoutAsset, IBlockscoutAssetMetadata } from '../interfaces' +import { IBlockscoutApi, IBlockscoutAsset, IBlockscoutAssetMetadata, IBlockscoutTransaction } from '../interfaces' import { NetworkId } from '@core/network/types' interface INextPageParams { @@ -76,9 +76,9 @@ export class BlockscoutApi extends BaseApi implements IBlockscoutApi { } } - async getTransactionsForAddress(address: string): Promise { + async getTransactionsForAddress(address: string): Promise { const path = `addresses/${address}/transactions` - const items = await this.makePaginatedGetRequest(path) + const items = await this.makePaginatedGetRequest(path) return items } } diff --git a/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-api.interface.ts b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-api.interface.ts index 53e5115265..46a5610528 100644 --- a/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-api.interface.ts +++ b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-api.interface.ts @@ -2,6 +2,7 @@ import { NftStandard } from '@core/nfts/enums' import { TokenStandard } from '@core/token/enums' import { IBlockscoutAsset } from './blockscout-asset.interface' import { IBlockscoutAssetMetadata } from './blockscout-asset-metadata.interface' +import { IBlockscoutTransaction } from './blockscout-transaction.interface' export interface IBlockscoutApi { getAssetMetadata(assetAddress: string): Promise @@ -9,4 +10,5 @@ export interface IBlockscoutApi { address: string, tokenStandard?: TokenStandard.Erc20 | NftStandard.Erc721 ): Promise + getTransactionsForAddress(address: string): Promise } diff --git a/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-transaction.interface.ts b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-transaction.interface.ts new file mode 100644 index 0000000000..fb26b6845a --- /dev/null +++ b/packages/shared/src/lib/auxiliary/blockscout/interfaces/blockscout-transaction.interface.ts @@ -0,0 +1,81 @@ +import { IBlockscoutAssetMetadata } from './blockscout-asset-metadata.interface' + +interface IFee { + type: string + value: string +} + +interface IAddressTag { + address_hash: string + display_name: string + label: string +} + +interface IWatchlistName { + display_name: string + label: string +} + +interface IAddressParam { + hash: string + implementation_name: string + name: string + is_contract: boolean + private_tags: IAddressTag[] + watchlist_names: IWatchlistName[] + public_tags: IAddressTag[] + is_verified: boolean +} + +interface IDecodedInput { + method_call: string + method_id: string + parameters: Record // IDecodedInputParameters +} + +interface ITokenTransfer { + block_hash: string + from: IAddressParam + log_index: string + method: string + timestamp: string + to: IAddressParam + token: IBlockscoutAssetMetadata +} + +export interface IBlockscoutTransaction { + timestamp: string + fee: IFee + gas_limit: number + block: number + status: string // e.g ok | error + method: string // e.g transferFrom + confirmations: number + type: number + exchange_rate: string + to: IAddressParam + tx_burnt_fee: string + max_fee_per_gas: string + result: string + hash: string + gas_price: string + priority_fee: string + base_fee_per_gas: string + from: IAddressParam + token_transfers: ITokenTransfer[] + tx_types: string[] + gas_used: string + created_contract: IAddressParam + position: number + nonce: number + has_error_in_internal_txs: boolean + actions: unknown // TransactionAction + decoded_input: IDecodedInput + token_transfers_overflow: boolean + raw_input: string + value: string + max_priority_fee_per_gas: string + revert_reason: string + confirmation_duration: string + tx_tag: string +} diff --git a/packages/shared/src/lib/auxiliary/blockscout/interfaces/index.ts b/packages/shared/src/lib/auxiliary/blockscout/interfaces/index.ts index 88bc1c3053..3a8f009cd6 100644 --- a/packages/shared/src/lib/auxiliary/blockscout/interfaces/index.ts +++ b/packages/shared/src/lib/auxiliary/blockscout/interfaces/index.ts @@ -1,3 +1,4 @@ export * from './blockscout-api.interface' export * from './blockscout-asset.interface' export * from './blockscout-asset-metadata.interface' +export * from './blockscout-transaction.interface' From 56f3af58f488d14c8ab97536bd90f738df9414e2 Mon Sep 17 00:00:00 2001 From: Tuditi Date: Tue, 27 Feb 2024 15:24:47 +0100 Subject: [PATCH 6/6] fix: correct queryParameters --- .../shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts | 2 +- packages/shared/src/lib/core/utils/api.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts b/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts index 3bd07f5628..29781e54e3 100644 --- a/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts +++ b/packages/shared/src/lib/auxiliary/blockscout/api/blockscout.api.ts @@ -62,7 +62,7 @@ export class BlockscoutApi extends BaseApi implements IBlockscoutApi { ): Promise { const tokenType = standard.replace('ERC', 'ERC-') const path = `addresses/${address}/tokens` - const response = await this.get>(path, { token_type: tokenType }) + const response = await this.get>(path, { type: tokenType }) if (response) { return (response?.items ?? []).map((asset) => ({ ...asset, diff --git a/packages/shared/src/lib/core/utils/api.ts b/packages/shared/src/lib/core/utils/api.ts index 609fac64ba..823c0afca7 100644 --- a/packages/shared/src/lib/core/utils/api.ts +++ b/packages/shared/src/lib/core/utils/api.ts @@ -45,7 +45,7 @@ export class BaseApi { ...(body && { body }), ...(options?.disableCors && { mode: 'no-cors' }), } - if (queryParameters) { + if (queryParameters && Object.keys(queryParameters).length) { const queryParametersString = buildQueryParametersFromObject(queryParameters) path = `${path}?${queryParametersString}` }