Skip to content

Conversation

@howjmay
Copy link
Member

@howjmay howjmay commented Oct 10, 2025

In the previous JSON RPC, iota_executeTransactionBlock and dry run would return
object changes and balance changes. However, thee fields are not returned in
the current GraphQL sdk.

@howjmay howjmay marked this pull request as draft October 10, 2025 08:21
@howjmay howjmay force-pushed the modify-sdk branch 5 times, most recently from 72fc959 to fc45052 Compare October 10, 2025 17:17
@howjmay howjmay marked this pull request as ready for review October 11, 2025 17:30
@howjmay howjmay force-pushed the modify-sdk branch 3 times, most recently from 1da8677 to 8780be8 Compare October 15, 2025 08:34
In the previous JSON RPC, iota_executeTransactionBlock and dry run would return
object changes and balance changes. However, thee fields are not returned in
the current GraphQL sdk.
@howjmay
Copy link
Member Author

howjmay commented Oct 15, 2025

Hi @Thoralf-M I am meeting a problem, and I am having no idea how to solve it.
This PR aims to return ObjectChanges. However, the object type of a created object in the ObjectChanges is not returned.
I am not sure whether it is an issue in GraphQL side? Maybe it is just not possible based on the current GraphQL, or node impl?
Thank you

@Thoralf-M
Copy link
Member

Hi @Thoralf-M I am meeting a problem, and I am having no idea how to solve it. This PR aims to return ObjectChanges. However, the object type of a created object in the ObjectChanges is not returned. I am not sure whether it is an issue in GraphQL side? Maybe it is just not possible based on the current GraphQL, or node impl? Thank you

GraphQL definitely supports that, seems like the SDK should be adjusted so TransactionEffectsV1::changed_objects contain the full objects for the input and output changes instead of the current ObjectIn, ObjectOut structs

@Thoralf-M
Copy link
Member

I created this issue #314 to make the data available

@howjmay
Copy link
Member Author

howjmay commented Oct 15, 2025

Thank you @Thoralf-M

#[cynic(schema = "rpc", graphql_type = "TransactionBlockEffects")]
pub struct TransactionBlockEffects {
pub bcs: Base64,
pub object_changes: ObjectChangeConnection,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't like to modify the TransactionBlockEffects struct like this as this would be requested for all requests then even if users don't care about the information
Instead an own request should be send, would this work for you?

// Copyright (c) 2025 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use cynic::QueryBuilder;
use eyre::Result;
use iota_graphql_client::{
    Client,
    query_types::{Base64, BigInt, schema},
};
use iota_types::Address;

#[derive(cynic::QueryVariables, Debug)]
pub struct TransactionBlockArgs {
    pub digest: String,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(
    schema = "rpc",
    graphql_type = "Query",
    variables = "TransactionBlockArgs"
)]
pub struct TransactionBlockEffectsQuery {
    #[arguments(digest: $digest)]
    pub transaction_block: Option<TxBlockEffects>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "TransactionBlock")]
pub struct TxBlockEffects {
    pub effects: Option<TransactionBlockEffects>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "TransactionBlockEffects")]
pub struct TransactionBlockEffects {
    #[cynic(rename = "objectChanges")]
    pub object_changes: Option<ObjectChangeConnection>,
    // here are more fields available, but we only care about object changes
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "ObjectChangeConnection")]
pub struct ObjectChangeConnection {
    pub nodes: Vec<ObjectChange>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "ObjectChange")]
pub struct ObjectChange {
    pub address: Address,
    #[cynic(rename = "inputState")]
    pub input_state: Option<Object>,
    #[cynic(rename = "outputState")]
    pub output_state: Option<Object>,
    #[cynic(rename = "idCreated")]
    pub id_created: Option<bool>,
    #[cynic(rename = "idDeleted")]
    pub id_deleted: Option<bool>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "Object")]
pub struct Object {
    pub address: Address,
    pub digest: Option<String>,
    pub version: u64,
    pub status: ObjectKind,
    pub owner: Option<ObjectOwner>,
    #[cynic(rename = "previousTransactionBlock")]
    pub previous_transaction_block: Option<TransactionBlock>,
    #[cynic(rename = "storageRebate")]
    pub storage_rebate: Option<BigInt>,
    pub display: Option<Vec<DisplayEntry>>,
    #[cynic(rename = "asMoveObject")]
    pub as_move_object: Option<MoveObject>,
    #[cynic(rename = "asMovePackage")]
    pub as_move_package: Option<MovePackage>,
    pub bcs: Option<Base64>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "MoveObject")]
pub struct MoveObject {
    pub contents: Option<MoveValue>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "MoveValue")]
pub struct MoveValue {
    #[cynic(rename = "type")]
    pub type_: MoveType,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "MoveType")]
pub struct MoveType {
    pub repr: String,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "TransactionBlock")]
pub struct TransactionBlock {
    pub digest: Option<String>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "DisplayEntry")]
pub struct DisplayEntry {
    pub key: String,
    pub value: Option<String>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "MovePackage")]
pub struct MovePackage {
    pub address: Address,
}

#[derive(cynic::Enum, Debug, Clone, Copy, PartialEq, Eq)]
#[cynic(schema = "rpc", graphql_type = "ObjectKind")]
pub enum ObjectKind {
    #[cynic(rename = "NOT_INDEXED")]
    NotIndexed,
    #[cynic(rename = "INDEXED")]
    Indexed,
    #[cynic(rename = "WRAPPED_OR_DELETED")]
    WrappedOrDeleted,
}

#[derive(cynic::InlineFragments, Debug)]
#[cynic(schema = "rpc")]
pub enum ObjectOwner {
    Immutable(Immutable),
    Shared(Shared),
    Parent(Parent),
    AddressOwner(AddressOwner),
    #[cynic(fallback)]
    Fallback,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "Immutable")]
pub struct Immutable {
    pub __typename: String,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "Shared")]
pub struct Shared {
    pub __typename: String,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "Parent")]
pub struct Parent {
    pub __typename: String,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "AddressOwner")]
pub struct AddressOwner {
    pub __typename: String,
}

#[tokio::main]
async fn main() -> Result<()> {
    let client = Client::new_devnet();

    let digest = "Agug2GETToZj4Ncw3RJn2KgDUEpVQKG1WaTZVcLcqYnf".to_string();
    let operation = TransactionBlockEffectsQuery::build(TransactionBlockArgs { digest });
    let response = client
        .run_query::<TransactionBlockEffectsQuery, TransactionBlockArgs>(&operation)
        .await;
    println!("{response:#?}");

    Ok(())
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants