sui_graphql_rpc/
mutation.rs1use crate::types::transaction_block_effects::TransactionBlockEffectsKind;
5use crate::{
6 error::Error, types::execution_result::ExecutionResult,
7 types::transaction_block_effects::TransactionBlockEffects,
8};
9use async_graphql::*;
10use fastcrypto::encoding::Encoding;
11use fastcrypto::{encoding::Base64, traits::ToFromBytes};
12use sui_json_rpc_types::SuiTransactionBlockResponseOptions;
13use sui_sdk::SuiClient;
14use sui_types::effects::TransactionEffects as NativeTransactionEffects;
15use sui_types::event::Event as NativeEvent;
16use sui_types::quorum_driver_types::ExecuteTransactionRequestType;
17use sui_types::transaction::SenderSignedData;
18use sui_types::{signature::GenericSignature, transaction::Transaction};
19pub struct Mutation;
20
21#[Object]
23impl Mutation {
24 async fn execute_transaction_block(
39 &self,
40 ctx: &Context<'_>,
41 tx_bytes: String,
42 signatures: Vec<String>,
43 ) -> Result<ExecutionResult> {
44 let sui_sdk_client: &Option<SuiClient> = ctx
45 .data()
46 .map_err(|_| Error::Internal("Unable to fetch Sui SDK client".to_string()))
47 .extend()?;
48 let sui_sdk_client = sui_sdk_client
49 .as_ref()
50 .ok_or_else(|| Error::Internal("Sui SDK client not initialized".to_string()))
51 .extend()?;
52 let tx_data = bcs::from_bytes(
53 &Base64::decode(&tx_bytes)
54 .map_err(|e| {
55 Error::Client(format!(
56 "Unable to deserialize transaction bytes from Base64: {e}"
57 ))
58 })
59 .extend()?,
60 )
61 .map_err(|e| {
62 Error::Client(format!(
63 "Unable to deserialize transaction bytes as BCS: {e}"
64 ))
65 })
66 .extend()?;
67
68 let mut sigs = Vec::new();
69 for sig in signatures {
70 sigs.push(
71 GenericSignature::from_bytes(
72 &Base64::decode(&sig)
73 .map_err(|e| {
74 Error::Client(format!(
75 "Unable to deserialize signature bytes {sig} from Base64: {e}"
76 ))
77 })
78 .extend()?,
79 )
80 .map_err(|e| Error::Client(format!("Unable to create signature from bytes: {e}")))
81 .extend()?,
82 );
83 }
84 let transaction = Transaction::from_generic_sig_data(tx_data, sigs);
85 let options = SuiTransactionBlockResponseOptions::new()
86 .with_events()
87 .with_raw_input()
88 .with_raw_effects();
89
90 let result = sui_sdk_client
91 .quorum_driver_api()
92 .execute_transaction_block(
93 transaction,
94 options,
95 Some(ExecuteTransactionRequestType::WaitForEffectsCert),
96 )
97 .await
98 .map_err(|e| Error::Internal(format!("Unable to execute transaction: {e}")))
101 .extend()?;
102
103 let native: NativeTransactionEffects = bcs::from_bytes(&result.raw_effects)
104 .map_err(|e| Error::Internal(format!("Unable to deserialize transaction effects: {e}")))
105 .extend()?;
106 let tx_data: SenderSignedData = bcs::from_bytes(&result.raw_transaction)
107 .map_err(|e| Error::Internal(format!("Unable to deserialize transaction data: {e}")))
108 .extend()?;
109
110 let events = result
111 .events
112 .ok_or_else(|| {
113 Error::Internal("No events are returned from transaction execution".to_string())
114 })?
115 .data
116 .into_iter()
117 .map(|e| NativeEvent {
118 package_id: e.package_id,
119 transaction_module: e.transaction_module,
120 sender: e.sender,
121 type_: e.type_,
122 contents: e.bcs.into_bytes(),
123 })
124 .collect();
125
126 Ok(ExecutionResult {
127 errors: if result.errors.is_empty() {
128 None
129 } else {
130 Some(result.errors)
131 },
132 effects: TransactionBlockEffects {
133 kind: TransactionBlockEffectsKind::Executed {
134 tx_data,
135 native,
136 events,
137 },
138 checkpoint_viewed_at: u64::MAX,
140 },
141 })
142 }
143}