From a8ae5b8d5d4142bd93d1252115e0d46b63aaed2e Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Thu, 3 Sep 2026 13:40:12 +0200 Subject: [PATCH 1/4] feat!: hold at most one complex transaction filter The GraphQL service stops supporting the combination of two or more complex filters with v1.38, and the client never sent `scanLimit`, so those combinations already failed at the server. A single selector field makes them unrepresentable instead. Co-Authored-By: Claude Opus 5 (1M context) --- .../examples/AddressTransactions/Program.cs | 4 +- .../csharp/examples/PackageInspect/Program.cs | 6 +- .../TransactionsWithFunction/Program.cs | 2 +- .../TransactionsWithShared/Program.cs | 2 +- .../go/examples/address_transactions/main.go | 10 +- bindings/go/examples/package_inspect/main.go | 9 +- .../transactions_with_function/main.go | 6 +- .../examples/transactions_with_shared/main.go | 3 +- .../kotlin/examples/AddressTransactions.kt | 4 +- bindings/kotlin/examples/PackageInspect.kt | 6 +- .../examples/TransactionsWithFunction.kt | 2 +- .../kotlin/examples/TransactionsWithShared.kt | 2 +- .../python/examples/address_transactions.py | 4 +- bindings/python/examples/package_inspect.py | 6 +- .../examples/transactions_with_function.py | 3 +- .../examples/transactions_with_shared.py | 2 +- .../swift/examples/AddressTransactions.swift | 4 +- bindings/swift/examples/PackageInspect.swift | 6 +- .../examples/TransactionsWithFunction.swift | 2 +- .../examples/TransactionsWithShared.swift | 2 +- .../wasm/examples/address_transactions.mjs | 4 +- bindings/wasm/examples/package_inspect.mjs | 6 +- .../examples/transactions_with_function.mjs | 2 +- .../examples/transactions_with_shared.mjs | 2 +- .../src/graphql/api/transactions.rs | 12 +- .../iota-sdk-ffi/src/graphql/query_types.rs | 167 ++++++++----- .../src/api/transactions.rs | 11 +- .../src/query_types/mod.rs | 9 +- .../src/query_types/transaction.rs | 227 ++++++++++++++---- 29 files changed, 356 insertions(+), 169 deletions(-) diff --git a/bindings/csharp/examples/AddressTransactions/Program.cs b/bindings/csharp/examples/AddressTransactions/Program.cs index dcb5fd0ba9..fe2b26a5b4 100644 --- a/bindings/csharp/examples/AddressTransactions/Program.cs +++ b/bindings/csharp/examples/AddressTransactions/Program.cs @@ -16,8 +16,8 @@ static async Task Main(string[] args) var client = GraphQlClient.NewLocalnet(); var address = Address.FromHex("0xa7c2cf9d8f8d95ff69d7a598c49c77acc36253f496f064a533ad306879b40bfa"); - var outgoing = await client.Transactions(filter: new TransactionsFilter(SentAddress: address)); - var incoming = await client.Transactions(filter: new TransactionsFilter(RecvAddress: address)); + var outgoing = await client.Transactions(filter: new TransactionsFilter().WithSentAddress(address)); + var incoming = await client.Transactions(filter: new TransactionsFilter().WithRecvAddress(address)); Console.WriteLine($"Transactions for {address.ToHex()}"); diff --git a/bindings/csharp/examples/PackageInspect/Program.cs b/bindings/csharp/examples/PackageInspect/Program.cs index a439d86322..cd3adc27b9 100644 --- a/bindings/csharp/examples/PackageInspect/Program.cs +++ b/bindings/csharp/examples/PackageInspect/Program.cs @@ -328,7 +328,7 @@ static bool TryExtractPolicy(string contents, out byte policy) static async Task ResolveUpgradeCapId(GraphQlClient client, ObjectId packageId) { var page = await client.TransactionsEffects( - new TransactionsFilter(ChangedObject: packageId), + new TransactionsFilter().WithChangedObject(packageId), new PaginationFilter(Direction.Forward, Limit: 1) ); @@ -528,7 +528,7 @@ ObjectId packageId while (true) { var page = await client.TransactionsDataEffects( - new TransactionsFilter(ChangedObject: packageId), + new TransactionsFilter().WithChangedObject(packageId), ForwardPage(cursor) ); @@ -559,7 +559,7 @@ ObjectId upgradeCapId while (true) { var page = await client.TransactionsDataEffects( - new TransactionsFilter(InputObject: upgradeCapId), + new TransactionsFilter().WithInputObject(upgradeCapId), ForwardPage(cursor) ); diff --git a/bindings/csharp/examples/TransactionsWithFunction/Program.cs b/bindings/csharp/examples/TransactionsWithFunction/Program.cs index 3453154e5a..0f71c6c9c8 100644 --- a/bindings/csharp/examples/TransactionsWithFunction/Program.cs +++ b/bindings/csharp/examples/TransactionsWithFunction/Program.cs @@ -8,7 +8,7 @@ class Program static async Task Main(string[] args) { var client = GraphQlClient.NewTestnet(); - var transactions = await client.Transactions(filter: new TransactionsFilter(Function: "0x3::iota_system::request_add_stake")); + var transactions = await client.Transactions(filter: new TransactionsFilter().WithFunction("0x3::iota_system::request_add_stake")); foreach (var transaction in transactions.Data) { diff --git a/bindings/csharp/examples/TransactionsWithShared/Program.cs b/bindings/csharp/examples/TransactionsWithShared/Program.cs index 56e293d980..8ebba2db7e 100644 --- a/bindings/csharp/examples/TransactionsWithShared/Program.cs +++ b/bindings/csharp/examples/TransactionsWithShared/Program.cs @@ -11,7 +11,7 @@ static async Task Main(string[] args) var sharedObjId = ObjectId.FromHex("0x7cab491740d51e0d75b26bf9984e49ba2e32a2d0694cabcee605543ed13c7dec"); - var transactions = await client.Transactions(filter: new TransactionsFilter(InputObject: sharedObjId)); + var transactions = await client.Transactions(filter: new TransactionsFilter().WithInputObject(sharedObjId)); foreach (var transaction in transactions.Data) { diff --git a/bindings/go/examples/address_transactions/main.go b/bindings/go/examples/address_transactions/main.go index 538aab4a06..9163be33db 100644 --- a/bindings/go/examples/address_transactions/main.go +++ b/bindings/go/examples/address_transactions/main.go @@ -23,16 +23,14 @@ func main() { log.Fatalf("Failed to parse address: %v", err) } - outgoing, err := client.Transactions(&iota_sdk.TransactionsFilter{ - SentAddress: &address, - }, nil) + sentFilter := iota_sdk.NewTransactionsFilter().WithSentAddress(address) + outgoing, err := client.Transactions(&sentFilter, nil) if err != nil { log.Fatalf("Failed to fetch outgoing transactions: %v", err) } - incoming, err := client.Transactions(&iota_sdk.TransactionsFilter{ - RecvAddress: &address, - }, nil) + recvFilter := iota_sdk.NewTransactionsFilter().WithRecvAddress(address) + incoming, err := client.Transactions(&recvFilter, nil) if err != nil { log.Fatalf("Failed to fetch incoming transactions: %v", err) } diff --git a/bindings/go/examples/package_inspect/main.go b/bindings/go/examples/package_inspect/main.go index 31c4e45196..3ee15f73df 100644 --- a/bindings/go/examples/package_inspect/main.go +++ b/bindings/go/examples/package_inspect/main.go @@ -369,8 +369,9 @@ func extractPolicy(contents string) (uint8, bool) { func resolveUpgradeCapID(client *iota_sdk.GraphQlClient, packageID *iota_sdk.ObjectId) (*iota_sdk.ObjectId, error) { limit := int32(1) + filter := iota_sdk.NewTransactionsFilter().WithChangedObject(packageID) page, err := client.TransactionsEffects( - &iota_sdk.TransactionsFilter{ChangedObject: &packageID}, + &filter, &iota_sdk.PaginationFilter{Direction: iota_sdk.DirectionForward, Limit: &limit}, ) if err != nil { @@ -544,10 +545,11 @@ func usesUpgradeCapForMakeImmutable(tx *iota_sdk.Transaction, upgradeCapID *iota func wasPackagePublishedAsImmutable(client *iota_sdk.GraphQlClient, packageID *iota_sdk.ObjectId) (bool, error) { var cursor *string + filter := iota_sdk.NewTransactionsFilter().WithChangedObject(packageID) for { page, err := client.TransactionsDataEffects( - &iota_sdk.TransactionsFilter{ChangedObject: &packageID}, + &filter, forwardPage(cursor), ) if err != nil { @@ -573,10 +575,11 @@ func wasPackagePublishedAsImmutable(client *iota_sdk.GraphQlClient, packageID *i func wasUpgradeCapUsedForMakeImmutable(client *iota_sdk.GraphQlClient, upgradeCapID *iota_sdk.ObjectId) (bool, error) { var cursor *string + filter := iota_sdk.NewTransactionsFilter().WithInputObject(upgradeCapID) for { page, err := client.TransactionsDataEffects( - &iota_sdk.TransactionsFilter{InputObject: &upgradeCapID}, + &filter, forwardPage(cursor), ) if err != nil { diff --git a/bindings/go/examples/transactions_with_function/main.go b/bindings/go/examples/transactions_with_function/main.go index a7f4f59f4d..3d382c044d 100644 --- a/bindings/go/examples/transactions_with_function/main.go +++ b/bindings/go/examples/transactions_with_function/main.go @@ -13,10 +13,8 @@ import ( func main() { client := iota_sdk.GraphQlClientNewTestnet() - function := "0x3::iota_system::request_add_stake" - transactions, err := client.Transactions(&iota_sdk.TransactionsFilter{ - Function: &function, - }, nil) + filter := iota_sdk.NewTransactionsFilter().WithFunction("0x3::iota_system::request_add_stake") + transactions, err := client.Transactions(&filter, nil) if err != nil { log.Fatalf("Failed to get transactions: %v", err) } diff --git a/bindings/go/examples/transactions_with_shared/main.go b/bindings/go/examples/transactions_with_shared/main.go index 5123d59b72..47ea3a42f9 100644 --- a/bindings/go/examples/transactions_with_shared/main.go +++ b/bindings/go/examples/transactions_with_shared/main.go @@ -23,7 +23,8 @@ func main() { sharedObjId := objIdFromHex("0x7cab491740d51e0d75b26bf9984e49ba2e32a2d0694cabcee605543ed13c7dec") - transactions, err := client.Transactions(&iota_sdk.TransactionsFilter{InputObject: &sharedObjId}, nil) + filter := iota_sdk.NewTransactionsFilter().WithInputObject(sharedObjId) + transactions, err := client.Transactions(&filter, nil) if err != nil { log.Fatalf("Failed to get transactions: %v", err) } diff --git a/bindings/kotlin/examples/AddressTransactions.kt b/bindings/kotlin/examples/AddressTransactions.kt index a06c2371c6..8555a0f5c8 100644 --- a/bindings/kotlin/examples/AddressTransactions.kt +++ b/bindings/kotlin/examples/AddressTransactions.kt @@ -18,8 +18,8 @@ fun main() = runBlocking { val address = Address.fromHex("0xa7c2cf9d8f8d95ff69d7a598c49c77acc36253f496f064a533ad306879b40bfa") - val outgoing = client.transactions(TransactionsFilter(sentAddress = address)) - val incoming = client.transactions(TransactionsFilter(recvAddress = address)) + val outgoing = client.transactions(TransactionsFilter().withSentAddress(address)) + val incoming = client.transactions(TransactionsFilter().withRecvAddress(address)) println("Transactions for ${address.toHex()}") diff --git a/bindings/kotlin/examples/PackageInspect.kt b/bindings/kotlin/examples/PackageInspect.kt index 1ddf10e4af..b48442c52e 100644 --- a/bindings/kotlin/examples/PackageInspect.kt +++ b/bindings/kotlin/examples/PackageInspect.kt @@ -248,7 +248,7 @@ private fun extractPolicy(contents: Value): Int? = private suspend fun resolveUpgradeCapId(client: GraphQlClient, packageId: ObjectId): ObjectId? { val page = client.transactionsEffects( - TransactionsFilter(changedObject = packageId), + TransactionsFilter().withChangedObject(packageId), PaginationFilter(direction = Direction.FORWARD, limit = 1), ) @@ -368,7 +368,7 @@ private suspend fun wasPackagePublishedAsImmutable( while (true) { val page = client.transactionsDataEffects( - TransactionsFilter(changedObject = packageId), + TransactionsFilter().withChangedObject(packageId), forwardPage(cursor), ) @@ -395,7 +395,7 @@ private suspend fun wasUpgradeCapUsedForMakeImmutable( while (true) { val page = client.transactionsDataEffects( - TransactionsFilter(inputObject = upgradeCapId), + TransactionsFilter().withInputObject(upgradeCapId), forwardPage(cursor), ) diff --git a/bindings/kotlin/examples/TransactionsWithFunction.kt b/bindings/kotlin/examples/TransactionsWithFunction.kt index 1dc31c6079..9654229a0a 100644 --- a/bindings/kotlin/examples/TransactionsWithFunction.kt +++ b/bindings/kotlin/examples/TransactionsWithFunction.kt @@ -10,7 +10,7 @@ fun main() = runBlocking { val client = GraphQlClient.newTestnet() val transactions = client.transactions( - TransactionsFilter(function = "0x3::iota_system::request_add_stake") + TransactionsFilter().withFunction("0x3::iota_system::request_add_stake") ) for (transaction in transactions.data) { println("Digest: ${transaction.transaction.digest().toBase58()}") diff --git a/bindings/kotlin/examples/TransactionsWithShared.kt b/bindings/kotlin/examples/TransactionsWithShared.kt index bf850913c0..519094f7e3 100644 --- a/bindings/kotlin/examples/TransactionsWithShared.kt +++ b/bindings/kotlin/examples/TransactionsWithShared.kt @@ -12,7 +12,7 @@ fun main() = runBlocking { val sharedObjId = ObjectId.fromHex("0x7cab491740d51e0d75b26bf9984e49ba2e32a2d0694cabcee605543ed13c7dec") - val transactions = client.transactions(TransactionsFilter(inputObject = sharedObjId)) + val transactions = client.transactions(TransactionsFilter().withInputObject(sharedObjId)) for (transaction in transactions.data) { println("Digest: ${transaction.transaction.digest().toBase58()}") diff --git a/bindings/python/examples/address_transactions.py b/bindings/python/examples/address_transactions.py index 8578506603..d002ada7db 100644 --- a/bindings/python/examples/address_transactions.py +++ b/bindings/python/examples/address_transactions.py @@ -18,9 +18,9 @@ async def main(): "0xa7c2cf9d8f8d95ff69d7a598c49c77acc36253f496f064a533ad306879b40bfa") outgoing = await client.transactions( - TransactionsFilter(sent_address=address)) + TransactionsFilter().with_sent_address(address)) incoming = await client.transactions( - TransactionsFilter(recv_address=address)) + TransactionsFilter().with_recv_address(address)) print(f"Transactions for {address.to_hex()}") diff --git a/bindings/python/examples/package_inspect.py b/bindings/python/examples/package_inspect.py index 53731a5c76..0905bc713d 100644 --- a/bindings/python/examples/package_inspect.py +++ b/bindings/python/examples/package_inspect.py @@ -223,7 +223,7 @@ def extract_policy(contents): async def resolve_upgrade_cap_id(client, package_id): page = await client.transactions_effects( - TransactionsFilter(changed_object=package_id), + TransactionsFilter().with_changed_object(package_id), PaginationFilter(direction=Direction.FORWARD, limit=1), ) @@ -343,7 +343,7 @@ async def was_package_published_as_immutable(client, package_id): while True: page = await client.transactions_data_effects( - TransactionsFilter(changed_object=package_id), + TransactionsFilter().with_changed_object(package_id), forward_page(cursor), ) @@ -363,7 +363,7 @@ async def was_upgrade_cap_used_for_make_immutable(client, upgrade_cap_id): while True: page = await client.transactions_data_effects( - TransactionsFilter(input_object=upgrade_cap_id), + TransactionsFilter().with_input_object(upgrade_cap_id), forward_page(cursor), ) diff --git a/bindings/python/examples/transactions_with_function.py b/bindings/python/examples/transactions_with_function.py index a246f94dbc..381db502f1 100644 --- a/bindings/python/examples/transactions_with_function.py +++ b/bindings/python/examples/transactions_with_function.py @@ -9,7 +9,8 @@ async def main(): client = GraphQlClient.new_testnet() transactions = await client.transactions( - TransactionsFilter(function="0x3::iota_system::request_add_stake"),) + TransactionsFilter().with_function( + "0x3::iota_system::request_add_stake"),) for transaction in transactions.data: print("Digest:", transaction.transaction.digest().to_base58()) diff --git a/bindings/python/examples/transactions_with_shared.py b/bindings/python/examples/transactions_with_shared.py index 522c3a402b..53a32eba8d 100644 --- a/bindings/python/examples/transactions_with_shared.py +++ b/bindings/python/examples/transactions_with_shared.py @@ -13,7 +13,7 @@ async def main(): "0x7cab491740d51e0d75b26bf9984e49ba2e32a2d0694cabcee605543ed13c7dec") transactions = await client.transactions( - TransactionsFilter(input_object=shared_obj_id),) + TransactionsFilter().with_input_object(shared_obj_id),) for transaction in transactions.data: print("Digest:", transaction.transaction.digest().to_base58()) diff --git a/bindings/swift/examples/AddressTransactions.swift b/bindings/swift/examples/AddressTransactions.swift index ede52f692f..c4864898ff 100644 --- a/bindings/swift/examples/AddressTransactions.swift +++ b/bindings/swift/examples/AddressTransactions.swift @@ -17,9 +17,9 @@ struct AddressTransactionsExample { hex: "0xa7c2cf9d8f8d95ff69d7a598c49c77acc36253f496f064a533ad306879b40bfa") let outgoing = try await client.transactions( - filter: TransactionsFilter(sentAddress: address)) + filter: TransactionsFilter().withSentAddress(sentAddress: address)) let incoming = try await client.transactions( - filter: TransactionsFilter(recvAddress: address)) + filter: TransactionsFilter().withRecvAddress(recvAddress: address)) print("Transactions for \(address.toHex())") diff --git a/bindings/swift/examples/PackageInspect.swift b/bindings/swift/examples/PackageInspect.swift index 02a9b926e7..a28709c750 100644 --- a/bindings/swift/examples/PackageInspect.swift +++ b/bindings/swift/examples/PackageInspect.swift @@ -277,7 +277,7 @@ private func resolveUpgradeCapId( packageId: ObjectId ) async throws -> ObjectId? { let page = try await client.transactionsEffects( - filter: TransactionsFilter(changedObject: packageId), + filter: TransactionsFilter().withChangedObject(changedObject: packageId), paginationFilter: PaginationFilter(direction: .forward, limit: 1) ) @@ -421,7 +421,7 @@ private func wasPackagePublishedAsImmutable( while true { let page = try await client.transactionsDataEffects( - filter: TransactionsFilter(changedObject: packageId), + filter: TransactionsFilter().withChangedObject(changedObject: packageId), paginationFilter: forwardPage(cursor: cursor) ) @@ -447,7 +447,7 @@ private func wasUpgradeCapUsedForMakeImmutable( while true { let page = try await client.transactionsDataEffects( - filter: TransactionsFilter(inputObject: upgradeCapId), + filter: TransactionsFilter().withInputObject(inputObject: upgradeCapId), paginationFilter: forwardPage(cursor: cursor) ) diff --git a/bindings/swift/examples/TransactionsWithFunction.swift b/bindings/swift/examples/TransactionsWithFunction.swift index 144ca74990..0b3442b871 100644 --- a/bindings/swift/examples/TransactionsWithFunction.swift +++ b/bindings/swift/examples/TransactionsWithFunction.swift @@ -8,7 +8,7 @@ struct TransactionsWithFunctionExample { static func main() async throws { let client = GraphQlClient.newTestnet() let transactions = try await client.transactions( - filter: TransactionsFilter(function: "0x3::iota_system::request_add_stake")) + filter: TransactionsFilter().withFunction(function: "0x3::iota_system::request_add_stake")) for transaction in transactions.data { print("Digest:", transaction.transaction.digest().toBase58()) } diff --git a/bindings/swift/examples/TransactionsWithShared.swift b/bindings/swift/examples/TransactionsWithShared.swift index 734f96095e..d73f34c7fe 100644 --- a/bindings/swift/examples/TransactionsWithShared.swift +++ b/bindings/swift/examples/TransactionsWithShared.swift @@ -12,7 +12,7 @@ struct TransactionsWithSharedExample { hex: "0x7cab491740d51e0d75b26bf9984e49ba2e32a2d0694cabcee605543ed13c7dec") let transactions = try await client.transactions( - filter: TransactionsFilter(inputObject: sharedObjId)) + filter: TransactionsFilter().withInputObject(inputObject: sharedObjId)) for transaction in transactions.data { print("Digest:", transaction.transaction.digest().toBase58()) diff --git a/bindings/wasm/examples/address_transactions.mjs b/bindings/wasm/examples/address_transactions.mjs index ffbd719f6b..5b62e0a7e3 100644 --- a/bindings/wasm/examples/address_transactions.mjs +++ b/bindings/wasm/examples/address_transactions.mjs @@ -22,10 +22,10 @@ const address = Address.fromHex( ); const outgoing = await client.transactions( - TransactionsFilter.new({ sentAddress: address }), + new TransactionsFilter().withSentAddress(address), ); const incoming = await client.transactions( - TransactionsFilter.new({ recvAddress: address }), + new TransactionsFilter().withRecvAddress(address), ); console.log(`Transactions for ${address.toHex()}`); diff --git a/bindings/wasm/examples/package_inspect.mjs b/bindings/wasm/examples/package_inspect.mjs index 6a0af4d22f..f7a59dbc3e 100644 --- a/bindings/wasm/examples/package_inspect.mjs +++ b/bindings/wasm/examples/package_inspect.mjs @@ -125,7 +125,7 @@ function extractPolicy(contents) { async function resolveUpgradeCapId(client, packageId) { const page = await client.transactionsEffects( - TransactionsFilter.new({ changedObject: packageId }), + new TransactionsFilter().withChangedObject(packageId), PaginationFilter.new({ direction: Direction.Forward, limit: 1 }), ); for (const effects of page.data) { @@ -246,7 +246,7 @@ async function wasPackagePublishedAsImmutable(client, packageId) { let cursor = undefined; while (true) { const page = await client.transactionsDataEffects( - TransactionsFilter.new({ changedObject: packageId }), + new TransactionsFilter().withChangedObject(packageId), forwardPage(cursor), ); for (const txData of page.data) { @@ -262,7 +262,7 @@ async function wasUpgradeCapUsedForMakeImmutable(client, upgradeCapId) { let cursor = undefined; while (true) { const page = await client.transactionsDataEffects( - TransactionsFilter.new({ inputObject: upgradeCapId }), + new TransactionsFilter().withInputObject(upgradeCapId), forwardPage(cursor), ); for (const txData of page.data) { diff --git a/bindings/wasm/examples/transactions_with_function.mjs b/bindings/wasm/examples/transactions_with_function.mjs index eec97d499e..6851d65935 100644 --- a/bindings/wasm/examples/transactions_with_function.mjs +++ b/bindings/wasm/examples/transactions_with_function.mjs @@ -7,7 +7,7 @@ await initAsync(); const client = GraphQlClient.newTestnet(); const transactions = await client.transactions( - TransactionsFilter.new({ function: "0x3::iota_system::request_add_stake" }), + new TransactionsFilter().withFunction("0x3::iota_system::request_add_stake"), ); for (const transaction of transactions.data) { console.log("Digest:", transaction.transaction.digest().toBase58()); diff --git a/bindings/wasm/examples/transactions_with_shared.mjs b/bindings/wasm/examples/transactions_with_shared.mjs index 8e80e9427a..8129b814ab 100644 --- a/bindings/wasm/examples/transactions_with_shared.mjs +++ b/bindings/wasm/examples/transactions_with_shared.mjs @@ -17,7 +17,7 @@ const sharedObjId = ObjectId.fromHex( ); const transactions = await client.transactions( - TransactionsFilter.new({ inputObject: sharedObjId }), + new TransactionsFilter().withInputObject(sharedObjId), ); for (const transaction of transactions.data) { diff --git a/crates/iota-sdk-ffi/src/graphql/api/transactions.rs b/crates/iota-sdk-ffi/src/graphql/api/transactions.rs index f203f82c3a..9a6b91a225 100644 --- a/crates/iota-sdk-ffi/src/graphql/api/transactions.rs +++ b/crates/iota-sdk-ffi/src/graphql/api/transactions.rs @@ -104,7 +104,7 @@ impl GraphQLClient { #[uniffi::method(default(pagination_filter = None, filter = None))] pub async fn transactions( &self, - filter: Option, + filter: Option>, pagination_filter: Option, ) -> Result { Ok(self @@ -112,7 +112,7 @@ impl GraphQLClient { .read() .await .transactions( - filter.map(Into::into), + filter.as_deref().map(Into::into), pagination_filter.map(Into::into).unwrap_or_default(), ) .await? @@ -124,7 +124,7 @@ impl GraphQLClient { #[uniffi::method(default(pagination_filter = None, filter = None))] pub async fn transactions_effects( &self, - filter: Option, + filter: Option>, pagination_filter: Option, ) -> Result { Ok(self @@ -132,7 +132,7 @@ impl GraphQLClient { .read() .await .transactions_effects( - filter.map(Into::into), + filter.as_deref().map(Into::into), pagination_filter.map(Into::into).unwrap_or_default(), ) .await? @@ -145,7 +145,7 @@ impl GraphQLClient { #[uniffi::method(default(pagination_filter = None, filter = None))] pub async fn transactions_data_effects( &self, - filter: Option, + filter: Option>, pagination_filter: Option, ) -> Result { Ok(self @@ -153,7 +153,7 @@ impl GraphQLClient { .read() .await .transactions_data_effects( - filter.map(Into::into), + filter.as_deref().map(Into::into), pagination_filter.map(Into::into).unwrap_or_default(), ) .await? diff --git a/crates/iota-sdk-ffi/src/graphql/query_types.rs b/crates/iota-sdk-ffi/src/graphql/query_types.rs index 910ad77750..a1374dad56 100644 --- a/crates/iota-sdk-ffi/src/graphql/query_types.rs +++ b/crates/iota-sdk-ffi/src/graphql/query_types.rs @@ -1,7 +1,7 @@ // Copyright (c) 2026 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use base64ct::Encoding; use iota_sdk::graphql_client::query_types::{ @@ -90,67 +90,122 @@ impl From for iota_sdk::graphql_client::TransactionDataE } } -#[derive(uniffi::Record)] -pub struct TransactionsFilter { - #[uniffi(default = None)] - pub function: Option, - #[uniffi(default = None)] - pub kind: Option, - #[uniffi(default = None)] - pub after_checkpoint: Option, - #[uniffi(default = None)] - pub at_checkpoint: Option, - #[uniffi(default = None)] - pub before_checkpoint: Option, - #[uniffi(default = None)] - pub sent_address: Option>, - #[uniffi(default = None)] - pub recv_address: Option>, - #[uniffi(default = None)] - pub input_object: Option>, - #[uniffi(default = None)] - pub changed_object: Option>, - #[uniffi(default = None)] - pub transaction_ids: Option>, - #[uniffi(default = None)] - pub wrapped_or_deleted_object: Option>, +/// Filter for transaction queries. +/// +/// Holds at most one of the function, kind, address and object filters that +/// the GraphQL service can only serve one of at a time, so each of those +/// setters replaces whichever was set before; the sender, checkpoint and +/// digest filters can be combined with them and with each other freely. +#[derive(Default, uniffi::Object)] +pub struct TransactionsFilter(RwLock); + +impl TransactionsFilter { + fn update( + &self, + f: impl FnOnce( + iota_sdk::graphql_client::query_types::TransactionsFilter, + ) -> iota_sdk::graphql_client::query_types::TransactionsFilter, + ) { + let mut lock = self.0.write().expect("error writing to filter"); + *lock = f(std::mem::take(&mut *lock)); + } } -impl From for TransactionsFilter { - fn from(value: iota_sdk::graphql_client::query_types::TransactionsFilter) -> Self { - Self { - function: value.function, - kind: value.kind.map(Into::into), - after_checkpoint: value.after_checkpoint, - at_checkpoint: value.at_checkpoint, - before_checkpoint: value.before_checkpoint, - sent_address: value.sent_address.map(Into::into).map(Arc::new), - recv_address: value.recv_address.map(Into::into).map(Arc::new), - input_object: value.input_object.map(Into::into).map(Arc::new), - changed_object: value.changed_object.map(Into::into).map(Arc::new), - transaction_ids: value.transaction_ids, - wrapped_or_deleted_object: value - .wrapped_or_deleted_object - .map(Into::into) - .map(Arc::new), - } +impl From<&TransactionsFilter> for iota_sdk::graphql_client::query_types::TransactionsFilter { + fn from(value: &TransactionsFilter) -> Self { + value.0.read().expect("error reading from filter").clone() } } -impl From for iota_sdk::graphql_client::query_types::TransactionsFilter { - fn from(value: TransactionsFilter) -> Self { +#[uniffi::export] +impl TransactionsFilter { + /// Create a filter that selects on nothing. + #[uniffi::constructor] + pub fn new() -> Self { Self::default() - .with_function(value.function) - .with_kind(value.kind.map(Into::into)) - .with_after_checkpoint(value.after_checkpoint) - .with_at_checkpoint(value.at_checkpoint) - .with_before_checkpoint(value.before_checkpoint) - .with_sent_address(value.sent_address.map(|v| **v)) - .with_recv_address(value.recv_address.map(|v| **v)) - .with_input_object(value.input_object.map(|v| **v)) - .with_changed_object(value.changed_object.map(|v| **v)) - .with_transaction_ids(value.transaction_ids) - .with_wrapped_or_deleted_object(value.wrapped_or_deleted_object.map(|v| **v)) + } + + /// Select by package, module, or function name, e.g. `"0x03"`, + /// `"0x03::iota_system"`, or `"0x03::iota_system::request_add_stake"`. + /// + /// Replaces the selector already set, if any. + pub fn with_function(self: Arc, function: String) -> Arc { + self.update(|filter| filter.with_function(function)); + self + } + + /// Select by transaction kind. + /// + /// Replaces the selector already set, if any. + pub fn with_kind(self: Arc, kind: TransactionBlockKindInput) -> Arc { + let kind = GraphQLTransactionBlockKindInput::from(kind); + self.update(|filter| filter.with_kind(kind)); + self + } + + /// Select transactions that sent an object to the given address. + /// + /// Replaces the selector already set, if any. + pub fn with_recv_address(self: Arc, recv_address: &Address) -> Arc { + self.update(|filter| filter.with_recv_address(**recv_address)); + self + } + + /// Select transactions that used the given object as an input. + /// + /// Replaces the selector already set, if any. + pub fn with_input_object(self: Arc, input_object: &ObjectId) -> Arc { + self.update(|filter| filter.with_input_object(**input_object)); + self + } + + /// Select transactions that output a version of the given object. + /// + /// Replaces the selector already set, if any. + pub fn with_changed_object(self: Arc, changed_object: &ObjectId) -> Arc { + self.update(|filter| filter.with_changed_object(**changed_object)); + self + } + + /// Select transactions that wrapped or deleted the given object. + /// + /// Replaces the selector already set, if any. + pub fn with_wrapped_or_deleted_object( + self: Arc, + wrapped_or_deleted_object: &ObjectId, + ) -> Arc { + self.update(|filter| filter.with_wrapped_or_deleted_object(**wrapped_or_deleted_object)); + self + } + + /// Filter by sender address. + pub fn with_sent_address(self: Arc, sent_address: &Address) -> Arc { + self.update(|filter| filter.with_sent_address(**sent_address)); + self + } + + /// Limit to transactions executed after the given checkpoint, exclusive. + pub fn with_after_checkpoint(self: Arc, after_checkpoint: u64) -> Arc { + self.update(|filter| filter.with_after_checkpoint(after_checkpoint)); + self + } + + /// Limit to transactions executed in the given checkpoint. + pub fn with_at_checkpoint(self: Arc, at_checkpoint: u64) -> Arc { + self.update(|filter| filter.with_at_checkpoint(at_checkpoint)); + self + } + + /// Limit to transactions executed before the given checkpoint, exclusive. + pub fn with_before_checkpoint(self: Arc, before_checkpoint: u64) -> Arc { + self.update(|filter| filter.with_before_checkpoint(before_checkpoint)); + self + } + + /// Filter by transaction digests. + pub fn with_transaction_ids(self: Arc, transaction_ids: Vec) -> Arc { + self.update(|filter| filter.with_transaction_ids(transaction_ids)); + self } } diff --git a/crates/iota-sdk-graphql-client/src/api/transactions.rs b/crates/iota-sdk-graphql-client/src/api/transactions.rs index c5e63c1314..ad018bf4fa 100644 --- a/crates/iota-sdk-graphql-client/src/api/transactions.rs +++ b/crates/iota-sdk-graphql-client/src/api/transactions.rs @@ -57,7 +57,7 @@ impl Client { let operation = TransactionBlocksQuery::build(TransactionBlocksQueryArgs { after: pagination.after, before: pagination.before, - filter: filter.into(), + filter: filter.into().map(Into::into), first: pagination.first, last: pagination.last, }); @@ -102,7 +102,7 @@ impl Client { let operation = TransactionBlocksEffectsQuery::build(TransactionBlocksQueryArgs { after: pagination.after, before: pagination.before, - filter: filter.into(), + filter: filter.into().map(Into::into), first: pagination.first, last: pagination.last, }); @@ -158,7 +158,7 @@ impl Client { let operation = TransactionBlocksWithEffectsQuery::build(TransactionBlocksQueryArgs { after: pagination.after, before: pagination.before, - filter: filter.into(), + filter: filter.into().map(Into::into), first: pagination.first, last: pagination.last, }); @@ -379,10 +379,7 @@ mod tests { client .transactions_data_effects( - TransactionsFilter { - transaction_ids: Some(vec![digest.to_string()]), - ..Default::default() - }, + TransactionsFilter::default().with_transaction_ids(vec![digest.to_string()]), PaginationFilter::default(), ) .await diff --git a/crates/iota-sdk-graphql-client/src/query_types/mod.rs b/crates/iota-sdk-graphql-client/src/query_types/mod.rs index fac4903ca3..d0234f22fe 100644 --- a/crates/iota-sdk-graphql-client/src/query_types/mod.rs +++ b/crates/iota-sdk-graphql-client/src/query_types/mod.rs @@ -82,10 +82,11 @@ pub use subscriptions::{ }; pub use transaction::{ TransactionBlock, TransactionBlockArgs, TransactionBlockCheckpointQuery, - TransactionBlockEffectsQuery, TransactionBlockIndexedQuery, TransactionBlockKindInput, - TransactionBlockQuery, TransactionBlockWithEffects, TransactionBlockWithEffectsQuery, - TransactionBlocksEffectsQuery, TransactionBlocksQuery, TransactionBlocksQueryArgs, - TransactionBlocksWithEffectsQuery, TransactionsFilter, + TransactionBlockEffectsQuery, TransactionBlockFilter, TransactionBlockIndexedQuery, + TransactionBlockKindInput, TransactionBlockQuery, TransactionBlockWithEffects, + TransactionBlockWithEffectsQuery, TransactionBlocksEffectsQuery, TransactionBlocksQuery, + TransactionBlocksQueryArgs, TransactionBlocksWithEffectsQuery, TransactionsFilter, + TransactionsSelector, }; use crate::error; diff --git a/crates/iota-sdk-graphql-client/src/query_types/transaction.rs b/crates/iota-sdk-graphql-client/src/query_types/transaction.rs index 02f3ef3804..f8d99998b3 100644 --- a/crates/iota-sdk-graphql-client/src/query_types/transaction.rs +++ b/crates/iota-sdk-graphql-client/src/query_types/transaction.rs @@ -116,7 +116,7 @@ pub struct TransactionBlocksQueryArgs { pub after: Option, pub last: Option, pub before: Option, - pub filter: Option, + pub filter: Option, } // =========================================================================== @@ -177,34 +177,112 @@ pub enum TransactionBlockKindInput { EndOfEpochTx, } -#[derive(Clone, cynic::InputObject, Debug, Default)] -#[cynic(schema = "rpc", graphql_type = "TransactionBlockFilter")] +/// The transaction filters that the GraphQL service can only serve one of at +/// a time. +/// +/// Combining two of the object or address filters requires a `scanLimit`, +/// which is deprecated and stops being supported with the v1.38 release, and +/// [`Kind`](Self::Kind) cannot be combined with any of the others at all. +/// Making them variants of one enum keeps those queries from being built in +/// the first place. +#[derive(Clone, Debug)] #[non_exhaustive] +pub enum TransactionsSelector { + /// Select by package, module, or function name, e.g. `"0x03"`, + /// `"0x03::iota_system"`, or `"0x03::iota_system::request_add_stake"`. + Function(String), + /// Select by transaction kind. + Kind(TransactionBlockKindInput), + /// Select transactions that sent an object to the given address. + RecvAddress(Address), + /// Select transactions that used the given object as an input. + InputObject(ObjectId), + /// Select transactions that output a version of the given object. + ChangedObject(ObjectId), + /// Select transactions that wrapped or deleted the given object. + WrappedOrDeletedObject(ObjectId), +} + +/// Filter for transaction queries. +/// +/// Holds at most one [`TransactionsSelector`], so each of the setters that +/// picks one replaces whichever was set before; the sender, checkpoint and +/// digest filters can be combined with it and with each other freely. +#[derive(Clone, Debug, Default)] pub struct TransactionsFilter { - pub function: Option, - pub kind: Option, - pub after_checkpoint: Option, - pub at_checkpoint: Option, - pub before_checkpoint: Option, - pub sent_address: Option
, - pub recv_address: Option
, - pub input_object: Option, - pub changed_object: Option, - pub wrapped_or_deleted_object: Option, - pub transaction_ids: Option>, + selector: Option, + sent_address: Option
, + after_checkpoint: Option, + at_checkpoint: Option, + before_checkpoint: Option, + transaction_ids: Option>, } impl TransactionsFilter { - /// Filter by package, module, or function name, e.g. `"0x03"`, - /// `"0x03::iota_system"`, or `"0x03::iota_system::request_add_stake"`. - pub fn with_function(mut self, function: impl Into>) -> Self { - self.function = function.into(); + /// Select on a function, kind, address or object, replacing the selector + /// already set, if any. + pub fn with_selector(mut self, selector: impl Into>) -> Self { + self.selector = selector.into(); self } - /// Filter by transaction kind. - pub fn with_kind(mut self, kind: impl Into>) -> Self { - self.kind = kind.into(); + /// Select by package, module, or function name, e.g. `"0x03"`, + /// `"0x03::iota_system"`, or `"0x03::iota_system::request_add_stake"`. + /// + /// Replaces the selector already set, if any. + pub fn with_function(self, function: impl Into>) -> Self { + self.with_selector(function.into().map(TransactionsSelector::Function)) + } + + /// Select by transaction kind. + /// + /// Replaces the selector already set, if any. + pub fn with_kind(self, kind: impl Into>) -> Self { + self.with_selector(kind.into().map(TransactionsSelector::Kind)) + } + + /// Select transactions that sent an object to the given address. + /// + /// Replaces the selector already set, if any. + pub fn with_recv_address(self, recv_address: impl Into>) -> Self { + self.with_selector(recv_address.into().map(TransactionsSelector::RecvAddress)) + } + + /// Select transactions that used the given object as an input. + /// + /// Replaces the selector already set, if any. + pub fn with_input_object(self, input_object: impl Into>) -> Self { + self.with_selector(input_object.into().map(TransactionsSelector::InputObject)) + } + + /// Select transactions that output a version of the given object. + /// + /// Replaces the selector already set, if any. + pub fn with_changed_object(self, changed_object: impl Into>) -> Self { + self.with_selector( + changed_object + .into() + .map(TransactionsSelector::ChangedObject), + ) + } + + /// Select transactions that wrapped or deleted the given object. + /// + /// Replaces the selector already set, if any. + pub fn with_wrapped_or_deleted_object( + self, + wrapped_or_deleted_object: impl Into>, + ) -> Self { + self.with_selector( + wrapped_or_deleted_object + .into() + .map(TransactionsSelector::WrappedOrDeletedObject), + ) + } + + /// Filter by sender address. + pub fn with_sent_address(mut self, sent_address: impl Into>) -> Self { + self.sent_address = sent_address.into(); self } @@ -226,43 +304,98 @@ impl TransactionsFilter { self } - /// Filter by sender address. - pub fn with_sent_address(mut self, sent_address: impl Into>) -> Self { - self.sent_address = sent_address.into(); + /// Filter by transaction digests. + pub fn with_transaction_ids(mut self, transaction_ids: impl Into>>) -> Self { + self.transaction_ids = transaction_ids.into(); self } - /// Filter by the address receiving an object from the transaction. - pub fn with_recv_address(mut self, recv_address: impl Into>) -> Self { - self.recv_address = recv_address.into(); - self + /// The selector this filter selects on, if any. + pub fn selector(&self) -> Option<&TransactionsSelector> { + self.selector.as_ref() } - /// Filter by an object used as input to the transaction. - pub fn with_input_object(mut self, input_object: impl Into>) -> Self { - self.input_object = input_object.into(); - self + /// The sender address this filter is limited to, if any. + pub fn sent_address(&self) -> Option
{ + self.sent_address } - /// Filter by an object changed by the transaction. - pub fn with_changed_object(mut self, changed_object: impl Into>) -> Self { - self.changed_object = changed_object.into(); - self + /// The exclusive lower checkpoint bound of this filter, if any. + pub fn after_checkpoint(&self) -> Option { + self.after_checkpoint } - /// Filter by an object wrapped or deleted by the transaction. - pub fn with_wrapped_or_deleted_object( - mut self, - wrapped_or_deleted_object: impl Into>, - ) -> Self { - self.wrapped_or_deleted_object = wrapped_or_deleted_object.into(); - self + /// The checkpoint this filter is limited to, if any. + pub fn at_checkpoint(&self) -> Option { + self.at_checkpoint } - /// Filter by transaction digests. - pub fn with_transaction_ids(mut self, transaction_ids: impl Into>>) -> Self { - self.transaction_ids = transaction_ids.into(); - self + /// The exclusive upper checkpoint bound of this filter, if any. + pub fn before_checkpoint(&self) -> Option { + self.before_checkpoint + } + + /// The transaction digests this filter is limited to, if any. + pub fn transaction_ids(&self) -> Option<&[String]> { + self.transaction_ids.as_deref() + } +} + +/// The GraphQL input object, built from a [`TransactionsFilter`]. +#[derive(Clone, cynic::InputObject, Debug, Default)] +#[cynic(schema = "rpc", graphql_type = "TransactionBlockFilter")] +pub struct TransactionBlockFilter { + function: Option, + kind: Option, + after_checkpoint: Option, + at_checkpoint: Option, + before_checkpoint: Option, + sent_address: Option
, + recv_address: Option
, + input_object: Option, + changed_object: Option, + wrapped_or_deleted_object: Option, + transaction_ids: Option>, +} + +impl From for TransactionBlockFilter { + fn from(filter: TransactionsFilter) -> Self { + let TransactionsFilter { + selector, + sent_address, + after_checkpoint, + at_checkpoint, + before_checkpoint, + transaction_ids, + } = filter; + + let mut input = Self { + sent_address, + after_checkpoint, + at_checkpoint, + before_checkpoint, + transaction_ids, + ..Default::default() + }; + + if let Some(selector) = selector { + match selector { + TransactionsSelector::Function(function) => input.function = Some(function), + TransactionsSelector::Kind(kind) => input.kind = Some(kind), + TransactionsSelector::RecvAddress(address) => input.recv_address = Some(address), + TransactionsSelector::InputObject(object_id) => { + input.input_object = Some(object_id) + } + TransactionsSelector::ChangedObject(object_id) => { + input.changed_object = Some(object_id) + } + TransactionsSelector::WrappedOrDeletedObject(object_id) => { + input.wrapped_or_deleted_object = Some(object_id) + } + } + } + + input } } From 180883fd7b8d5f9fc1f0025d011633afa5c2f65d Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Fri, 4 Sep 2026 10:02:12 +0200 Subject: [PATCH 2/4] fix doc comment --- .../src/query_types/transaction.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/crates/iota-sdk-graphql-client/src/query_types/transaction.rs b/crates/iota-sdk-graphql-client/src/query_types/transaction.rs index f8d99998b3..c387b4eb8b 100644 --- a/crates/iota-sdk-graphql-client/src/query_types/transaction.rs +++ b/crates/iota-sdk-graphql-client/src/query_types/transaction.rs @@ -177,14 +177,7 @@ pub enum TransactionBlockKindInput { EndOfEpochTx, } -/// The transaction filters that the GraphQL service can only serve one of at -/// a time. -/// -/// Combining two of the object or address filters requires a `scanLimit`, -/// which is deprecated and stops being supported with the v1.38 release, and -/// [`Kind`](Self::Kind) cannot be combined with any of the others at all. -/// Making them variants of one enum keeps those queries from being built in -/// the first place. +/// Selection criteria for querying transactions. #[derive(Clone, Debug)] #[non_exhaustive] pub enum TransactionsSelector { From bde62d7f4e441e01917f30e4cb5e52fced23feb5 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Fri, 4 Sep 2026 10:03:37 +0200 Subject: [PATCH 3/4] select nit --- crates/iota-sdk-ffi/src/graphql/query_types.rs | 2 +- crates/iota-sdk-graphql-client/src/query_types/transaction.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/iota-sdk-ffi/src/graphql/query_types.rs b/crates/iota-sdk-ffi/src/graphql/query_types.rs index a1374dad56..af846173c3 100644 --- a/crates/iota-sdk-ffi/src/graphql/query_types.rs +++ b/crates/iota-sdk-ffi/src/graphql/query_types.rs @@ -202,7 +202,7 @@ impl TransactionsFilter { self } - /// Filter by transaction digests. + /// Select by transaction digests. pub fn with_transaction_ids(self: Arc, transaction_ids: Vec) -> Arc { self.update(|filter| filter.with_transaction_ids(transaction_ids)); self diff --git a/crates/iota-sdk-graphql-client/src/query_types/transaction.rs b/crates/iota-sdk-graphql-client/src/query_types/transaction.rs index c387b4eb8b..70a6b08386 100644 --- a/crates/iota-sdk-graphql-client/src/query_types/transaction.rs +++ b/crates/iota-sdk-graphql-client/src/query_types/transaction.rs @@ -297,7 +297,7 @@ impl TransactionsFilter { self } - /// Filter by transaction digests. + /// Select by transaction digests. pub fn with_transaction_ids(mut self, transaction_ids: impl Into>>) -> Self { self.transaction_ids = transaction_ids.into(); self From d4e135797120a0e8cef8560994ef270fd62ad668 Mon Sep 17 00:00:00 2001 From: Chloe Martin Date: Thu, 10 Sep 2026 11:39:18 +0200 Subject: [PATCH 4/4] re-add affected address --- crates/iota-sdk-ffi/src/graphql/query_types.rs | 8 ++++++++ .../src/query_types/transaction.rs | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/crates/iota-sdk-ffi/src/graphql/query_types.rs b/crates/iota-sdk-ffi/src/graphql/query_types.rs index 3f7a81aeaf..1b78872b0a 100644 --- a/crates/iota-sdk-ffi/src/graphql/query_types.rs +++ b/crates/iota-sdk-ffi/src/graphql/query_types.rs @@ -152,6 +152,14 @@ impl TransactionsFilter { self } + /// Select transactions that affected the given address. + /// + /// Replaces the selector already set, if any. + pub fn with_affected_address(self: Arc, affected_address: &Address) -> Arc { + self.update(|filter| filter.with_affected_address(**affected_address)); + self + } + /// Select transactions that used the given object as an input. /// /// Replaces the selector already set, if any. diff --git a/crates/iota-sdk-graphql-client/src/query_types/transaction.rs b/crates/iota-sdk-graphql-client/src/query_types/transaction.rs index 2cbca9e2f7..50c90ecf29 100644 --- a/crates/iota-sdk-graphql-client/src/query_types/transaction.rs +++ b/crates/iota-sdk-graphql-client/src/query_types/transaction.rs @@ -239,6 +239,8 @@ pub enum TransactionsSelector { Kind(TransactionBlockKindInput), /// Select transactions that sent an object to the given address. RecvAddress(Address), + /// Select transactions that affected the given address. + AffectedAddress(Address), /// Select transactions that used the given object as an input. InputObject(ObjectId), /// Select transactions that output a version of the given object. @@ -292,6 +294,17 @@ impl TransactionsFilter { self.with_selector(recv_address.into().map(TransactionsSelector::RecvAddress)) } + /// Select transactions that affected the given address. + /// + /// Replaces the selector already set, if any. + pub fn with_affected_address(self, affected_address: impl Into>) -> Self { + self.with_selector( + affected_address + .into() + .map(TransactionsSelector::AffectedAddress), + ) + } + /// Select transactions that used the given object as an input. /// /// Replaces the selector already set, if any. @@ -395,6 +408,7 @@ pub struct TransactionBlockFilter { at_checkpoint: Option, before_checkpoint: Option, sent_address: Option
, + affected_address: Option
, recv_address: Option
, input_object: Option, changed_object: Option, @@ -427,6 +441,9 @@ impl From for TransactionBlockFilter { TransactionsSelector::Function(function) => input.function = Some(function), TransactionsSelector::Kind(kind) => input.kind = Some(kind), TransactionsSelector::RecvAddress(address) => input.recv_address = Some(address), + TransactionsSelector::AffectedAddress(address) => { + input.affected_address = Some(address) + } TransactionsSelector::InputObject(object_id) => { input.input_object = Some(object_id) }