Skip to content

Commit a0b225d

Browse files
marc2332kodemartin
authored andcommitted
feat(ts-sdk): Add isTransactionIndexedOnNode method (#8716)
Closes #8606 `waitForTransaction` will be refactored in #8720 [run-ci]
1 parent ffb37b7 commit a0b225d

File tree

9 files changed

+151
-2
lines changed

9 files changed

+151
-2
lines changed

.changeset/proud-pillows-pull.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@iota/graphql-transport': minor
3+
'@iota/iota-sdk': minor
4+
---
5+
6+
Support the new node method `isTransactionIndexedOnNode`

sdk/graphql-transport/src/generated/queries.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4344,6 +4344,8 @@ export type Query = {
43444344
* error.
43454345
*/
43464346
events: EventConnection;
4347+
/** Check if a transaction is indexed on the fullnode. */
4348+
isTransactionIndexedOnNode: Scalars['Boolean']['output'];
43474349
/**
43484350
* The latest version of the package at `address`.
43494351
*
@@ -4533,6 +4535,11 @@ export type QueryEventsArgs = {
45334535
};
45344536

45354537

4538+
export type QueryIsTransactionIndexedOnNodeArgs = {
4539+
digest: Scalars['String']['input'];
4540+
};
4541+
4542+
45364543
export type QueryLatestPackageArgs = {
45374544
address: Scalars['IotaAddress']['input'];
45384545
};
@@ -5223,6 +5230,21 @@ export type TransactionBlock = {
52235230
* transaction block is a sponsored transaction block.
52245231
*/
52255232
gasInput?: Maybe<GasInput>;
5233+
/**
5234+
* Returns whether the transaction has been indexed on the fullnode.
5235+
*
5236+
* This makes a request to the fullnode if the transaction is not part of
5237+
* a checkpoint to resolve the index status on the node.
5238+
*
5239+
* However, as this relies on the transaction data being already
5240+
* constructed or fetched from the backing database, it only makes
5241+
* sense to be used with `Mutation.executeTransactionBlock` on the
5242+
* resulting effects.
5243+
*
5244+
* Otherwise, it is recommended that you use
5245+
* `Query.isTransactionIndexedOnNode` for optimal performance.
5246+
*/
5247+
indexedOnNode?: Maybe<Scalars['Boolean']['output']>;
52265248
/**
52275249
* The type of this transaction as well as the commands and/or parameters
52285250
* comprising the transaction of this kind.
@@ -6011,6 +6033,13 @@ export type ResolveNameServiceNamesQueryVariables = Exact<{
60116033

60126034
export type ResolveNameServiceNamesQuery = { __typename?: 'Query', address?: { __typename?: 'Address', iotaNamesRegistrations: { __typename?: 'NameRegistrationConnection', pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, endCursor?: string | null }, nodes: Array<{ __typename?: 'NameRegistration', name: string }> } } | null };
60136035

6036+
export type IsTransactionIndexedOnNodeQueryVariables = Exact<{
6037+
digest: Scalars['String']['input'];
6038+
}>;
6039+
6040+
6041+
export type IsTransactionIndexedOnNodeQuery = { __typename?: 'Query', isTransactionIndexedOnNode: boolean };
6042+
60146043
export type GetOwnedObjectsQueryVariables = Exact<{
60156044
owner: Scalars['IotaAddress']['input'];
60166045
limit?: InputMaybe<Scalars['Int']['input']>;
@@ -8222,6 +8251,11 @@ export const ResolveNameServiceNamesDocument = new TypedDocumentString(`
82228251
}
82238252
}
82248253
`) as unknown as TypedDocumentString<ResolveNameServiceNamesQuery, ResolveNameServiceNamesQueryVariables>;
8254+
export const IsTransactionIndexedOnNodeDocument = new TypedDocumentString(`
8255+
query IsTransactionIndexedOnNode($digest: String!) {
8256+
isTransactionIndexedOnNode(digest: $digest)
8257+
}
8258+
`) as unknown as TypedDocumentString<IsTransactionIndexedOnNodeQuery, IsTransactionIndexedOnNodeQueryVariables>;
82258259
export const GetOwnedObjectsDocument = new TypedDocumentString(`
82268260
query getOwnedObjects($owner: IotaAddress!, $limit: Int, $cursor: String, $showBcs: Boolean = false, $showContent: Boolean = false, $showDisplay: Boolean = false, $showType: Boolean = false, $showOwner: Boolean = false, $showPreviousTransaction: Boolean = false, $showStorageRebate: Boolean = false, $filter: ObjectFilter) {
82278261
address(address: $owner) {

sdk/graphql-transport/src/methods.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import {
5454
GetTransactionBlockDocument,
5555
GetTypeLayoutDocument,
5656
GetValidatorsApyDocument,
57+
IsTransactionIndexedOnNodeDocument,
5758
MultiGetObjectsDocument,
5859
MultiGetTransactionBlocksDocument,
5960
PaginateCheckpointTransactionBlocksDocument,
@@ -1460,6 +1461,19 @@ export const RPC_METHODS: {
14601461
featureFlags,
14611462
};
14621463
},
1464+
1465+
async isTransactionIndexedOnNode(transport, [digest]): Promise<boolean> {
1466+
const isTransactionIndexedOnNode = await transport.graphqlQuery(
1467+
{
1468+
query: IsTransactionIndexedOnNodeDocument,
1469+
variables: {
1470+
digest,
1471+
},
1472+
},
1473+
(data) => data.isTransactionIndexedOnNode,
1474+
);
1475+
return isTransactionIndexedOnNode;
1476+
},
14631477
};
14641478

14651479
export class UnsupportedParamError extends Error {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) 2025 IOTA Stiftung
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
query IsTransactionIndexedOnNode($digest: String!) {
5+
isTransactionIndexedOnNode(digest: $digest)
6+
}

sdk/graphql-transport/test/compatibility.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,4 +813,58 @@ describe('GraphQL IotaClient compatibility', () => {
813813

814814
expect(graphql).toEqual(rpc);
815815
});
816+
817+
test('isTransactionIndexedOnNode', async () => {
818+
const tx = new Transaction();
819+
tx.setSender(toolbox.address());
820+
const [coin] = tx.splitCoins(tx.gas, [1]);
821+
tx.transferObjects([coin], toolbox.address());
822+
823+
const transaction = await graphQLClient!.signAndExecuteTransaction({
824+
transaction: tx as Transaction,
825+
signer: toolbox.keypair,
826+
options: {
827+
showBalanceChanges: true,
828+
showEffects: true,
829+
showEvents: true,
830+
// TODO inputs missing valueType
831+
showInput: false,
832+
showObjectChanges: true,
833+
showRawInput: true,
834+
},
835+
});
836+
837+
expect(
838+
await toolbox.client.isTransactionIndexedOnNode({ digest: transaction.digest }),
839+
).toEqual(false);
840+
expect(
841+
await graphQLClient.isTransactionIndexedOnNode({ digest: transaction.digest }),
842+
).toEqual(false);
843+
844+
await toolbox.client.waitForTransaction({ digest: transaction.digest });
845+
846+
let result = null;
847+
for (const _ of Array.from({ length: 5 })) {
848+
try {
849+
result = await toolbox.client.isTransactionIndexedOnNode({
850+
digest: transaction.digest,
851+
});
852+
if (result) {
853+
break;
854+
} else {
855+
await new Promise((r) => {
856+
setTimeout(r, 2000);
857+
});
858+
}
859+
860+
// eslint-disable-next-line no-empty
861+
} catch (e) {}
862+
}
863+
expect(result).toEqual(true);
864+
865+
await graphQLClient.waitForTransaction({ digest: transaction.digest });
866+
expect(
867+
await graphQLClient.isTransactionIndexedOnNode({ digest: transaction.digest }),
868+
).toEqual(true);
869+
});
816870
});

sdk/typescript/src/client/client.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import type {
9898
IotaNameRecord,
9999
IotaNamesReverseLookupParams,
100100
IotaNamesFindAllRegistrationNFTsParams,
101+
IsTransactionIndexedOnNodeParams,
101102
} from './types/index.js';
102103

103104
export interface PaginationArguments<Cursor> {
@@ -986,4 +987,14 @@ export class IotaClient {
986987
params: [input.address, input.cursor, input.limit, input.options],
987988
});
988989
}
990+
991+
/**
992+
* Check if a Transaction has been indexed on the Node.
993+
*/
994+
async isTransactionIndexedOnNode(input: IsTransactionIndexedOnNodeParams): Promise<boolean> {
995+
return await this.transport.request({
996+
method: 'iota_isTransactionIndexedOnNode',
997+
params: [input.digest],
998+
});
999+
}
9891000
}

sdk/typescript/src/client/types/params.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ export interface GetTransactionBlockParams {
139139
/** options for specifying the content to be returned */
140140
options?: RpcTypes.IotaTransactionBlockResponseOptions | null | undefined;
141141
}
142+
/** Return if the transaction has been indexed on the fullnode. */
143+
export interface IsTransactionIndexedOnNodeParams {
144+
/** the digest of the queried transaction */
145+
digest: string;
146+
}
142147
/** Return the object data for a list of objects */
143148
export interface MultiGetObjectsParams {
144149
/** the IDs of the queried objects */

sdk/typescript/src/graphql/generated/2025.2/schema.graphql

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)