From f92e8645f706cfef40ddaf6d25d83502ee7d8c7e Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Sun, 29 Oct 2023 16:05:39 +0100 Subject: [PATCH] Add anchor indexer features --- bindings/core/src/method/client.rs | 21 +++++- bindings/core/src/method_handler/client.rs | 6 +- bindings/core/src/response.rs | 2 + bindings/nodejs/lib/client/client.ts | 38 ++++++++++ bindings/nodejs/lib/types/block/id.ts | 5 ++ .../nodejs/lib/types/client/bridge/client.ts | 16 ++++ .../nodejs/lib/types/client/bridge/index.ts | 4 + .../lib/types/client/query-parameters.ts | 4 + .../iota_sdk/client/_node_indexer_api.py | 29 +++++++- sdk/src/client/node_api/indexer/routes.rs | 73 ++++++++++++------- 10 files changed, 166 insertions(+), 32 deletions(-) diff --git a/bindings/core/src/method/client.rs b/bindings/core/src/method/client.rs index d8542a7014..c13efc2ae9 100644 --- a/bindings/core/src/method/client.rs +++ b/bindings/core/src/method/client.rs @@ -7,16 +7,17 @@ use iota_sdk::client::mqtt::Topic; use iota_sdk::{ client::{ node_api::indexer::query_parameters::{ - AccountOutputQueryParameters, BasicOutputQueryParameters, DelegationOutputQueryParameters, - FoundryOutputQueryParameters, NftOutputQueryParameters, OutputQueryParameters, + AccountOutputQueryParameters, AnchorOutputQueryParameters, BasicOutputQueryParameters, + DelegationOutputQueryParameters, FoundryOutputQueryParameters, NftOutputQueryParameters, + OutputQueryParameters, }, node_manager::node::NodeAuth, }, types::block::{ address::{Bech32Address, Hrp}, output::{ - dto::OutputDto, feature::Feature, unlock_condition::dto::UnlockConditionDto, AccountId, DelegationId, - FoundryId, NativeToken, NftId, OutputId, TokenScheme, + dto::OutputDto, feature::Feature, unlock_condition::dto::UnlockConditionDto, AccountId, AnchorId, + DelegationId, FoundryId, NativeToken, NftId, OutputId, TokenScheme, }, payload::{dto::PayloadDto, signed_transaction::TransactionId}, BlockId, IssuerId, SignedBlockDto, @@ -236,6 +237,18 @@ pub enum ClientMethod { /// Account id account_id: AccountId, }, + /// Fetch anchor output IDs + #[serde(rename_all = "camelCase")] + AnchorOutputIds { + /// Query parameters for output requests + query_parameters: AnchorOutputQueryParameters, + }, + /// Fetch anchor output ID + #[serde(rename_all = "camelCase")] + AnchorOutputId { + /// Anchor id + anchor_id: AnchorId, + }, /// Fetch delegation output IDs #[serde(rename_all = "camelCase")] DelegationOutputIds { diff --git a/bindings/core/src/method_handler/client.rs b/bindings/core/src/method_handler/client.rs index 3845fc14d8..8f9c541cbf 100644 --- a/bindings/core/src/method_handler/client.rs +++ b/bindings/core/src/method_handler/client.rs @@ -234,13 +234,17 @@ pub(crate) async fn call_client_method_internal(client: &Client, method: ClientM ClientMethod::AccountOutputIds { query_parameters } => { Response::OutputIdsResponse(client.account_output_ids(query_parameters).await?) } + ClientMethod::AccountOutputId { account_id } => Response::OutputId(client.account_output_id(account_id).await?), + ClientMethod::AnchorOutputIds { query_parameters } => { + Response::OutputIdsResponse(client.anchor_output_ids(query_parameters).await?) + } + ClientMethod::AnchorOutputId { anchor_id } => Response::OutputId(client.anchor_output_id(anchor_id).await?), ClientMethod::DelegationOutputId { delegation_id } => { Response::OutputId(client.delegation_output_id(delegation_id).await?) } ClientMethod::DelegationOutputIds { query_parameters } => { Response::OutputIdsResponse(client.delegation_output_ids(query_parameters).await?) } - ClientMethod::AccountOutputId { account_id } => Response::OutputId(client.account_output_id(account_id).await?), ClientMethod::FoundryOutputIds { query_parameters } => { Response::OutputIdsResponse(client.foundry_output_ids(query_parameters).await?) } diff --git a/bindings/core/src/response.rs b/bindings/core/src/response.rs index 1cda600f88..9493c4f956 100644 --- a/bindings/core/src/response.rs +++ b/bindings/core/src/response.rs @@ -130,6 +130,7 @@ pub enum Response { Outputs(Vec), /// Response for: /// - [`AccountOutputId`](crate::method::ClientMethod::AccountOutputId) + /// - [`AnchorOutputId`](crate::method::ClientMethod::AnchorOutputId) /// - [`DelegationOutputId`](crate::method::ClientMethod::DelegationOutputId) /// - [`FoundryOutputId`](crate::method::ClientMethod::FoundryOutputId) /// - [`NftOutputId`](crate::method::ClientMethod::NftOutputId) @@ -138,6 +139,7 @@ pub enum Response { /// - [`OutputIds`](crate::method::ClientMethod::OutputIds) /// - [`BasicOutputIds`](crate::method::ClientMethod::BasicOutputIds) /// - [`AccountOutputIds`](crate::method::ClientMethod::AccountOutputIds) + /// - [`AnchorOutputIds`](crate::method::ClientMethod::AnchorOutputIds) /// - [`DelegationOutputIds`](crate::method::ClientMethod::DelegationOutputIds) /// - [`FoundryOutputIds`](crate::method::ClientMethod::FoundryOutputIds) /// - [`NftOutputIds`](crate::method::ClientMethod::NftOutputIds) diff --git a/bindings/nodejs/lib/client/client.ts b/bindings/nodejs/lib/client/client.ts index 9bab98e1a9..c74553c68c 100644 --- a/bindings/nodejs/lib/client/client.ts +++ b/bindings/nodejs/lib/client/client.ts @@ -16,6 +16,7 @@ import { FoundryQueryParameter, NftQueryParameter, AccountQueryParameter, + AnchorQueryParameter, GenericQueryParameter, DelegationQueryParameter, } from '../types/client'; @@ -37,6 +38,7 @@ import { parseSignedBlock, SignedBlock, AccountId, + AnchorId, NftId, FoundryId, DelegationId, @@ -605,6 +607,42 @@ export class Client { return JSON.parse(response).payload; } + /** + * Get the corresponding output IDs given a list of anchor query parameters. + * + * @param queryParameters An array of `AnchorQueryParameter`s. + * @returns A paginated query response of corresponding output IDs. + */ + async anchorOutputIds( + queryParameters: AnchorQueryParameter[], + ): Promise { + const response = await this.methodHandler.callMethod({ + name: 'anchorOutputIds', + data: { + queryParameters, + }, + }); + + return JSON.parse(response).payload; + } + + /** + * Get the corresponding output ID from an anchor ID. + * + * @param anchorId An anchor ID. + * @returns The corresponding output ID. + */ + async anchorOutputId(anchorId: AnchorId): Promise { + const response = await this.methodHandler.callMethod({ + name: 'anchorOutputId', + data: { + anchorId, + }, + }); + + return JSON.parse(response).payload; + } + /** * Get the corresponding output IDs given a list of delegation query parameters. * diff --git a/bindings/nodejs/lib/types/block/id.ts b/bindings/nodejs/lib/types/block/id.ts index 33adab1d9e..3267996d9d 100644 --- a/bindings/nodejs/lib/types/block/id.ts +++ b/bindings/nodejs/lib/types/block/id.ts @@ -8,6 +8,11 @@ import { HexEncodedString } from '../utils'; */ export type AccountId = HexEncodedString; +/** + * An Anchor ID represented as hex-encoded string. + */ +export type AnchorId = HexEncodedString; + /** * An NFT ID represented as hex-encoded string. */ diff --git a/bindings/nodejs/lib/types/client/bridge/client.ts b/bindings/nodejs/lib/types/client/bridge/client.ts index 551605d803..0837c9f808 100644 --- a/bindings/nodejs/lib/types/client/bridge/client.ts +++ b/bindings/nodejs/lib/types/client/bridge/client.ts @@ -11,6 +11,7 @@ import type { BlockId, FoundryId, IssuerId, + AnchorId, NftId, DelegationId, Output, @@ -20,6 +21,7 @@ import type { import type { PreparedTransactionData } from '../prepared-transaction-data'; import type { AccountQueryParameter, + AnchorQueryParameter, FoundryQueryParameter, GenericQueryParameter, NftQueryParameter, @@ -237,6 +239,20 @@ export interface __AccountOutputIdMethod__ { }; } +export interface __AnchorOutputIdsMethod__ { + name: 'anchorOutputIds'; + data: { + queryParameters: AnchorQueryParameter[]; + }; +} + +export interface __AnchorOutputIdMethod__ { + name: 'anchorOutputId'; + data: { + anchorId: AnchorId; + }; +} + export interface __DelegationOutputIdsMethod__ { name: 'delegationOutputIds'; data: { diff --git a/bindings/nodejs/lib/types/client/bridge/index.ts b/bindings/nodejs/lib/types/client/bridge/index.ts index 676f26b261..591a2f1645 100644 --- a/bindings/nodejs/lib/types/client/bridge/index.ts +++ b/bindings/nodejs/lib/types/client/bridge/index.ts @@ -32,6 +32,8 @@ import type { __HexPublicKeyToBech32AddressMethod__, __AccountOutputIdsMethod__, __AccountOutputIdMethod__, + __AnchorOutputIdsMethod__, + __AnchorOutputIdMethod__, __DelegationOutputIdsMethod__, __DelegationOutputIdMethod__, __FoundryOutputIdsMethod__, @@ -84,6 +86,8 @@ export type __ClientMethods__ = | __HexPublicKeyToBech32AddressMethod__ | __AccountOutputIdsMethod__ | __AccountOutputIdMethod__ + | __AnchorOutputIdsMethod__ + | __AnchorOutputIdMethod__ | __DelegationOutputIdsMethod__ | __DelegationOutputIdMethod__ | __FoundryOutputIdsMethod__ diff --git a/bindings/nodejs/lib/types/client/query-parameters.ts b/bindings/nodejs/lib/types/client/query-parameters.ts index e540d86bbf..7dcf40375e 100644 --- a/bindings/nodejs/lib/types/client/query-parameters.ts +++ b/bindings/nodejs/lib/types/client/query-parameters.ts @@ -35,6 +35,10 @@ export type AccountQueryParameter = | UnlockableByAddress | CommonQueryParameters; +/** Query parameters for filtering Anchor Outputs */ +// TODO https://github.com/iotaledger/iota-sdk/issues/1503 +export type AnchorQueryParameter = any; + /** Query parameters for filtering Delegation Outputs */ // TODO https://github.com/iotaledger/iota-sdk/issues/1503 export type DelegationQueryParameter = any; diff --git a/bindings/python/iota_sdk/client/_node_indexer_api.py b/bindings/python/iota_sdk/client/_node_indexer_api.py index 38e8fe1730..5202858428 100644 --- a/bindings/python/iota_sdk/client/_node_indexer_api.py +++ b/bindings/python/iota_sdk/client/_node_indexer_api.py @@ -172,8 +172,33 @@ def account_output_id(self, account_id: HexStr) -> OutputId: 'accountId': account_id })) - def delegation_output_ids( - self, query_parameters: QueryParameters) -> OutputIdsResponse: + def anchor_output_ids( + self, query_parameters: QueryParameters) -> OutputIdsResponse: + """Fetch anchor output IDs from the given query parameters. + + Returns: + The corresponding output IDs of the anchor outputs. + """ + + query_parameters_camelized = query_parameters.to_dict() + + response = self._call_method('anchorOutputIds', { + 'queryParameters': query_parameters_camelized, + }) + return OutputIdsResponse(response) + + def anchor_output_id(self, anchor_id: HexStr) -> OutputId: + """Fetch anchor output ID from the given anchor ID. + + Returns: + The output ID of the anchor output. + """ + return OutputId.from_string(self._call_method('anchorOutputId', { + 'anchorId': anchor_id + })) + + def delegation_output_ids( + self, query_parameters: QueryParameters) -> OutputIdsResponse: """Fetch delegation output IDs from the given query parameters. Returns: diff --git a/sdk/src/client/node_api/indexer/routes.rs b/sdk/src/client/node_api/indexer/routes.rs index fdab4d15de..10df56dabd 100644 --- a/sdk/src/client/node_api/indexer/routes.rs +++ b/sdk/src/client/node_api/indexer/routes.rs @@ -6,14 +6,15 @@ use crate::{ client::{ node_api::indexer::query_parameters::{ - AccountOutputQueryParameters, BasicOutputQueryParameters, DelegationOutputQueryParameters, - FoundryOutputQueryParameters, NftOutputQueryParameters, OutputQueryParameters, + AccountOutputQueryParameters, AnchorOutputQueryParameters, BasicOutputQueryParameters, + DelegationOutputQueryParameters, FoundryOutputQueryParameters, NftOutputQueryParameters, + OutputQueryParameters, }, ClientInner, Error, Result, }, types::{ api::plugins::indexer::OutputIdsResponse, - block::output::{AccountId, DelegationId, FoundryId, NftId, OutputId}, + block::output::{AccountId, AnchorId, DelegationId, FoundryId, NftId, OutputId}, }, }; @@ -38,54 +39,76 @@ impl ClientInner { self.get_output_ids(route, query_parameters, true, false).await } - /// Get delegation outputs filtered by the given parameters. + /// Get account outputs filtered by the given parameters. /// GET with query parameter returns all outputIDs that fit these filter criteria. /// Returns Err(Node(NotFound) if no results are found. - /// api/indexer/v2/outputs/delegation - pub async fn delegation_output_ids( + /// api/indexer/v2/outputs/account + pub async fn account_output_ids( &self, - query_parameters: DelegationOutputQueryParameters, + query_parameters: AccountOutputQueryParameters, ) -> Result { - let route = "api/indexer/v2/outputs/delegation"; + let route = "api/indexer/v2/outputs/account"; self.get_output_ids(route, query_parameters, true, false).await } - /// Get delegation output by its delegationID. - /// api/indexer/v2/outputs/delegation/:{DelegationId} - pub async fn delegation_output_id(&self, delegation_id: DelegationId) -> Result { - let route = format!("api/indexer/v2/outputs/delegation/{delegation_id}"); + /// Get account output by its accountID. + /// api/indexer/v2/outputs/account/:{AccountId} + pub async fn account_output_id(&self, account_id: AccountId) -> Result { + let route = format!("api/indexer/v2/outputs/account/{account_id}"); Ok(*(self - .get_output_ids(&route, DelegationOutputQueryParameters::new(), true, false) + .get_output_ids(&route, AccountOutputQueryParameters::new(), true, false) .await? .first() - .ok_or_else(|| Error::NoOutput(format!("{delegation_id:?}")))?)) + .ok_or_else(|| Error::NoOutput(format!("{account_id:?}")))?)) } - /// Get account outputs filtered by the given parameters. + /// Get anchor outputs filtered by the given parameters. /// GET with query parameter returns all outputIDs that fit these filter criteria. /// Returns Err(Node(NotFound) if no results are found. - /// api/indexer/v2/outputs/account - pub async fn account_output_ids( + /// api/indexer/v2/outputs/anchor + pub async fn anchor_output_ids(&self, query_parameters: AnchorOutputQueryParameters) -> Result { + let route = "api/indexer/v2/outputs/anchor"; + + self.get_output_ids(route, query_parameters, true, false).await + } + + /// Get anchor output by its anchorID. + /// api/indexer/v2/outputs/anchor/:{AnchorId} + pub async fn anchor_output_id(&self, anchor_id: AnchorId) -> Result { + let route = format!("api/indexer/v2/outputs/anchor/{anchor_id}"); + + Ok(*(self + .get_output_ids(&route, AnchorOutputQueryParameters::new(), true, false) + .await? + .first() + .ok_or_else(|| Error::NoOutput(format!("{anchor_id:?}")))?)) + } + + /// Get delegation outputs filtered by the given parameters. + /// GET with query parameter returns all outputIDs that fit these filter criteria. + /// Returns Err(Node(NotFound) if no results are found. + /// api/indexer/v2/outputs/delegation + pub async fn delegation_output_ids( &self, - query_parameters: AccountOutputQueryParameters, + query_parameters: DelegationOutputQueryParameters, ) -> Result { - let route = "api/indexer/v2/outputs/account"; + let route = "api/indexer/v2/outputs/delegation"; self.get_output_ids(route, query_parameters, true, false).await } - /// Get account output by its accountID. - /// api/indexer/v2/outputs/account/:{AccountId} - pub async fn account_output_id(&self, account_id: AccountId) -> Result { - let route = format!("api/indexer/v2/outputs/account/{account_id}"); + /// Get delegation output by its delegationID. + /// api/indexer/v2/outputs/delegation/:{DelegationId} + pub async fn delegation_output_id(&self, delegation_id: DelegationId) -> Result { + let route = format!("api/indexer/v2/outputs/delegation/{delegation_id}"); Ok(*(self - .get_output_ids(&route, AccountOutputQueryParameters::new(), true, false) + .get_output_ids(&route, DelegationOutputQueryParameters::new(), true, false) .await? .first() - .ok_or_else(|| Error::NoOutput(format!("{account_id:?}")))?)) + .ok_or_else(|| Error::NoOutput(format!("{delegation_id:?}")))?)) } /// Get foundry outputs filtered by the given parameters.