sui_gql_client/mutations/
execute_transaction_classic.rs

1use af_sui_types::TransactionEffects;
2use cynic::GraphQlResponse;
3use sui_gql_schema::scalars;
4
5use crate::{GraphQlClient, GraphQlErrors, GraphQlResponseExt, schema};
6
7#[derive(cynic::QueryVariables, Clone, Debug)]
8pub struct Variables {
9    /// [TransactionData] struct that has been BCS-encoded and then Base64-encoded.
10    ///
11    /// [TransactionData]: af_sui_types::TransactionData
12    pub tx_bytes: String,
13    /// A list of `flag || signature || pubkey` bytes, Base64-encoded.
14    pub signatures: Vec<String>,
15}
16
17/// Execute a transaction, committing its effects on chain.
18///
19/// Waits until the transaction has been finalized on chain to return its transaction digest. If the
20/// transaction could not be finalized, returns the errors that prevented it, instead.
21#[derive(cynic::QueryFragment, Clone, Debug)]
22#[cynic(variables = "Variables")]
23pub struct Mutation {
24    #[arguments(txBytes: $tx_bytes, signatures: $signatures)]
25    pub execute_transaction_block: ExecutionResult,
26}
27
28impl Mutation {
29    /// Execute a transaction, committing its effects on chain.
30    ///
31    /// Waits until the transaction has been finalized on chain to return its transaction digest. If the
32    /// transaction could not be finalized, returns the errors that prevented it, instead.
33    ///
34    /// Args:
35    /// - `tx_bytes`: [TransactionData] struct that has been BCS-encoded and then Base64-encoded.
36    /// - `signatures`: A list of `flag || signature || pubkey` bytes, Base64-encoded.
37    ///
38    /// [TransactionData]: af_sui_types::TransactionData
39    #[allow(clippy::future_not_send)]
40    pub async fn execute<Client: GraphQlClient>(
41        client: &Client,
42        tx_bytes: String,
43        signatures: Vec<String>,
44    ) -> Result<TransactionEffects, Error<Client::Error>> {
45        let result: GraphQlResponse<Self> = client
46            .mutation(Variables {
47                tx_bytes,
48                signatures,
49            })
50            .await
51            .map_err(Error::Client)?;
52        let Some(Self {
53            execute_transaction_block: ExecutionResult { effects, errors },
54        }) = result.try_into_data()?
55        else {
56            return Err(Error::NoData);
57        };
58
59        if let Some(errors) = errors {
60            return Err(Error::Execution(errors));
61        }
62
63        Ok(effects.bcs.into_inner())
64    }
65}
66
67#[derive(thiserror::Error, Debug)]
68pub enum Error<T> {
69    #[error("No data in transaction GQL response")]
70    NoData,
71    #[error(transparent)]
72    Client(T),
73    #[error(transparent)]
74    GraphQlResponse(#[from] GraphQlErrors),
75    #[error("Executing transaction: {0:?}")]
76    Execution(Vec<String>),
77}
78
79#[derive(cynic::QueryFragment, Clone, Debug)]
80pub struct ExecutionResult {
81    /// The effects of the executed transaction.
82    pub effects: TransactionBlockEffects,
83    /// The errors field captures any errors that occurred during execution
84    pub errors: Option<Vec<String>>,
85}
86
87/// The effects representing the result of executing a transaction block.
88#[derive(cynic::QueryFragment, Clone, Debug)]
89pub struct TransactionBlockEffects {
90    /// Base64 encoded bcs serialization of the on-chain transaction effects.
91    pub bcs: scalars::Base64Bcs<TransactionEffects>,
92}