From f6de9d3c6d7433bae4ea31dc7d689bdd6ede3bb3 Mon Sep 17 00:00:00 2001 From: Mario Date: Wed, 7 Feb 2024 11:55:17 +0100 Subject: [PATCH] feat: Basic support for NFT address page (#1091) * chore: Extract AddressNotFound to own component * feat: Make AddressPage.tsx an entrypoint for address pages. Refactor useAddressPageState to be Account address specific. Add AccountAddressView. * feat: Add support for Ed25519 address page (state hook and tsx component) * fix: Fix OutputPage for Nft and Account outputs * feat: Support Nft address page (basic). Add custom hooks for nft address page and load nft output details. --- ...ntRequest.ts => IAccountDetailsRequest.ts} | 2 +- ...Response.ts => IAccountDetailsResponse.ts} | 4 +- api/src/models/api/nova/INftDetailsRequest.ts | 11 ++++ .../models/api/nova/INftDetailsResponse.ts | 11 ++++ api/src/routes.ts | 1 + api/src/routes/nova/account/get.ts | 6 +- api/src/routes/nova/nft/get.ts | 29 +++++++++ api/src/services/nova/novaApiService.ts | 32 ++++++++-- client/src/app/components/nova/OutputView.tsx | 10 +-- .../nova/address/NftAddressView.tsx | 52 +++++++++++++++ client/src/app/routes/nova/AddressPage.tsx | 5 +- .../src/helpers/nova/bech32AddressHelper.ts | 2 +- .../helpers/nova/hooks/useAccountDetails.ts | 2 +- .../helpers/nova/hooks/useNftAddressState.ts | 64 +++++++++++++++++++ .../src/helpers/nova/hooks/useNftDetails.ts | 48 ++++++++++++++ ...ntRequest.ts => IAccountDetailsRequest.ts} | 2 +- ...Response.ts => IAccountDetailsResponse.ts} | 4 +- .../src/models/api/nova/INftDetailsRequest.ts | 11 ++++ .../models/api/nova/INftDetailsResponse.ts | 9 +++ client/src/services/nova/novaApiClient.ts | 19 ++++-- 20 files changed, 297 insertions(+), 27 deletions(-) rename api/src/models/api/nova/{IAccountRequest.ts => IAccountDetailsRequest.ts} (79%) rename api/src/models/api/nova/{IAccountResponse.ts => IAccountDetailsResponse.ts} (70%) create mode 100644 api/src/models/api/nova/INftDetailsRequest.ts create mode 100644 api/src/models/api/nova/INftDetailsResponse.ts create mode 100644 api/src/routes/nova/nft/get.ts create mode 100644 client/src/app/components/nova/address/NftAddressView.tsx create mode 100644 client/src/helpers/nova/hooks/useNftAddressState.ts create mode 100644 client/src/helpers/nova/hooks/useNftDetails.ts rename client/src/models/api/nova/{IAccountRequest.ts => IAccountDetailsRequest.ts} (79%) rename client/src/models/api/nova/{IAccountResponse.ts => IAccountDetailsResponse.ts} (59%) create mode 100644 client/src/models/api/nova/INftDetailsRequest.ts create mode 100644 client/src/models/api/nova/INftDetailsResponse.ts diff --git a/api/src/models/api/nova/IAccountRequest.ts b/api/src/models/api/nova/IAccountDetailsRequest.ts similarity index 79% rename from api/src/models/api/nova/IAccountRequest.ts rename to api/src/models/api/nova/IAccountDetailsRequest.ts index 24fa3324a..28b69dcc6 100644 --- a/api/src/models/api/nova/IAccountRequest.ts +++ b/api/src/models/api/nova/IAccountDetailsRequest.ts @@ -1,4 +1,4 @@ -export interface IAccountRequest { +export interface IAccountDetailsRequest { /** * The network to search on. */ diff --git a/api/src/models/api/nova/IAccountResponse.ts b/api/src/models/api/nova/IAccountDetailsResponse.ts similarity index 70% rename from api/src/models/api/nova/IAccountResponse.ts rename to api/src/models/api/nova/IAccountDetailsResponse.ts index 4db772845..665bbf30a 100644 --- a/api/src/models/api/nova/IAccountResponse.ts +++ b/api/src/models/api/nova/IAccountDetailsResponse.ts @@ -3,9 +3,9 @@ import { OutputResponse } from "@iota/sdk-nova"; import { IResponse } from "./IResponse"; -export interface IAccountResponse extends IResponse { +export interface IAccountDetailsResponse extends IResponse { /** * The account details response. */ - accountDetails?: OutputResponse; + accountOutputDetails?: OutputResponse; } diff --git a/api/src/models/api/nova/INftDetailsRequest.ts b/api/src/models/api/nova/INftDetailsRequest.ts new file mode 100644 index 000000000..fd8daeb97 --- /dev/null +++ b/api/src/models/api/nova/INftDetailsRequest.ts @@ -0,0 +1,11 @@ +export interface INftDetailsRequest { + /** + * The network to search on. + */ + network: string; + + /** + * The nft id to get the nft output details for. + */ + nftId: string; +} diff --git a/api/src/models/api/nova/INftDetailsResponse.ts b/api/src/models/api/nova/INftDetailsResponse.ts new file mode 100644 index 000000000..7ebf5ccf0 --- /dev/null +++ b/api/src/models/api/nova/INftDetailsResponse.ts @@ -0,0 +1,11 @@ +/* eslint-disable import/no-unresolved */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { OutputResponse } from "@iota/sdk-nova"; +import { IResponse } from "./IResponse"; + +export interface INftDetailsResponse extends IResponse { + /** + * The nft output details response. + */ + nftOutputDetails?: OutputResponse; +} diff --git a/api/src/routes.ts b/api/src/routes.ts index 91861a21b..c3ec04325 100644 --- a/api/src/routes.ts +++ b/api/src/routes.ts @@ -205,6 +205,7 @@ export const routes: IRoute[] = [ { path: "/nova/output/:network/:outputId", method: "get", folder: "nova/output", func: "get" }, { path: "/nova/output/rewards/:network/:outputId", method: "get", folder: "nova/output/rewards", func: "get" }, { path: "/nova/account/:network/:accountId", method: "get", folder: "nova/account", func: "get" }, + { path: "/nova/nft/:network/:nftId", method: "get", folder: "nova/nft", func: "get" }, { path: "/nova/output/associated/:network/:address", method: "post", diff --git a/api/src/routes/nova/account/get.ts b/api/src/routes/nova/account/get.ts index 06f690f33..17d4f386d 100644 --- a/api/src/routes/nova/account/get.ts +++ b/api/src/routes/nova/account/get.ts @@ -1,6 +1,6 @@ import { ServiceFactory } from "../../../factories/serviceFactory"; -import { IAccountRequest } from "../../../models/api/nova/IAccountRequest"; -import { IAccountResponse } from "../../../models/api/nova/IAccountResponse"; +import { IAccountDetailsRequest } from "../../../models/api/nova/IAccountDetailsRequest"; +import { IAccountDetailsResponse } from "../../../models/api/nova/IAccountDetailsResponse"; import { IConfiguration } from "../../../models/configuration/IConfiguration"; import { NOVA } from "../../../models/db/protocolVersion"; import { NetworkService } from "../../../services/networkService"; @@ -13,7 +13,7 @@ import { ValidationHelper } from "../../../utils/validationHelper"; * @param request The request. * @returns The response. */ -export async function get(config: IConfiguration, request: IAccountRequest): Promise { +export async function get(config: IConfiguration, request: IAccountDetailsRequest): Promise { const networkService = ServiceFactory.get("network"); const networks = networkService.networkNames(); ValidationHelper.oneOf(request.network, networks, "network"); diff --git a/api/src/routes/nova/nft/get.ts b/api/src/routes/nova/nft/get.ts new file mode 100644 index 000000000..2e4ed00e1 --- /dev/null +++ b/api/src/routes/nova/nft/get.ts @@ -0,0 +1,29 @@ +import { ServiceFactory } from "../../../factories/serviceFactory"; +import { INftDetailsRequest } from "../../../models/api/nova/INftDetailsRequest"; +import { INftDetailsResponse } from "../../../models/api/nova/INftDetailsResponse"; +import { IConfiguration } from "../../../models/configuration/IConfiguration"; +import { NOVA } from "../../../models/db/protocolVersion"; +import { NetworkService } from "../../../services/networkService"; +import { NovaApiService } from "../../../services/nova/novaApiService"; +import { ValidationHelper } from "../../../utils/validationHelper"; + +/** + * Get nft output details by Nft id + * @param config The configuration. + * @param request The request. + * @returns The response. + */ +export async function get(config: IConfiguration, request: INftDetailsRequest): Promise { + const networkService = ServiceFactory.get("network"); + const networks = networkService.networkNames(); + ValidationHelper.oneOf(request.network, networks, "network"); + ValidationHelper.string(request.nftId, "nftId"); + + const networkConfig = networkService.get(request.network); + + if (networkConfig.protocolVersion !== NOVA) { + return {}; + } + const novaApiService = ServiceFactory.get(`api-service-${networkConfig.network}`); + return novaApiService.nftDetails(request.nftId); +} diff --git a/api/src/services/nova/novaApiService.ts b/api/src/services/nova/novaApiService.ts index 27f6406b2..549e5001a 100644 --- a/api/src/services/nova/novaApiService.ts +++ b/api/src/services/nova/novaApiService.ts @@ -3,9 +3,10 @@ import { Client } from "@iota/sdk-nova"; import { ServiceFactory } from "../../factories/serviceFactory"; import logger from "../../logger"; -import { IAccountResponse } from "../../models/api/nova/IAccountResponse"; +import { IAccountDetailsResponse } from "../../models/api/nova/IAccountDetailsResponse"; import { IBlockDetailsResponse } from "../../models/api/nova/IBlockDetailsResponse"; import { IBlockResponse } from "../../models/api/nova/IBlockResponse"; +import { INftDetailsResponse } from "../../models/api/nova/INftDetailsResponse"; import { IOutputDetailsResponse } from "../../models/api/nova/IOutputDetailsResponse"; import { IRewardsResponse } from "../../models/api/nova/IRewardsResponse"; import { INetwork } from "../../models/db/INetwork"; @@ -86,24 +87,43 @@ export class NovaApiService { } /** - * Get the account details. - * @param accountId The accountId to get the details for. - * @returns The account details. + * Get the account output details. + * @param accountId The accountId to get the output details for. + * @returns The account output details. */ - public async accountDetails(accountId: string): Promise { + public async accountDetails(accountId: string): Promise { try { const accountOutputId = await this.client.accountOutputId(accountId); if (accountOutputId) { const outputResponse = await this.outputDetails(accountOutputId); - return outputResponse.error ? { error: outputResponse.error } : { accountDetails: outputResponse.output }; + return outputResponse.error ? { error: outputResponse.error } : { accountOutputDetails: outputResponse.output }; } } catch { return { message: "Account output not found" }; } } + /** + * Get the nft output details. + * @param nftId The nftId to get the output details for. + * @returns The nft output details. + */ + public async nftDetails(nftId: string): Promise { + try { + const nftOutputId = await this.client.nftOutputId(nftId); + + if (nftOutputId) { + const outputResponse = await this.outputDetails(nftOutputId); + + return outputResponse.error ? { error: outputResponse.error } : { nftOutputDetails: outputResponse.output }; + } + } catch { + return { message: "Nft output not found" }; + } + } + /** * Get the output mana rewards. * @param outputId The outputId to get the rewards for. diff --git a/client/src/app/components/nova/OutputView.tsx b/client/src/app/components/nova/OutputView.tsx index b63544e7b..5e445f594 100644 --- a/client/src/app/components/nova/OutputView.tsx +++ b/client/src/app/components/nova/OutputView.tsx @@ -14,6 +14,7 @@ import { SimpleTokenScheme, DelegationOutput, AddressType, + Utils, } from "@iota/sdk-wasm-nova/web"; import UnlockConditionView from "./UnlockConditionView"; import CopyButton from "../CopyButton"; @@ -21,7 +22,6 @@ import { Link } from "react-router-dom"; import { useNetworkInfoNova } from "~/helpers/nova/networkInfo"; import FeatureView from "./FeaturesView"; import TruncatedId from "../stardust/TruncatedId"; -import { TransactionsHelper } from "~/helpers/stardust/transactionsHelper"; import { Bech32AddressHelper } from "~/helpers/nova/bech32AddressHelper"; import "./OutputView.scss"; @@ -216,16 +216,16 @@ const OutputView: React.FC = ({ outputId, output, showCopyAmoun ); }; -function buildAddressForAliasOrNft(outputId: string, output: Output, bech32Hrp: string) { +function buildAddressForAliasOrNft(outputId: string, output: Output, bech32Hrp: string): string { let address: string = ""; let addressType: number = 0; if (output.type === OutputType.Account) { - const aliasId = TransactionsHelper.buildIdHashForNft((output as AccountOutput).accountId, outputId); - address = aliasId; + const accountId = Utils.computeAccountId(outputId); + address = accountId; addressType = AddressType.Account; } else if (output.type === OutputType.Nft) { - const nftId = TransactionsHelper.buildIdHashForAlias((output as NftOutput).nftId, outputId); + const nftId = Utils.computeNftId(outputId); address = nftId; addressType = AddressType.Nft; } diff --git a/client/src/app/components/nova/address/NftAddressView.tsx b/client/src/app/components/nova/address/NftAddressView.tsx new file mode 100644 index 000000000..358a6c11b --- /dev/null +++ b/client/src/app/components/nova/address/NftAddressView.tsx @@ -0,0 +1,52 @@ +import { NftAddress } from "@iota/sdk-wasm-nova/web"; +import React from "react"; +import { useNftAddressState } from "~/helpers/nova/hooks/useNftAddressState"; +import Spinner from "../../Spinner"; +import Bech32Address from "../../stardust/address/Bech32Address"; +import AssociatedOutputs from "./section/association/AssociatedOutputs"; + +interface NftAddressViewProps { + nftAddress: NftAddress; +} + +const NftAddressView: React.FC = ({ nftAddress }) => { + const { nftAddressDetails, isNftDetailsLoading } = useNftAddressState(nftAddress); + const isPageLoading = isNftDetailsLoading; + + return ( +
+
+ {nftAddressDetails && ( +
+
+
+

{nftAddressDetails.typeLabel?.replace("Ed25519", "Address")}

+
+ {isPageLoading && } +
+
+
+
+

General

+
+
+
+
+ +
+
+
+
+
+

Associated Outputs

+
+ +
+
+ )} +
+
+ ); +}; + +export default NftAddressView; diff --git a/client/src/app/routes/nova/AddressPage.tsx b/client/src/app/routes/nova/AddressPage.tsx index a857fc02a..0abda5cfc 100644 --- a/client/src/app/routes/nova/AddressPage.tsx +++ b/client/src/app/routes/nova/AddressPage.tsx @@ -1,4 +1,4 @@ -import { AccountAddress, Address, AddressType, Ed25519Address, Utils } from "@iota/sdk-wasm-nova/web"; +import { AccountAddress, Address, AddressType, Ed25519Address, NftAddress, Utils } from "@iota/sdk-wasm-nova/web"; import React from "react"; import { RouteComponentProps } from "react-router-dom"; import AddressNotFoundPage from "~/app/components/nova/address/AddressNotFoundPage"; @@ -6,6 +6,7 @@ import { AddressRouteProps } from "../AddressRouteProps"; import AccountAddressView from "~/app/components/nova/address/AccountAddressView"; import Ed25519AddressView from "~/app/components/nova/address/Ed25519AddressView"; import "./AddressPage.scss"; +import NftAddressView from "~/app/components/nova/address/NftAddressView"; const AddressPage: React.FC> = ({ match: { @@ -26,6 +27,8 @@ const AddressPage: React.FC> = ({ return ; case AddressType.Account: return ; + case AddressType.Nft: + return ; default: return (
diff --git a/client/src/helpers/nova/bech32AddressHelper.ts b/client/src/helpers/nova/bech32AddressHelper.ts index 22ee6534f..f1e5f3b1e 100644 --- a/client/src/helpers/nova/bech32AddressHelper.ts +++ b/client/src/helpers/nova/bech32AddressHelper.ts @@ -41,7 +41,7 @@ export class Bech32AddressHelper { return { bech32, - hex, + hex: hex ? HexHelper.addPrefix(hex) : hex, type, typeLabel: Bech32AddressHelper.typeLabel(type), }; diff --git a/client/src/helpers/nova/hooks/useAccountDetails.ts b/client/src/helpers/nova/hooks/useAccountDetails.ts index 8c8b081dd..db65abc84 100644 --- a/client/src/helpers/nova/hooks/useAccountDetails.ts +++ b/client/src/helpers/nova/hooks/useAccountDetails.ts @@ -30,7 +30,7 @@ export function useAccountDetails(network: string, accountId: string | null): { }) .then((response) => { if (!response?.error && isMounted) { - const output = response.accountDetails?.output as AccountOutput; + const output = response.accountOutputDetails?.output as AccountOutput; setAccountOutput(output); } diff --git a/client/src/helpers/nova/hooks/useNftAddressState.ts b/client/src/helpers/nova/hooks/useNftAddressState.ts new file mode 100644 index 000000000..87412dac0 --- /dev/null +++ b/client/src/helpers/nova/hooks/useNftAddressState.ts @@ -0,0 +1,64 @@ +import { Reducer, useEffect, useReducer } from "react"; +import { NftAddress, NftOutput } from "@iota/sdk-wasm-nova/web"; +import { IBech32AddressDetails } from "~/models/api/IBech32AddressDetails"; +import { useNftDetails } from "./useNftDetails"; +import { useLocation, useParams } from "react-router-dom"; +import { AddressRouteProps } from "~/app/routes/AddressRouteProps"; +import { useNetworkInfoNova } from "../networkInfo"; +import { Bech32AddressHelper } from "~/helpers/nova/bech32AddressHelper"; + +export interface INftAddressState { + nftAddressDetails: IBech32AddressDetails | null; + nftOutput: NftOutput | null; + isNftDetailsLoading: boolean; +} + +const initialState = { + nftAddressDetails: null, + nftOutput: null, + isNftDetailsLoading: true, +}; + +/** + * Route Location Props + */ +interface IAddressPageLocationProps { + addressDetails: IBech32AddressDetails; +} + +export const useNftAddressState = (address: NftAddress): INftAddressState => { + const location = useLocation(); + const { network } = useParams(); + const { bech32Hrp } = useNetworkInfoNova((s) => s.networkInfo); + const [state, setState] = useReducer>>( + (currentState, newState) => ({ ...currentState, ...newState }), + initialState, + ); + + const { nftOutput, isLoading: isNftDetailsLoading } = useNftDetails(network, address.nftId); + + useEffect(() => { + const locationState = location.state as IAddressPageLocationProps; + const { addressDetails } = locationState?.addressDetails + ? locationState + : { addressDetails: Bech32AddressHelper.buildAddress(bech32Hrp, address) }; + + setState({ + ...initialState, + nftAddressDetails: addressDetails, + }); + }, []); + + useEffect(() => { + setState({ + nftOutput, + isNftDetailsLoading, + }); + }, [nftOutput, isNftDetailsLoading]); + + return { + nftAddressDetails: state.nftAddressDetails, + nftOutput: state.nftOutput, + isNftDetailsLoading: state.isNftDetailsLoading, + }; +}; diff --git a/client/src/helpers/nova/hooks/useNftDetails.ts b/client/src/helpers/nova/hooks/useNftDetails.ts new file mode 100644 index 000000000..9335864d1 --- /dev/null +++ b/client/src/helpers/nova/hooks/useNftDetails.ts @@ -0,0 +1,48 @@ +import { NftOutput } from "@iota/sdk-wasm-nova/web"; +import { useEffect, useState } from "react"; +import { ServiceFactory } from "~/factories/serviceFactory"; +import { useIsMounted } from "~/helpers/hooks/useIsMounted"; +import { HexHelper } from "~/helpers/stardust/hexHelper"; +import { NOVA } from "~/models/config/protocolVersion"; +import { NovaApiClient } from "~/services/nova/novaApiClient"; + +/** + * Fetch nft output details + * @param network The Network in context + * @param nftID The nft id + * @returns The output response and loading bool. + */ +export function useNftDetails(network: string, nftId: string | null): { nftOutput: NftOutput | null; isLoading: boolean } { + const isMounted = useIsMounted(); + const [apiClient] = useState(ServiceFactory.get(`api-client-${NOVA}`)); + const [nftOutput, setNftOutput] = useState(null); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + setIsLoading(true); + if (nftId) { + // eslint-disable-next-line no-void + void (async () => { + apiClient + .nftDetails({ + network, + nftId: HexHelper.addPrefix(nftId), + }) + .then((response) => { + if (!response?.error && isMounted) { + const output = response.nftOutputDetails?.output as NftOutput; + + setNftOutput(output); + } + }) + .finally(() => { + setIsLoading(false); + }); + })(); + } else { + setIsLoading(false); + } + }, [network, nftId]); + + return { nftOutput, isLoading }; +} diff --git a/client/src/models/api/nova/IAccountRequest.ts b/client/src/models/api/nova/IAccountDetailsRequest.ts similarity index 79% rename from client/src/models/api/nova/IAccountRequest.ts rename to client/src/models/api/nova/IAccountDetailsRequest.ts index 24fa3324a..28b69dcc6 100644 --- a/client/src/models/api/nova/IAccountRequest.ts +++ b/client/src/models/api/nova/IAccountDetailsRequest.ts @@ -1,4 +1,4 @@ -export interface IAccountRequest { +export interface IAccountDetailsRequest { /** * The network to search on. */ diff --git a/client/src/models/api/nova/IAccountResponse.ts b/client/src/models/api/nova/IAccountDetailsResponse.ts similarity index 59% rename from client/src/models/api/nova/IAccountResponse.ts rename to client/src/models/api/nova/IAccountDetailsResponse.ts index cc8f27543..22722dddc 100644 --- a/client/src/models/api/nova/IAccountResponse.ts +++ b/client/src/models/api/nova/IAccountDetailsResponse.ts @@ -1,9 +1,9 @@ import { OutputResponse } from "@iota/sdk-wasm-nova/web"; import { IResponse } from "./IResponse"; -export interface IAccountResponse extends IResponse { +export interface IAccountDetailsResponse extends IResponse { /** * The account details response. */ - accountDetails?: OutputResponse; + accountOutputDetails?: OutputResponse; } diff --git a/client/src/models/api/nova/INftDetailsRequest.ts b/client/src/models/api/nova/INftDetailsRequest.ts new file mode 100644 index 000000000..fd8daeb97 --- /dev/null +++ b/client/src/models/api/nova/INftDetailsRequest.ts @@ -0,0 +1,11 @@ +export interface INftDetailsRequest { + /** + * The network to search on. + */ + network: string; + + /** + * The nft id to get the nft output details for. + */ + nftId: string; +} diff --git a/client/src/models/api/nova/INftDetailsResponse.ts b/client/src/models/api/nova/INftDetailsResponse.ts new file mode 100644 index 000000000..5ac2cfd11 --- /dev/null +++ b/client/src/models/api/nova/INftDetailsResponse.ts @@ -0,0 +1,9 @@ +import { OutputResponse } from "@iota/sdk-wasm-nova/web"; +import { IResponse } from "./IResponse"; + +export interface INftDetailsResponse extends IResponse { + /** + * The nft output details response. + */ + nftOutputDetails?: OutputResponse; +} diff --git a/client/src/services/nova/novaApiClient.ts b/client/src/services/nova/novaApiClient.ts index 493dc5c50..fad3bce73 100644 --- a/client/src/services/nova/novaApiClient.ts +++ b/client/src/services/nova/novaApiClient.ts @@ -2,8 +2,8 @@ import { INetworkBoundGetRequest } from "~/models/api/INetworkBoundGetRequest"; import { IBlockRequest } from "~/models/api/nova/block/IBlockRequest"; import { IBlockResponse } from "~/models/api/nova/block/IBlockResponse"; import { IOutputDetailsRequest } from "~/models/api/IOutputDetailsRequest"; -import { IAccountRequest } from "~/models/api/nova/IAccountRequest"; -import { IAccountResponse } from "~/models/api/nova/IAccountResponse"; +import { IAccountDetailsRequest } from "~/models/api/nova/IAccountDetailsRequest"; +import { IAccountDetailsResponse } from "~/models/api/nova/IAccountDetailsResponse"; import { IAssociationsResponse } from "~/models/api/nova/IAssociationsResponse"; import { INodeInfoResponse } from "~/models/api/nova/INodeInfoResponse"; import { IOutputDetailsResponse } from "~/models/api/nova/IOutputDetailsResponse"; @@ -15,6 +15,8 @@ import { IRewardsRequest } from "~/models/api/nova/IRewardsRequest"; import { IRewardsResponse } from "~/models/api/nova/IRewardsResponse"; import { IStatsGetRequest } from "~/models/api/stats/IStatsGetRequest"; import { IStatsGetResponse } from "~/models/api/stats/IStatsGetResponse"; +import { INftDetailsRequest } from "~/models/api/nova/INftDetailsRequest"; +import { INftDetailsResponse } from "~/models/api/nova/INftDetailsResponse"; /** * Class to handle api communications on nova. @@ -61,8 +63,17 @@ export class NovaApiClient extends ApiClient { * @param request The request to send. * @returns The response from the request. */ - public async accountDetails(request: IAccountRequest): Promise { - return this.callApi(`nova/account/${request.network}/${request.accountId}`, "get"); + public async accountDetails(request: IAccountDetailsRequest): Promise { + return this.callApi(`nova/account/${request.network}/${request.accountId}`, "get"); + } + + /** + * Get the nft output details. + * @param request The request to send. + * @returns The response from the request. + */ + public async nftDetails(request: INftDetailsRequest): Promise { + return this.callApi(`nova/nft/${request.network}/${request.nftId}`, "get"); } /**