sui_graphql_rpc/types/
gas.rs1use async_graphql::connection::Connection;
5use async_graphql::connection::CursorType;
6use async_graphql::connection::Edge;
7use async_graphql::*;
8use sui_types::{
9 base_types::SuiAddress as NativeSuiAddress,
10 effects::{TransactionEffects as NativeTransactionEffects, TransactionEffectsAPI},
11 gas::GasCostSummary as NativeGasCostSummary,
12 transaction::GasData,
13};
14
15use super::{address::Address, big_int::BigInt, object::Object, sui_address::SuiAddress};
16use super::{cursor::Page, object::ObjectKey};
17use crate::consistency::ConsistentIndexCursor;
18use crate::error::Error;
19use crate::types::cursor::JsonCursor;
20
21type CGasPayment = JsonCursor<ConsistentIndexCursor>;
22
23#[derive(Clone, Debug, PartialEq, Eq)]
24pub(crate) struct GasInput {
25 pub owner: SuiAddress,
26 pub price: u64,
27 pub budget: u64,
28 pub payment_obj_keys: Vec<ObjectKey>,
29 pub checkpoint_viewed_at: u64,
31}
32
33#[derive(Clone, Copy, Debug, PartialEq, Eq)]
34pub(crate) struct GasCostSummary {
35 pub computation_cost: u64,
36 pub storage_cost: u64,
37 pub storage_rebate: u64,
38 pub non_refundable_storage_fee: u64,
39}
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq)]
42pub(crate) struct GasEffects {
43 pub summary: GasCostSummary,
44 pub object_id: SuiAddress,
45 pub object_version: u64,
46 pub checkpoint_viewed_at: u64,
48}
49
50#[Object]
52impl GasInput {
53 async fn gas_sponsor(&self) -> Option<Address> {
55 Some(Address {
56 address: self.owner,
57 checkpoint_viewed_at: self.checkpoint_viewed_at,
58 })
59 }
60
61 async fn gas_payment(
63 &self,
64 ctx: &Context<'_>,
65 first: Option<u64>,
66 after: Option<CGasPayment>,
67 last: Option<u64>,
68 before: Option<CGasPayment>,
69 ) -> Result<Connection<String, Object>> {
70 let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?;
77
78 let mut connection = Connection::new(false, false);
79 if self.payment_obj_keys.is_empty() {
81 return Ok(connection);
82 }
83
84 let Some((prev, next, checkpoint_viewed_at, cs)) = page
85 .paginate_consistent_indices(self.payment_obj_keys.len(), self.checkpoint_viewed_at)?
86 else {
87 return Ok(connection);
88 };
89
90 connection.has_previous_page = prev;
91 connection.has_next_page = next;
92
93 let cursors: Vec<_> = cs.collect();
95 let objects = Object::query_many(
96 ctx,
97 cursors
98 .iter()
99 .map(|c| self.payment_obj_keys[c.ix].clone())
100 .collect(),
101 checkpoint_viewed_at,
102 )
103 .await?
104 .into_iter()
105 .map(|obj| obj.ok_or_else(|| Error::Internal("Gas object not found".to_string())))
106 .collect::<Result<Vec<_>, _>>()?;
107
108 for (c, obj) in cursors.into_iter().zip(objects) {
109 connection.edges.push(Edge::new(c.encode_cursor(), obj));
110 }
111
112 Ok(connection)
113 }
114
115 async fn gas_price(&self) -> Option<BigInt> {
118 Some(BigInt::from(self.price))
119 }
120
121 async fn gas_budget(&self) -> Option<BigInt> {
123 Some(BigInt::from(self.budget))
124 }
125}
126
127#[Object]
129impl GasCostSummary {
130 async fn computation_cost(&self) -> Option<BigInt> {
132 Some(BigInt::from(self.computation_cost))
133 }
134
135 async fn storage_cost(&self) -> Option<BigInt> {
137 Some(BigInt::from(self.storage_cost))
138 }
139
140 async fn storage_rebate(&self) -> Option<BigInt> {
144 Some(BigInt::from(self.storage_rebate))
145 }
146
147 async fn non_refundable_storage_fee(&self) -> Option<BigInt> {
150 Some(BigInt::from(self.non_refundable_storage_fee))
151 }
152}
153
154#[Object]
156impl GasEffects {
157 async fn gas_object(&self, ctx: &Context<'_>) -> Result<Option<Object>> {
158 Object::query(
159 ctx,
160 self.object_id,
161 Object::at_version(self.object_version, self.checkpoint_viewed_at),
162 )
163 .await
164 .extend()
165 }
166
167 async fn gas_summary(&self) -> Option<&GasCostSummary> {
168 Some(&self.summary)
169 }
170}
171
172impl GasEffects {
173 pub(crate) fn from(effects: &NativeTransactionEffects, checkpoint_viewed_at: u64) -> Self {
177 let ((id, version, _digest), _owner) = effects.gas_object();
178 Self {
179 summary: GasCostSummary::from(effects.gas_cost_summary()),
180 object_id: SuiAddress::from(id),
181 object_version: version.value(),
182 checkpoint_viewed_at,
183 }
184 }
185}
186
187impl GasInput {
188 pub(crate) fn from(s: &GasData, checkpoint_viewed_at: u64) -> Self {
192 let payment_obj_keys = match s.owner {
193 NativeSuiAddress::ZERO => vec![], _ => s
195 .payment
196 .iter()
197 .map(|o| ObjectKey {
198 object_id: o.0.into(),
199 version: o.1.value().into(),
200 })
201 .collect(),
202 };
203
204 Self {
205 owner: s.owner.into(),
206 price: s.price,
207 budget: s.budget,
208 payment_obj_keys,
209 checkpoint_viewed_at,
210 }
211 }
212}
213
214impl From<&NativeGasCostSummary> for GasCostSummary {
215 fn from(gcs: &NativeGasCostSummary) -> Self {
216 Self {
217 computation_cost: gcs.computation_cost,
218 storage_cost: gcs.storage_cost,
219 storage_rebate: gcs.storage_rebate,
220 non_refundable_storage_fee: gcs.non_refundable_storage_fee,
221 }
222 }
223}