openmina_node_native/graphql/
zkapp.rs

1use std::str::FromStr;
2
3use juniper::{GraphQLInputObject, GraphQLObject};
4use ledger::{FpExt, VerificationKey};
5use mina_p2p_messages::{
6    bigint::BigInt,
7    list::List,
8    pseq::PaddedSeq,
9    string::{TokenSymbol, ZkAppUri},
10    v2::{
11        CurrencyAmountStableV1, CurrencyBalanceStableV1, CurrencyFeeStableV1,
12        MinaBaseAccountUpdateAccountPreconditionStableV1,
13        MinaBaseAccountUpdateAuthorizationKindStableV1, MinaBaseAccountUpdateBodyEventsStableV1,
14        MinaBaseAccountUpdateBodyFeePayerStableV1, MinaBaseAccountUpdateBodyStableV1,
15        MinaBaseAccountUpdateFeePayerStableV1, MinaBaseAccountUpdateMayUseTokenStableV1,
16        MinaBaseAccountUpdatePreconditionsStableV1, MinaBaseAccountUpdateTStableV1,
17        MinaBaseAccountUpdateUpdateStableV1, MinaBaseAccountUpdateUpdateStableV1AppStateA,
18        MinaBaseAccountUpdateUpdateStableV1Delegate,
19        MinaBaseAccountUpdateUpdateStableV1Permissions, MinaBaseAccountUpdateUpdateStableV1Timing,
20        MinaBaseAccountUpdateUpdateStableV1TokenSymbol,
21        MinaBaseAccountUpdateUpdateStableV1VerificationKey,
22        MinaBaseAccountUpdateUpdateStableV1VotingFor, MinaBaseAccountUpdateUpdateStableV1ZkappUri,
23        MinaBaseAccountUpdateUpdateTimingInfoStableV1, MinaBaseControlStableV2,
24        MinaBasePermissionsStableV2, MinaBaseReceiptChainHashStableV1,
25        MinaBaseSignedCommandMemoStableV1, MinaBaseUserCommandStableV2,
26        MinaBaseVerificationKeyWireStableV1, MinaBaseZkappCommandTStableV1WireStableV1,
27        MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesA,
28        MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA,
29        MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAACallsA,
30        MinaBaseZkappPreconditionAccountStableV2, MinaBaseZkappPreconditionAccountStableV2Balance,
31        MinaBaseZkappPreconditionAccountStableV2BalanceA,
32        MinaBaseZkappPreconditionAccountStableV2Delegate,
33        MinaBaseZkappPreconditionAccountStableV2ProvedState,
34        MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash,
35        MinaBaseZkappPreconditionAccountStableV2StateA,
36        MinaBaseZkappPreconditionProtocolStateEpochDataStableV1,
37        MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger,
38        MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed,
39        MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint,
40        MinaBaseZkappPreconditionProtocolStateStableV1,
41        MinaBaseZkappPreconditionProtocolStateStableV1Amount,
42        MinaBaseZkappPreconditionProtocolStateStableV1AmountA,
43        MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot,
44        MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlotA,
45        MinaBaseZkappPreconditionProtocolStateStableV1Length,
46        MinaBaseZkappPreconditionProtocolStateStableV1LengthA,
47        MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash,
48        MinaNumbersGlobalSlotSinceGenesisMStableV1, MinaNumbersGlobalSlotSpanStableV1,
49        MinaStateBlockchainStateValueStableV2SignedAmount, PicklesProofProofsVerifiedMaxStableV2,
50        StateHash,
51    },
52};
53
54use node::account::AccountPublicKey;
55use serde::Deserialize;
56
57use super::{
58    account::{GraphQLTiming, InputGraphQLTiming},
59    ConversionError,
60};
61
62#[derive(GraphQLInputObject, Debug)]
63pub struct SendZkappInput {
64    pub zkapp_command: InputGraphQLZkappCommand,
65}
66
67impl TryFrom<SendZkappInput> for MinaBaseUserCommandStableV2 {
68    type Error = ConversionError;
69    fn try_from(value: SendZkappInput) -> Result<Self, Self::Error> {
70        value.zkapp_command.try_into()
71    }
72}
73
74#[derive(GraphQLObject, Debug)]
75pub struct GraphQLSendZkappResponse {
76    pub zkapp: GraphQLZkapp,
77}
78
79#[derive(GraphQLObject, Debug)]
80pub struct GraphQLZkapp {
81    pub hash: String,
82    pub failure_reason: Option<Vec<GraphQLFailureReason>>,
83    /// Zkapp represented as base64 string
84    pub id: String,
85    pub zkapp_command: GraphQLZkappCommand,
86}
87
88#[derive(GraphQLInputObject, Debug)]
89pub struct InputGraphQLZkapp {
90    // pub hash: String,
91    // pub failure_reason: Option<Vec<GraphQLFailureReason>>,
92    /// Zkapp represented as base64 string
93    // pub id: String,
94    pub zkapp_command: InputGraphQLZkappCommand,
95}
96
97#[derive(GraphQLObject, Debug)]
98pub struct GraphQLZkappCommand {
99    pub memo: String,
100    pub account_updates: Vec<GraphQLAccountUpdate>,
101    pub fee_payer: GraphQLFeePayer,
102}
103
104#[derive(GraphQLInputObject, Debug)]
105pub struct InputGraphQLZkappCommand {
106    pub memo: Option<String>,
107    pub account_updates: Vec<InputGraphQLAccountUpdate>,
108    pub fee_payer: InputGraphQLFeePayer,
109}
110
111impl TryFrom<MinaBaseZkappCommandTStableV1WireStableV1> for GraphQLZkapp {
112    type Error = ConversionError;
113
114    fn try_from(zkapp: MinaBaseZkappCommandTStableV1WireStableV1) -> Result<Self, Self::Error> {
115        let account_updates = zkapp
116            .account_updates
117            .clone()
118            .into_iter()
119            .map(|v| v.elt.account_update.try_into())
120            .collect::<Result<Vec<_>, _>>()?;
121
122        Ok(GraphQLZkapp {
123            hash: zkapp.hash()?.to_string(),
124            failure_reason: None,
125            id: zkapp.to_base64()?,
126            zkapp_command: GraphQLZkappCommand {
127                memo: zkapp.memo.to_base58check(),
128                account_updates,
129                fee_payer: GraphQLFeePayer::from(zkapp.fee_payer),
130            },
131        })
132    }
133}
134
135impl TryFrom<MinaBaseUserCommandStableV2> for GraphQLSendZkappResponse {
136    type Error = ConversionError;
137    fn try_from(value: MinaBaseUserCommandStableV2) -> Result<Self, Self::Error> {
138        if let MinaBaseUserCommandStableV2::ZkappCommand(zkapp) = value {
139            Ok(GraphQLSendZkappResponse {
140                zkapp: GraphQLZkapp::try_from(zkapp)?,
141            })
142        } else {
143            Err(ConversionError::WrongVariant)
144        }
145    }
146}
147
148impl TryFrom<InputGraphQLZkappCommand> for MinaBaseUserCommandStableV2 {
149    type Error = ConversionError;
150    fn try_from(value: InputGraphQLZkappCommand) -> Result<Self, Self::Error> {
151        Ok(MinaBaseUserCommandStableV2::ZkappCommand(
152            MinaBaseZkappCommandTStableV1WireStableV1 {
153                fee_payer: value.fee_payer.try_into()?,
154                account_updates: try_tree_from_account_updates(List::from_iter(
155                    value.account_updates,
156                ))?,
157                memo: if let Some(memo) = value.memo {
158                    MinaBaseSignedCommandMemoStableV1::from_base58check(&memo)
159                } else {
160                    let empty_memo = ledger::scan_state::transaction_logic::Memo::empty();
161                    MinaBaseSignedCommandMemoStableV1::from(&empty_memo)
162                },
163            },
164        ))
165    }
166}
167
168/// Recursively builds a tree of account updates based on their depth.
169fn try_tree_from_account_updates(
170    updates: List<InputGraphQLAccountUpdate>,
171) -> Result<List<MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesA>, ConversionError> {
172    let result =
173        try_tree_from_account_updates_aux(updates)?
174            .into_iter()
175            .map(|update| {
176                let MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAACallsA {
177                    elt,
178                    stack_hash,
179                } = update;
180                let MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA {
181                    account_update,
182                    account_update_digest,
183                    calls,
184                } = *elt;
185                let elt = MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA {
186                    account_update,
187                    account_update_digest,
188                    calls,
189                };
190                MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesA { elt, stack_hash }
191            })
192            .collect();
193    Ok(result)
194}
195
196fn try_tree_from_account_updates_aux(
197    updates: List<InputGraphQLAccountUpdate>,
198) -> Result<List<MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAACallsA>, ConversionError>
199{
200    let mut result = List::new();
201    let mut iter = updates.into_iter().peekable();
202
203    while let Some(account_update) = iter.next() {
204        let depth = account_update.body.call_depth;
205        let mut children = List::new();
206
207        while let Some(next_p) = iter.peek() {
208            if next_p.body.call_depth > depth {
209                // unwrap cannot fail, we just peeked it
210                children.push_back(iter.next().unwrap());
211            } else {
212                break;
213            }
214        }
215
216        let calls = try_tree_from_account_updates_aux(children)?;
217
218        result.push_back(
219            MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAACallsA {
220                elt: Box::new(MinaBaseZkappCommandTStableV1WireStableV1AccountUpdatesAA {
221                    account_update: account_update.try_into()?, // FIXME: remove unwrap
222                    account_update_digest: (),
223                    calls,
224                }),
225                stack_hash: (),
226            },
227        );
228    }
229
230    Ok(result)
231}
232
233#[derive(GraphQLObject, Debug)]
234pub struct GraphQLFeePayer {
235    pub body: GraphQLFeePayerBody,
236    pub authorization: String,
237}
238
239#[derive(GraphQLInputObject, Debug)]
240pub struct InputGraphQLFeePayer {
241    pub body: InputGraphQLFeePayerBody,
242    pub authorization: String,
243}
244
245#[derive(GraphQLObject, Debug)]
246pub struct GraphQLFeePayerBody {
247    pub public_key: String,
248    pub fee: String,
249    pub valid_until: Option<String>,
250    pub nonce: String,
251}
252
253#[derive(GraphQLInputObject, Debug)]
254pub struct InputGraphQLFeePayerBody {
255    pub public_key: String,
256    pub fee: String,
257    pub valid_until: Option<String>,
258    pub nonce: String,
259}
260
261#[derive(GraphQLObject, Debug)]
262pub struct GraphQLAccountUpdate {
263    pub body: GraphQLAccountUpdateBody,
264    pub authorization: GraphQLAuthorization,
265}
266
267#[derive(GraphQLInputObject, Debug)]
268pub struct InputGraphQLAccountUpdate {
269    pub body: InputGraphQLAccountUpdateBody,
270    pub authorization: InputGraphQLAuthorization,
271}
272
273#[derive(GraphQLObject, Debug)]
274pub struct GraphQLAuthorization {
275    pub proof: Option<String>,
276    pub signature: Option<String>,
277}
278
279#[derive(GraphQLInputObject, Debug)]
280pub struct InputGraphQLAuthorization {
281    pub proof: Option<String>,
282    pub signature: Option<String>,
283}
284
285impl TryFrom<MinaBaseControlStableV2> for GraphQLAuthorization {
286    type Error = ConversionError;
287
288    fn try_from(value: MinaBaseControlStableV2) -> Result<Self, Self::Error> {
289        let auth = match value {
290            MinaBaseControlStableV2::Signature(signature) => GraphQLAuthorization {
291                proof: None,
292                signature: Some(signature.to_string()),
293            },
294            MinaBaseControlStableV2::Proof(proof) => GraphQLAuthorization {
295                proof: Some(
296                    serde_json::to_string_pretty(&proof)?
297                        .trim_matches('"')
298                        .to_string(),
299                ),
300                signature: None,
301            },
302            MinaBaseControlStableV2::NoneGiven => GraphQLAuthorization {
303                proof: None,
304                signature: None,
305            },
306        };
307        Ok(auth)
308    }
309}
310
311impl TryFrom<InputGraphQLAuthorization> for MinaBaseControlStableV2 {
312    type Error = ConversionError;
313
314    fn try_from(value: InputGraphQLAuthorization) -> Result<Self, Self::Error> {
315        match (value.signature, value.proof) {
316            (Some(signature), None) => {
317                // Handle signature case
318                Ok(MinaBaseControlStableV2::Signature(signature.parse()?))
319            }
320            (None, Some(proof)) => {
321                // Handle proof case
322                let proof = PicklesProofProofsVerifiedMaxStableV2::deserialize(
323                    serde_json::Value::String(proof),
324                )?;
325                Ok(MinaBaseControlStableV2::Proof(Box::new(proof)))
326            }
327            _ => Err(ConversionError::Custom(
328                "Either signature or proof must be provided, but not both".into(),
329            )),
330        }
331    }
332}
333
334#[derive(GraphQLObject, Debug)]
335pub struct GraphQLAccountUpdateBody {
336    pub public_key: String,
337    pub token_id: String,
338    pub use_full_commitment: bool,
339    pub increment_nonce: bool,
340    pub update: GraphQLAccountUpdateUpdate,
341    pub balance_change: GraphQLBalanceChange,
342    pub events: Vec<Vec<String>>,
343    pub actions: Vec<Vec<String>>,
344    pub call_data: String,
345    pub call_depth: i32,
346    pub preconditions: GraphQLPreconditions,
347    pub may_use_token: GraphQLMayUseToken,
348    pub authorization_kind: GraphQLAuthorizationKind,
349    pub implicit_account_creation_fee: bool,
350}
351
352#[derive(GraphQLInputObject, Debug)]
353pub struct InputGraphQLAccountUpdateBody {
354    pub public_key: String,
355    pub token_id: String,
356    pub use_full_commitment: bool,
357    pub increment_nonce: bool,
358    pub update: InputGraphQLAccountUpdateUpdate,
359    pub balance_change: InputGraphQLBalanceChange,
360    pub events: Vec<Vec<String>>,
361    pub actions: Vec<Vec<String>>,
362    pub call_data: String,
363    pub call_depth: i32,
364    pub preconditions: InputGraphQLPreconditions,
365    pub may_use_token: InputGraphQLMayUseToken,
366    pub authorization_kind: InputGraphQLAuthorizationKind,
367    pub implicit_account_creation_fee: bool,
368}
369
370#[derive(GraphQLObject, Debug)]
371pub struct GraphQLAuthorizationKind {
372    pub is_signed: bool,
373    pub is_proved: bool,
374    pub verification_key_hash: Option<String>,
375}
376
377#[derive(GraphQLInputObject, Debug)]
378pub struct InputGraphQLAuthorizationKind {
379    pub is_signed: bool,
380    pub is_proved: bool,
381    pub verification_key_hash: Option<String>,
382}
383
384impl From<MinaBaseAccountUpdateAuthorizationKindStableV1> for GraphQLAuthorizationKind {
385    fn from(value: MinaBaseAccountUpdateAuthorizationKindStableV1) -> Self {
386        match value {
387            MinaBaseAccountUpdateAuthorizationKindStableV1::Signature => GraphQLAuthorizationKind {
388                is_signed: true,
389                is_proved: false,
390                verification_key_hash: None,
391            },
392            MinaBaseAccountUpdateAuthorizationKindStableV1::Proof(proof) => {
393                GraphQLAuthorizationKind {
394                    is_signed: false,
395                    is_proved: true,
396                    verification_key_hash: Some(proof.to_decimal()),
397                }
398            }
399            MinaBaseAccountUpdateAuthorizationKindStableV1::NoneGiven => GraphQLAuthorizationKind {
400                is_signed: false,
401                is_proved: false,
402                verification_key_hash: None,
403            },
404        }
405    }
406}
407
408impl TryFrom<InputGraphQLAuthorizationKind> for MinaBaseAccountUpdateAuthorizationKindStableV1 {
409    type Error = ConversionError;
410    fn try_from(value: InputGraphQLAuthorizationKind) -> Result<Self, Self::Error> {
411        if value.is_signed {
412            return Ok(MinaBaseAccountUpdateAuthorizationKindStableV1::Signature);
413        }
414
415        if value.is_proved {
416            match &value.verification_key_hash {
417                Some(vk_hash) => {
418                    let big_int = BigInt::from_decimal(vk_hash)?;
419                    return Ok(MinaBaseAccountUpdateAuthorizationKindStableV1::Proof(
420                        big_int,
421                    ));
422                }
423                None => {
424                    return Err(ConversionError::MissingField(
425                        "verification_key_hash".to_string(),
426                    ));
427                }
428            }
429        }
430
431        Ok(MinaBaseAccountUpdateAuthorizationKindStableV1::NoneGiven)
432    }
433}
434
435#[derive(GraphQLObject, Debug)]
436pub struct GraphQLMayUseToken {
437    pub parents_own_token: bool,
438    pub inherit_from_parent: bool,
439}
440
441#[derive(GraphQLInputObject, Debug)]
442pub struct InputGraphQLMayUseToken {
443    pub parents_own_token: bool,
444    pub inherit_from_parent: bool,
445}
446
447impl From<MinaBaseAccountUpdateMayUseTokenStableV1> for GraphQLMayUseToken {
448    fn from(value: MinaBaseAccountUpdateMayUseTokenStableV1) -> Self {
449        match value {
450            MinaBaseAccountUpdateMayUseTokenStableV1::ParentsOwnToken => GraphQLMayUseToken {
451                parents_own_token: true,
452                inherit_from_parent: false,
453            },
454            MinaBaseAccountUpdateMayUseTokenStableV1::InheritFromParent => GraphQLMayUseToken {
455                parents_own_token: false,
456                inherit_from_parent: true,
457            },
458            MinaBaseAccountUpdateMayUseTokenStableV1::No => GraphQLMayUseToken {
459                parents_own_token: false,
460                inherit_from_parent: false,
461            },
462        }
463    }
464}
465
466impl From<InputGraphQLMayUseToken> for MinaBaseAccountUpdateMayUseTokenStableV1 {
467    fn from(value: InputGraphQLMayUseToken) -> Self {
468        if value.parents_own_token {
469            MinaBaseAccountUpdateMayUseTokenStableV1::ParentsOwnToken
470        } else if value.inherit_from_parent {
471            MinaBaseAccountUpdateMayUseTokenStableV1::InheritFromParent
472        } else {
473            MinaBaseAccountUpdateMayUseTokenStableV1::No
474        }
475    }
476}
477
478#[derive(GraphQLObject, Debug)]
479pub struct GraphQLEvent {
480    pub event: String,
481    pub data: String,
482}
483
484#[derive(GraphQLInputObject, Debug)]
485pub struct InputGraphQLEvent {
486    pub event: String,
487    pub data: String,
488}
489
490#[derive(GraphQLObject, Debug)]
491pub struct GraphQLAction {
492    pub action: String,
493    pub data: String,
494}
495
496#[derive(GraphQLInputObject, Debug)]
497pub struct InputGraphQLAction {
498    pub action: String,
499    pub data: String,
500}
501
502#[derive(GraphQLObject, Debug)]
503pub struct GraphQLPreconditions {
504    pub network: GraphQLPreconditionsNetwork,
505    pub account: GraphQLPreconditionsAccount,
506    pub valid_while: Option<GraphQLPreconditionsNetworkBounds>,
507}
508
509#[derive(GraphQLInputObject, Debug)]
510pub struct InputGraphQLPreconditions {
511    pub network: InputGraphQLPreconditionsNetwork,
512    pub account: InputGraphQLPreconditionsAccount,
513    pub valid_while: Option<InputGraphQLPreconditionsNetworkBounds>,
514}
515
516#[derive(GraphQLObject, Debug)]
517pub struct GraphQLPreconditionsAccount {
518    pub balance: Option<GraphQLPreconditionsNetworkBounds>,
519    pub nonce: Option<GraphQLPreconditionsNetworkBounds>,
520    pub receipt_chain_hash: Option<String>,
521    pub delegate: Option<String>,
522    pub state: Vec<Option<String>>,
523    pub action_state: Option<String>,
524    pub proved_state: Option<bool>,
525    pub is_new: Option<bool>,
526}
527
528#[derive(GraphQLInputObject, Debug)]
529pub struct InputGraphQLPreconditionsAccount {
530    pub balance: Option<InputGraphQLPreconditionsNetworkBounds>,
531    pub nonce: Option<InputGraphQLPreconditionsNetworkBounds>,
532    pub receipt_chain_hash: Option<String>,
533    pub delegate: Option<String>,
534    pub state: Vec<Option<String>>,
535    pub action_state: Option<String>,
536    pub proved_state: Option<bool>,
537    pub is_new: Option<bool>,
538}
539
540impl From<MinaBaseAccountUpdateAccountPreconditionStableV1> for GraphQLPreconditionsAccount {
541    fn from(value: MinaBaseAccountUpdateAccountPreconditionStableV1) -> Self {
542        Self {
543            balance: if let MinaBaseZkappPreconditionAccountStableV2Balance::Check(v) =
544                value.0.balance
545            {
546                Some(GraphQLPreconditionsNetworkBounds {
547                    upper: v.upper.as_u64().to_string(),
548                    lower: v.lower.as_u64().to_string(),
549                })
550            } else {
551                None
552            },
553            nonce: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(v) =
554                value.0.nonce
555            {
556                Some(GraphQLPreconditionsNetworkBounds {
557                    upper: v.upper.as_u32().to_string(),
558                    lower: v.lower.as_u32().to_string(),
559                })
560            } else {
561                None
562            },
563            receipt_chain_hash:
564                if let MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash::Check(v) =
565                    value.0.receipt_chain_hash
566                {
567                    Some(v.to_decimal())
568                } else {
569                    None
570                },
571            delegate: if let MinaBaseZkappPreconditionAccountStableV2Delegate::Check(v) =
572                value.0.delegate
573            {
574                Some(v.to_string())
575            } else {
576                None
577            },
578            state: value
579                .0
580                .state
581                .clone()
582                .iter()
583                .map(|v| {
584                    if let MinaBaseZkappPreconditionAccountStableV2StateA::Check(state_value) = v {
585                        Some(state_value.to_decimal())
586                    } else {
587                        None
588                    }
589                })
590                .collect(),
591            action_state: if let MinaBaseZkappPreconditionAccountStableV2StateA::Check(value) =
592                value.0.action_state
593            {
594                Some(value.to_decimal())
595            } else {
596                None
597            },
598            proved_state: if let MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(v) =
599                value.0.proved_state
600            {
601                Some(v)
602            } else {
603                None
604            },
605            is_new: if let MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(v) =
606                value.0.is_new
607            {
608                Some(v)
609            } else {
610                None
611            },
612        }
613    }
614}
615
616impl TryFrom<InputGraphQLPreconditionsAccount>
617    for MinaBaseAccountUpdateAccountPreconditionStableV1
618{
619    type Error = ConversionError;
620    fn try_from(value: InputGraphQLPreconditionsAccount) -> Result<Self, Self::Error> {
621        let state: Result<Vec<_>, _> = value
622            .state
623            .iter()
624            .map(|v| {
625                if let Some(state) = v {
626                    BigInt::from_decimal(state)
627                        .map(MinaBaseZkappPreconditionAccountStableV2StateA::Check)
628                } else {
629                    Ok(MinaBaseZkappPreconditionAccountStableV2StateA::Ignore)
630                }
631            })
632            .collect();
633
634        let state = state?;
635        Ok(Self(MinaBaseZkappPreconditionAccountStableV2 {
636            balance: if let Some(balance) = value.balance {
637                MinaBaseZkappPreconditionAccountStableV2Balance::Check(
638                    MinaBaseZkappPreconditionAccountStableV2BalanceA {
639                        lower: CurrencyBalanceStableV1(CurrencyAmountStableV1(
640                            balance.lower.parse::<u64>()?.into(),
641                        )),
642                        upper: CurrencyBalanceStableV1(CurrencyAmountStableV1(
643                            balance.upper.parse::<u64>()?.into(),
644                        )),
645                    },
646                )
647            } else {
648                MinaBaseZkappPreconditionAccountStableV2Balance::Ignore
649            },
650            nonce: if let Some(nonce) = value.nonce {
651                MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
652                    MinaBaseZkappPreconditionProtocolStateStableV1LengthA {
653                        lower: (nonce.lower.parse::<u32>()?).into(),
654                        upper: (nonce.upper.parse::<u32>()?).into(),
655                    },
656                )
657            } else {
658                MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore
659            },
660            receipt_chain_hash: if let Some(receipt_chain_hash) = value.receipt_chain_hash {
661                MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash::Check(
662                    MinaBaseReceiptChainHashStableV1(BigInt::from_decimal(&receipt_chain_hash)?),
663                )
664            } else {
665                MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash::Ignore
666            },
667            delegate: if let Some(delegate) = value.delegate {
668                MinaBaseZkappPreconditionAccountStableV2Delegate::Check(
669                    AccountPublicKey::from_str(&delegate)?.into(),
670                )
671            } else {
672                MinaBaseZkappPreconditionAccountStableV2Delegate::Ignore
673            },
674            state: PaddedSeq(
675                state
676                    .try_into()
677                    .map_err(|_| ConversionError::InvalidLength)?,
678            ),
679            action_state: if let Some(action_state) = value.action_state {
680                MinaBaseZkappPreconditionAccountStableV2StateA::Check(BigInt::from_decimal(
681                    &action_state,
682                )?)
683            } else {
684                MinaBaseZkappPreconditionAccountStableV2StateA::Ignore
685            },
686            proved_state: if let Some(proved_state) = value.proved_state {
687                MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(proved_state)
688            } else {
689                MinaBaseZkappPreconditionAccountStableV2ProvedState::Ignore
690            },
691            is_new: if let Some(is_new) = value.is_new {
692                MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(is_new)
693            } else {
694                MinaBaseZkappPreconditionAccountStableV2ProvedState::Ignore
695            },
696        }))
697    }
698}
699#[derive(GraphQLObject, Debug)]
700pub struct GraphQLPreconditionsNetwork {
701    pub snarked_ledger_hash: Option<String>,
702    pub blockchain_length: Option<GraphQLPreconditionsNetworkBounds>,
703    pub min_window_density: Option<GraphQLPreconditionsNetworkBounds>,
704    pub total_currency: Option<GraphQLPreconditionsNetworkBounds>,
705    pub global_slot_since_genesis: Option<GraphQLPreconditionsNetworkBounds>,
706    pub staking_epoch_data: GraphQLPreconditionsNetworkEpochData,
707    pub next_epoch_data: GraphQLPreconditionsNetworkEpochData,
708}
709
710#[derive(GraphQLInputObject, Debug)]
711pub struct InputGraphQLPreconditionsNetwork {
712    pub snarked_ledger_hash: Option<String>,
713    pub blockchain_length: Option<InputGraphQLPreconditionsNetworkBounds>,
714    pub min_window_density: Option<InputGraphQLPreconditionsNetworkBounds>,
715    pub total_currency: Option<InputGraphQLPreconditionsNetworkBounds>,
716    pub global_slot_since_genesis: Option<InputGraphQLPreconditionsNetworkBounds>,
717    pub staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData,
718    pub next_epoch_data: InputGraphQLPreconditionsNetworkEpochData,
719}
720
721#[derive(GraphQLObject, Debug)]
722pub struct GraphQLPreconditionsNetworkEpochData {
723    pub ledger: GraphQLPreconditionsNetworkLedger,
724    pub seed: Option<String>,
725    pub start_checkpoint: Option<String>,
726    pub lock_checkpoint: Option<String>,
727    pub epoch_length: Option<GraphQLPreconditionsNetworkBounds>,
728}
729
730#[derive(GraphQLInputObject, Debug)]
731pub struct InputGraphQLPreconditionsNetworkEpochData {
732    pub ledger: InputGraphQLPreconditionsNetworkLedger,
733    pub seed: Option<String>,
734    pub start_checkpoint: Option<String>,
735    pub lock_checkpoint: Option<String>,
736    pub epoch_length: Option<InputGraphQLPreconditionsNetworkBounds>,
737}
738
739#[derive(GraphQLObject, Debug)]
740pub struct GraphQLPreconditionsNetworkLedger {
741    pub hash: Option<String>,
742    pub total_currency: Option<GraphQLPreconditionsNetworkBounds>,
743}
744
745#[derive(GraphQLInputObject, Debug)]
746pub struct InputGraphQLPreconditionsNetworkLedger {
747    pub hash: Option<String>,
748    pub total_currency: Option<InputGraphQLPreconditionsNetworkBounds>,
749}
750#[derive(GraphQLObject, Debug)]
751pub struct GraphQLPreconditionsNetworkBounds {
752    pub upper: String,
753    pub lower: String,
754}
755
756#[derive(GraphQLInputObject, Debug)]
757pub struct InputGraphQLPreconditionsNetworkBounds {
758    pub upper: String,
759    pub lower: String,
760}
761
762impl From<MinaBaseZkappPreconditionProtocolStateEpochDataStableV1>
763    for GraphQLPreconditionsNetworkEpochData
764{
765    fn from(value: MinaBaseZkappPreconditionProtocolStateEpochDataStableV1) -> Self {
766        Self {
767            ledger: GraphQLPreconditionsNetworkLedger::from(value.ledger),
768            seed: if let MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed::Check(v) = value.seed {
769                Some(v.to_string())
770            } else {
771                None
772            },
773            start_checkpoint: if let MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(v) = value.start_checkpoint {
774                Some(v.to_string())
775            } else {
776                None
777            },
778            lock_checkpoint: if let MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(v) = value.lock_checkpoint {
779                Some(v.to_string())
780            } else {
781                None
782            },
783            epoch_length: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(v) = value.epoch_length {
784                Some(GraphQLPreconditionsNetworkBounds {
785                    upper: v.upper.as_u32().to_string(),
786                    lower: v.lower.as_u32().to_string(),
787                })
788            } else {
789                None
790            },
791        }
792    }
793}
794
795impl TryFrom<InputGraphQLPreconditionsNetworkEpochData>
796    for MinaBaseZkappPreconditionProtocolStateEpochDataStableV1
797{
798    type Error = ConversionError;
799    fn try_from(value: InputGraphQLPreconditionsNetworkEpochData) -> Result<Self, Self::Error> {
800        Ok(Self {
801            ledger: value.ledger.try_into()?,
802            seed: if let Some(seed) = value.seed {
803                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed::Check(
804                    seed.parse()?,
805                )
806            } else {
807                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed::Ignore
808            },
809            start_checkpoint: if let Some(start_checkpoint) = value.start_checkpoint {
810                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(
811                    start_checkpoint.parse()?,
812                )
813            } else {
814                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Ignore
815            },
816            lock_checkpoint: if let Some(lock_checkpoint) = value.lock_checkpoint {
817                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(
818                    lock_checkpoint.parse()?,
819                )
820            } else {
821                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Ignore
822            },
823            epoch_length: if let Some(epoch_length) = value.epoch_length {
824                MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
825                    MinaBaseZkappPreconditionProtocolStateStableV1LengthA {
826                        lower: (epoch_length.lower.parse::<u32>()?).into(),
827                        upper: (epoch_length.upper.parse::<u32>()?).into(),
828                    },
829                )
830            } else {
831                MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore
832            },
833        })
834    }
835}
836impl From<MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger>
837    for GraphQLPreconditionsNetworkLedger
838{
839    fn from(value: MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger) -> Self {
840        Self {
841            hash: if let MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(v) =
842                value.hash
843            {
844                Some(v.to_string())
845            } else {
846                None
847            },
848            total_currency: if let MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(v) =
849                value.total_currency
850            {
851                Some(GraphQLPreconditionsNetworkBounds {
852                    upper: v.upper.as_u64().to_string(),
853                    lower: v.lower.as_u64().to_string(),
854                })
855            } else {
856                None
857            },
858        }
859    }
860}
861
862impl TryFrom<InputGraphQLPreconditionsNetworkLedger>
863    for MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger
864{
865    type Error = ConversionError;
866    fn try_from(value: InputGraphQLPreconditionsNetworkLedger) -> Result<Self, Self::Error> {
867        Ok(Self {
868            hash: if let Some(hash) = value.hash {
869                MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(
870                    hash.parse()?,
871                )
872            } else {
873                MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Ignore
874            },
875            total_currency: if let Some(total_currency) = value.total_currency {
876                MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(
877                    MinaBaseZkappPreconditionProtocolStateStableV1AmountA {
878                        lower: CurrencyAmountStableV1(
879                            (total_currency.lower.parse::<u64>()?).into(),
880                        ),
881                        upper: CurrencyAmountStableV1(
882                            (total_currency.upper.parse::<u64>()?).into(),
883                        ),
884                    },
885                )
886            } else {
887                MinaBaseZkappPreconditionProtocolStateStableV1Amount::Ignore
888            },
889        })
890    }
891}
892
893impl From<MinaBaseZkappPreconditionProtocolStateStableV1> for GraphQLPreconditionsNetwork {
894    fn from(value: MinaBaseZkappPreconditionProtocolStateStableV1) -> Self {
895        Self {
896            snarked_ledger_hash:
897                if let MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(v) =
898                    value.snarked_ledger_hash
899                {
900                    Some(v.to_string())
901                } else {
902                    None
903                },
904            blockchain_length: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
905                v,
906            ) = value.blockchain_length
907            {
908                Some(GraphQLPreconditionsNetworkBounds {
909                    upper: v.upper.as_u32().to_string(),
910                    lower: v.lower.as_u32().to_string(),
911                })
912            } else {
913                None
914            },
915            min_window_density: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
916                v,
917            ) = value.min_window_density
918            {
919                Some(GraphQLPreconditionsNetworkBounds {
920                    upper: v.upper.as_u32().to_string(),
921                    lower: v.lower.as_u32().to_string(),
922                })
923            } else {
924                None
925            },
926            total_currency: if let MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(v) =
927                value.total_currency
928            {
929                Some(GraphQLPreconditionsNetworkBounds {
930                    upper: v.upper.as_u64().to_string(),
931                    lower: v.lower.as_u64().to_string(),
932                })
933            } else {
934                None
935            },
936            global_slot_since_genesis:
937                if let MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(v) =
938                    value.global_slot_since_genesis
939                {
940                    Some(GraphQLPreconditionsNetworkBounds {
941                        upper: v.upper.as_u32().to_string(),
942                        lower: v.lower.as_u32().to_string(),
943                    })
944                } else {
945                    None
946                },
947            staking_epoch_data: GraphQLPreconditionsNetworkEpochData::from(
948                value.staking_epoch_data,
949            ),
950            next_epoch_data: GraphQLPreconditionsNetworkEpochData::from(value.next_epoch_data),
951        }
952    }
953}
954
955impl TryFrom<InputGraphQLPreconditionsNetwork> for MinaBaseZkappPreconditionProtocolStateStableV1 {
956    type Error = ConversionError;
957    fn try_from(value: InputGraphQLPreconditionsNetwork) -> Result<Self, Self::Error> {
958        Ok(Self {
959            snarked_ledger_hash: if let Some(snarked_ledger_hash) = value.snarked_ledger_hash {
960                MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(
961                    snarked_ledger_hash.parse()?,
962                )
963            } else {
964                MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Ignore
965            },
966            blockchain_length: if let Some(blockchain_length) = value.blockchain_length {
967                MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
968                    MinaBaseZkappPreconditionProtocolStateStableV1LengthA {
969                        lower: (blockchain_length.lower.parse::<u32>()?).into(),
970                        upper: (blockchain_length.upper.parse::<u32>()?).into(),
971                    },
972                )
973            } else {
974                MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore
975            },
976            min_window_density: if let Some(min_window_density) = value.min_window_density {
977                MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
978                    MinaBaseZkappPreconditionProtocolStateStableV1LengthA {
979                        lower: (min_window_density.lower.parse::<u32>()?).into(),
980                        upper: (min_window_density.upper.parse::<u32>()?).into(),
981                    },
982                )
983            } else {
984                MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore
985            },
986            total_currency: if let Some(total_currency) = value.total_currency {
987                MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(
988                    MinaBaseZkappPreconditionProtocolStateStableV1AmountA {
989                        lower: CurrencyAmountStableV1(
990                            (total_currency.lower.parse::<u64>()?).into(),
991                        ),
992                        upper: CurrencyAmountStableV1(
993                            (total_currency.upper.parse::<u64>()?).into(),
994                        ),
995                    },
996                )
997            } else {
998                MinaBaseZkappPreconditionProtocolStateStableV1Amount::Ignore
999            },
1000            global_slot_since_genesis: if let Some(global_slot_since_genesis) =
1001                value.global_slot_since_genesis
1002            {
1003                MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(
1004                    MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlotA {
1005                        lower: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1006                            (global_slot_since_genesis.lower.parse::<u32>()?).into(),
1007                        ),
1008                        upper: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1009                            (global_slot_since_genesis.upper.parse::<u32>()?).into(),
1010                        ),
1011                    },
1012                )
1013            } else {
1014                MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Ignore
1015            },
1016            staking_epoch_data: value.staking_epoch_data.try_into()?,
1017            next_epoch_data: value.next_epoch_data.try_into()?,
1018        })
1019    }
1020}
1021
1022#[derive(GraphQLObject, Debug)]
1023pub struct GraphQLAccountUpdateUpdate {
1024    pub app_state: Vec<Option<String>>,
1025    pub delegate: Option<String>,
1026    pub verification_key: Option<GraphQLVerificationKey>,
1027    pub permissions: Option<GraphQLAccountUpdateUpdatePermissions>,
1028    pub zkapp_uri: Option<String>,
1029    pub token_symbol: Option<String>,
1030    pub timing: Option<GraphQLTiming>,
1031    pub voting_for: Option<String>,
1032}
1033
1034#[derive(GraphQLObject, Debug)]
1035pub struct GraphQLVerificationKey {
1036    pub data: String,
1037    pub hash: String,
1038}
1039
1040#[derive(GraphQLInputObject, Debug)]
1041pub struct InputGraphQLAccountUpdateUpdate {
1042    pub app_state: Vec<Option<String>>,
1043    pub delegate: Option<String>,
1044    pub verification_key: Option<InputGraphQLVerificationKey>,
1045    pub permissions: Option<InputGraphQLAccountUpdateUpdatePermissions>,
1046    pub zkapp_uri: Option<String>,
1047    pub token_symbol: Option<String>,
1048    pub timing: Option<InputGraphQLTiming>,
1049    pub voting_for: Option<String>,
1050}
1051
1052#[derive(GraphQLInputObject, Debug)]
1053pub struct InputGraphQLVerificationKey {
1054    pub data: String,
1055    pub hash: String,
1056}
1057
1058#[derive(GraphQLObject, Debug)]
1059pub struct GraphQLAccountUpdateUpdatePermissions {
1060    pub edit_state: String,
1061    pub access: String,
1062    pub send: String,
1063    pub receive: String,
1064    pub set_delegate: String,
1065    pub set_permissions: String,
1066    pub set_verification_key: GraphQLSetVerificationKeyPermissions,
1067    pub set_zkapp_uri: String,
1068    pub edit_action_state: String,
1069    pub set_token_symbol: String,
1070    pub set_timing: String,
1071    pub set_voting_for: String,
1072    pub increment_nonce: String,
1073}
1074
1075#[derive(GraphQLObject, Debug)]
1076pub struct GraphQLSetVerificationKeyPermissions {
1077    pub auth: String,
1078    pub txn_version: String,
1079}
1080
1081#[derive(GraphQLInputObject, Debug)]
1082pub struct InputGraphQLAccountUpdateUpdatePermissions {
1083    pub edit_state: String,
1084    pub access: String,
1085    pub send: String,
1086    pub receive: String,
1087    pub set_delegate: String,
1088    pub set_permissions: String,
1089    pub set_verification_key: InputGraphQLSetVerificationKeyPermissions,
1090    pub set_zkapp_uri: String,
1091    pub edit_action_state: String,
1092    pub set_token_symbol: String,
1093    pub set_timing: String,
1094    pub set_voting_for: String,
1095    pub increment_nonce: String,
1096}
1097
1098#[derive(GraphQLInputObject, Debug)]
1099pub struct InputGraphQLSetVerificationKeyPermissions {
1100    pub auth: String,
1101    pub txn_version: String,
1102}
1103
1104impl From<MinaBasePermissionsStableV2> for GraphQLAccountUpdateUpdatePermissions {
1105    fn from(value: MinaBasePermissionsStableV2) -> Self {
1106        Self {
1107            edit_state: value.edit_state.to_string(),
1108            access: value.access.to_string(),
1109            send: value.send.to_string(),
1110            receive: value.receive.to_string(),
1111            set_delegate: value.set_delegate.to_string(),
1112            set_permissions: value.set_permissions.to_string(),
1113            set_verification_key: GraphQLSetVerificationKeyPermissions {
1114                auth: value.set_verification_key.0.to_string(),
1115                txn_version: value.set_verification_key.1.as_u32().to_string(),
1116            },
1117            set_zkapp_uri: value.set_zkapp_uri.to_string(),
1118            edit_action_state: value.edit_action_state.to_string(),
1119            set_token_symbol: value.set_token_symbol.to_string(),
1120            set_timing: value.set_timing.to_string(),
1121            set_voting_for: value.set_voting_for.to_string(),
1122            increment_nonce: value.increment_nonce.to_string(),
1123        }
1124    }
1125}
1126
1127impl TryFrom<InputGraphQLAccountUpdateUpdatePermissions> for MinaBasePermissionsStableV2 {
1128    type Error = ConversionError;
1129    fn try_from(value: InputGraphQLAccountUpdateUpdatePermissions) -> Result<Self, Self::Error> {
1130        Ok(Self {
1131            edit_state: value.edit_state.parse()?,
1132            access: value.access.parse()?,
1133            send: value.send.parse()?,
1134            receive: value.receive.parse()?,
1135            set_delegate: value.set_delegate.parse()?,
1136            set_permissions: value.set_permissions.parse()?,
1137            set_verification_key: (
1138                value.set_verification_key.auth.parse()?,
1139                value
1140                    .set_verification_key
1141                    .txn_version
1142                    .parse::<u32>()?
1143                    .into(),
1144            ),
1145            set_zkapp_uri: value.set_zkapp_uri.parse()?,
1146            edit_action_state: value.edit_action_state.parse()?,
1147            set_token_symbol: value.set_token_symbol.parse()?,
1148            set_timing: value.set_timing.parse()?,
1149            set_voting_for: value.set_voting_for.parse()?,
1150            increment_nonce: value.increment_nonce.parse()?,
1151        })
1152    }
1153}
1154
1155#[derive(GraphQLObject, Debug)]
1156pub struct GraphQLBalanceChange {
1157    pub magnitude: String,
1158    pub sgn: String,
1159}
1160
1161#[derive(GraphQLInputObject, Debug)]
1162pub struct InputGraphQLBalanceChange {
1163    pub magnitude: String,
1164    pub sgn: String,
1165}
1166
1167#[derive(GraphQLObject, Debug)]
1168pub struct GraphQLFailureReason {
1169    pub index: String,
1170    pub failures: Vec<String>,
1171}
1172
1173impl From<MinaStateBlockchainStateValueStableV2SignedAmount> for GraphQLBalanceChange {
1174    fn from(value: MinaStateBlockchainStateValueStableV2SignedAmount) -> Self {
1175        Self {
1176            magnitude: value.magnitude.as_u64().to_string(),
1177            sgn: value.sgn.to_string(),
1178        }
1179    }
1180}
1181
1182impl TryFrom<InputGraphQLBalanceChange> for MinaStateBlockchainStateValueStableV2SignedAmount {
1183    type Error = ConversionError;
1184    fn try_from(value: InputGraphQLBalanceChange) -> Result<Self, Self::Error> {
1185        Ok(Self {
1186            magnitude: CurrencyAmountStableV1(value.magnitude.parse::<u64>()?.into()),
1187            sgn: value
1188                .sgn
1189                .parse()
1190                .map_err(|_| ConversionError::WrongVariant)?,
1191        })
1192    }
1193}
1194
1195impl From<MinaBaseAccountUpdatePreconditionsStableV1> for GraphQLPreconditions {
1196    fn from(value: MinaBaseAccountUpdatePreconditionsStableV1) -> Self {
1197        Self {
1198            network: GraphQLPreconditionsNetwork::from(value.network),
1199            account: GraphQLPreconditionsAccount::from(value.account),
1200            valid_while: if let MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(v) =
1201                value.valid_while
1202            {
1203                Some(GraphQLPreconditionsNetworkBounds {
1204                    upper: v.upper.as_u32().to_string(),
1205                    lower: v.lower.as_u32().to_string(),
1206                })
1207            } else {
1208                None
1209            },
1210        }
1211    }
1212}
1213
1214impl TryFrom<InputGraphQLPreconditions> for MinaBaseAccountUpdatePreconditionsStableV1 {
1215    type Error = ConversionError;
1216    fn try_from(value: InputGraphQLPreconditions) -> Result<Self, Self::Error> {
1217        Ok(Self {
1218            network: value.network.try_into()?,
1219            account: value.account.try_into()?,
1220            valid_while: if let Some(v) = value.valid_while {
1221                MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(
1222                    MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlotA {
1223                        upper: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1224                            (v.upper.parse::<u32>()?).into(),
1225                        ),
1226                        lower: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1227                            (v.lower.parse::<u32>()?).into(),
1228                        ),
1229                    },
1230                )
1231            } else {
1232                MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Ignore
1233            },
1234        })
1235    }
1236}
1237
1238impl TryFrom<MinaBaseVerificationKeyWireStableV1> for GraphQLVerificationKey {
1239    type Error = ConversionError;
1240
1241    fn try_from(value: MinaBaseVerificationKeyWireStableV1) -> Result<Self, Self::Error> {
1242        Ok(Self {
1243            data: value.to_base64()?,
1244            hash: VerificationKey::try_from(&value)
1245                .map_err(|_| ConversionError::InvalidBigInt)?
1246                .hash()
1247                .to_decimal(),
1248        })
1249    }
1250}
1251
1252impl TryFrom<InputGraphQLVerificationKey> for MinaBaseVerificationKeyWireStableV1 {
1253    type Error = ConversionError;
1254
1255    fn try_from(value: InputGraphQLVerificationKey) -> Result<Self, Self::Error> {
1256        Ok(Self::from_base64(&value.data)?)
1257    }
1258}
1259
1260impl TryFrom<MinaBaseAccountUpdateUpdateStableV1> for GraphQLAccountUpdateUpdate {
1261    type Error = ConversionError;
1262
1263    fn try_from(value: MinaBaseAccountUpdateUpdateStableV1) -> Result<Self, Self::Error> {
1264        Ok(Self {
1265            app_state: value
1266                .app_state
1267                .0
1268                .into_iter()
1269                .map(|v| {
1270                    if let MinaBaseAccountUpdateUpdateStableV1AppStateA::Set(value) = v {
1271                        Some(value.to_decimal())
1272                    } else {
1273                        None
1274                    }
1275                })
1276                .collect(),
1277            delegate: if let MinaBaseAccountUpdateUpdateStableV1Delegate::Set(v) = value.delegate {
1278                Some(v.to_string())
1279            } else {
1280                None
1281            },
1282            verification_key: if let MinaBaseAccountUpdateUpdateStableV1VerificationKey::Set(v) =
1283                value.verification_key
1284            {
1285                Some(GraphQLVerificationKey::try_from(*v)?)
1286            } else {
1287                None
1288            },
1289            permissions: if let MinaBaseAccountUpdateUpdateStableV1Permissions::Set(v) =
1290                value.permissions
1291            {
1292                Some(GraphQLAccountUpdateUpdatePermissions::from(*v))
1293            } else {
1294                None
1295            },
1296            zkapp_uri: if let MinaBaseAccountUpdateUpdateStableV1ZkappUri::Set(v) = value.zkapp_uri
1297            {
1298                Some(v.to_string())
1299            } else {
1300                None
1301            },
1302            token_symbol: if let MinaBaseAccountUpdateUpdateStableV1TokenSymbol::Set(v) =
1303                value.token_symbol
1304            {
1305                Some(v.to_string())
1306            } else {
1307                None
1308            },
1309            timing: if let MinaBaseAccountUpdateUpdateStableV1Timing::Set(v) = value.timing {
1310                Some(GraphQLTiming::from(*v))
1311            } else {
1312                None
1313            },
1314            voting_for: if let MinaBaseAccountUpdateUpdateStableV1VotingFor::Set(v) =
1315                value.voting_for
1316            {
1317                Some(v.to_string())
1318            } else {
1319                None
1320            },
1321        })
1322    }
1323}
1324
1325impl TryFrom<InputGraphQLAccountUpdateUpdate> for MinaBaseAccountUpdateUpdateStableV1 {
1326    type Error = ConversionError;
1327    fn try_from(value: InputGraphQLAccountUpdateUpdate) -> Result<Self, Self::Error> {
1328        let app_state: Vec<_> = value
1329            .app_state
1330            .iter()
1331            .map(|v| {
1332                if let Some(v) = v {
1333                    Ok(MinaBaseAccountUpdateUpdateStableV1AppStateA::Set(
1334                        BigInt::from_decimal(v)?,
1335                    ))
1336                } else {
1337                    Ok(MinaBaseAccountUpdateUpdateStableV1AppStateA::Keep)
1338                }
1339            })
1340            .collect::<Result<Vec<_>, ConversionError>>()?;
1341        Ok(Self {
1342            app_state: PaddedSeq(
1343                app_state
1344                    .try_into()
1345                    .map_err(|_| ConversionError::InvalidLength)?,
1346            ),
1347            delegate: if let Some(delegate) = value.delegate {
1348                MinaBaseAccountUpdateUpdateStableV1Delegate::Set(
1349                    AccountPublicKey::from_str(&delegate)?.into(),
1350                )
1351            } else {
1352                MinaBaseAccountUpdateUpdateStableV1Delegate::Keep
1353            },
1354            verification_key: if let Some(vk) = value.verification_key {
1355                MinaBaseAccountUpdateUpdateStableV1VerificationKey::Set(Box::new(
1356                    MinaBaseVerificationKeyWireStableV1::try_from(vk)?,
1357                ))
1358            } else {
1359                MinaBaseAccountUpdateUpdateStableV1VerificationKey::Keep
1360            },
1361            permissions: if let Some(permissions) = value.permissions {
1362                MinaBaseAccountUpdateUpdateStableV1Permissions::Set(Box::new(
1363                    MinaBasePermissionsStableV2::try_from(permissions)?,
1364                ))
1365            } else {
1366                MinaBaseAccountUpdateUpdateStableV1Permissions::Keep
1367            },
1368            zkapp_uri: if let Some(zkapp_uri) = value.zkapp_uri {
1369                MinaBaseAccountUpdateUpdateStableV1ZkappUri::Set(ZkAppUri::from(zkapp_uri.as_str()))
1370            } else {
1371                MinaBaseAccountUpdateUpdateStableV1ZkappUri::Keep
1372            },
1373            token_symbol: if let Some(token_symbol) = value.token_symbol {
1374                MinaBaseAccountUpdateUpdateStableV1TokenSymbol::Set(TokenSymbol::from(
1375                    token_symbol.as_str(),
1376                ))
1377            } else {
1378                MinaBaseAccountUpdateUpdateStableV1TokenSymbol::Keep
1379            },
1380            timing: if let Some(timing) = value.timing {
1381                MinaBaseAccountUpdateUpdateStableV1Timing::Set(Box::new(
1382                    MinaBaseAccountUpdateUpdateTimingInfoStableV1::try_from(timing)?,
1383                ))
1384            } else {
1385                MinaBaseAccountUpdateUpdateStableV1Timing::Keep
1386            },
1387            voting_for: if let Some(voting_for) = value.voting_for {
1388                MinaBaseAccountUpdateUpdateStableV1VotingFor::Set(StateHash::from_str(&voting_for)?)
1389            } else {
1390                MinaBaseAccountUpdateUpdateStableV1VotingFor::Keep
1391            },
1392        })
1393    }
1394}
1395
1396impl From<MinaBaseAccountUpdateFeePayerStableV1> for GraphQLFeePayer {
1397    fn from(value: MinaBaseAccountUpdateFeePayerStableV1) -> Self {
1398        Self {
1399            authorization: value.authorization.to_string(),
1400            body: GraphQLFeePayerBody {
1401                public_key: value.body.public_key.to_string(),
1402                fee: value.body.fee.as_u64().to_string(),
1403                valid_until: value.body.valid_until.map(|v| v.as_u32().to_string()),
1404                nonce: value.body.nonce.to_string(),
1405            },
1406        }
1407    }
1408}
1409
1410impl TryFrom<InputGraphQLFeePayer> for MinaBaseAccountUpdateFeePayerStableV1 {
1411    type Error = ConversionError;
1412
1413    fn try_from(value: InputGraphQLFeePayer) -> Result<Self, Self::Error> {
1414        Ok(Self {
1415            authorization: value.authorization.parse()?,
1416            body: MinaBaseAccountUpdateBodyFeePayerStableV1 {
1417                public_key: value.body.public_key.parse()?,
1418                fee: CurrencyFeeStableV1(value.body.fee.parse::<u64>()?.into()),
1419                valid_until: value
1420                    .body
1421                    .valid_until
1422                    .map(|v| -> Result<_, ConversionError> {
1423                        Ok(MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1424                            v.parse::<u32>()?.into(),
1425                        ))
1426                    })
1427                    .transpose()?,
1428                nonce: value.body.nonce.parse::<u32>()?.into(),
1429            },
1430        })
1431    }
1432}
1433
1434impl TryFrom<MinaBaseAccountUpdateTStableV1> for GraphQLAccountUpdate {
1435    type Error = ConversionError;
1436
1437    fn try_from(value: MinaBaseAccountUpdateTStableV1) -> Result<Self, Self::Error> {
1438        Ok(Self {
1439            body: GraphQLAccountUpdateBody {
1440                public_key: value.body.public_key.to_string(),
1441                token_id: value.body.token_id.to_string(),
1442                use_full_commitment: value.body.use_full_commitment,
1443                increment_nonce: value.body.increment_nonce,
1444                update: GraphQLAccountUpdateUpdate::try_from(value.body.update)?,
1445                balance_change: GraphQLBalanceChange::from(value.body.balance_change),
1446                events: value
1447                    .body
1448                    .events
1449                    .0
1450                    .into_iter()
1451                    .map(|v| v.into_iter().map(|i| i.to_decimal()).collect())
1452                    .collect(),
1453                actions: value
1454                    .body
1455                    .actions
1456                    .0
1457                    .into_iter()
1458                    .map(|v| v.into_iter().map(|i| i.to_decimal()).collect())
1459                    .collect(),
1460                call_data: value.body.call_data.to_decimal(),
1461                // TODO(adonagy): figure out call depth
1462                call_depth: 0,
1463                preconditions: GraphQLPreconditions::from(value.body.preconditions),
1464                may_use_token: GraphQLMayUseToken::from(value.body.may_use_token),
1465                authorization_kind: GraphQLAuthorizationKind::from(value.body.authorization_kind),
1466                implicit_account_creation_fee: value.body.implicit_account_creation_fee,
1467            },
1468            authorization: GraphQLAuthorization::try_from(value.authorization)?,
1469        })
1470    }
1471}
1472
1473impl TryFrom<InputGraphQLAccountUpdate> for MinaBaseAccountUpdateTStableV1 {
1474    type Error = ConversionError;
1475
1476    fn try_from(value: InputGraphQLAccountUpdate) -> Result<Self, Self::Error> {
1477        Ok(Self {
1478            body: MinaBaseAccountUpdateBodyStableV1 {
1479                public_key: value.body.public_key.parse()?,
1480                token_id: value.body.token_id.parse()?,
1481                update: value.body.update.try_into()?,
1482                balance_change: value.body.balance_change.try_into()?,
1483                increment_nonce: value.body.increment_nonce,
1484                events: MinaBaseAccountUpdateBodyEventsStableV1(
1485                    value
1486                        .body
1487                        .events
1488                        .into_iter()
1489                        .map(|v| {
1490                            v.into_iter()
1491                                .map(|i| BigInt::from_decimal(&i).map_err(ConversionError::from))
1492                                .collect::<Result<_, _>>()
1493                        })
1494                        .collect::<Result<_, _>>()?,
1495                ),
1496                actions: MinaBaseAccountUpdateBodyEventsStableV1(
1497                    value
1498                        .body
1499                        .actions
1500                        .into_iter()
1501                        .map(|v| {
1502                            v.into_iter()
1503                                .map(|i| BigInt::from_decimal(&i).map_err(ConversionError::from))
1504                                .collect::<Result<_, _>>()
1505                        })
1506                        .collect::<Result<_, _>>()?,
1507                ),
1508                call_data: BigInt::from_decimal(&value.body.call_data)?,
1509                preconditions: value.body.preconditions.try_into()?,
1510                use_full_commitment: value.body.use_full_commitment,
1511                implicit_account_creation_fee: value.body.implicit_account_creation_fee,
1512                may_use_token: value.body.may_use_token.into(),
1513                authorization_kind: value.body.authorization_kind.try_into()?,
1514            },
1515            authorization: value.authorization.try_into()?,
1516        })
1517    }
1518}
1519
1520impl TryFrom<InputGraphQLTiming> for MinaBaseAccountUpdateUpdateTimingInfoStableV1 {
1521    type Error = ConversionError;
1522
1523    fn try_from(value: InputGraphQLTiming) -> Result<Self, Self::Error> {
1524        let cliff_time: u32 = value.cliff_time.try_into()?;
1525        let vesting_period: u32 = value.vesting_period.try_into()?;
1526        Ok(Self {
1527            initial_minimum_balance: CurrencyBalanceStableV1(CurrencyAmountStableV1(
1528                value.initial_minimum_balance.parse::<u64>()?.into(),
1529            )),
1530            cliff_time: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(cliff_time.into()),
1531            cliff_amount: CurrencyAmountStableV1(value.cliff_amount.parse::<u64>()?.into()),
1532            vesting_period: MinaNumbersGlobalSlotSpanStableV1::GlobalSlotSpan(
1533                vesting_period.into(),
1534            ),
1535            vesting_increment: CurrencyAmountStableV1(
1536                value.vesting_increment.parse::<u64>()?.into(),
1537            ),
1538        })
1539    }
1540}
1541
1542#[cfg(test)]
1543mod test {
1544    use std::str::FromStr;
1545
1546    use mina_p2p_messages::{
1547        binprot::BinProtRead,
1548        v2::{
1549            MinaBaseSignedCommandMemoStableV1, MinaBaseUserCommandStableV2,
1550            MinaBaseZkappCommandTStableV1WireStableV1,
1551        },
1552    };
1553
1554    use super::*;
1555
1556    #[test]
1557    fn test_empty_memo() {
1558        use ledger::scan_state::transaction_logic::Memo;
1559
1560        let expected = "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH";
1561        let empty_memo = Memo::from_str("").unwrap();
1562        let mina_empty_memo = MinaBaseSignedCommandMemoStableV1::from(&empty_memo);
1563        assert_eq!(mina_empty_memo.to_base58check(), expected);
1564        let empty_memo = Memo::empty();
1565        let mina_empty_memo = MinaBaseSignedCommandMemoStableV1::from(&empty_memo);
1566        assert_eq!(mina_empty_memo.to_base58check(), expected);
1567    }
1568
1569    #[test]
1570    fn test_zkapp_from_input() {
1571        let bytes = include_bytes!("../../../../tests/files/zkapps/valid_zkapp.bin");
1572        let zkapp =
1573            MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap();
1574
1575        let serialized_valid = serde_json::to_string_pretty(&zkapp).unwrap();
1576
1577        std::fs::write("zkapp_valid.json", &serialized_valid).unwrap();
1578
1579        let from_input = create_input_graphql_zkapp();
1580        let converted: MinaBaseUserCommandStableV2 = from_input.zkapp_command.try_into().unwrap();
1581        if let MinaBaseUserCommandStableV2::ZkappCommand(zkapp_cmd) = converted {
1582            let serialized_converted = serde_json::to_string_pretty(&zkapp_cmd).unwrap();
1583            std::fs::write("zkapp_converted.json", &serialized_converted).unwrap();
1584            assert_eq!(serialized_valid, serialized_converted);
1585        } else {
1586            unreachable!()
1587        }
1588    }
1589
1590    #[test]
1591    fn test_authorization_kind() {
1592        let kind = InputGraphQLAuthorizationKind {
1593            is_signed: false,
1594            is_proved: true,
1595            verification_key_hash: Some(
1596                "19951435866906059835892103359374709356309230417850637795098911039647240505427"
1597                    .to_string(),
1598            ),
1599        };
1600        let converted: Result<MinaBaseAccountUpdateAuthorizationKindStableV1, ConversionError> =
1601            kind.try_into();
1602
1603        assert!(converted.is_ok());
1604    }
1605
1606    #[test]
1607    fn test_authorization_proof() {
1608        let proof = InputGraphQLAuthorization {
1609            signature: None,
1610            proof: Some(
1611                include_str!("../../../../tests/files/zkapps/proof_string.txt").to_string(),
1612            ),
1613        };
1614        let converted: Result<MinaBaseControlStableV2, _> = proof.try_into();
1615        assert!(converted.is_ok());
1616    }
1617
1618    fn create_input_graphql_zkapp() -> InputGraphQLZkapp {
1619        InputGraphQLZkapp {
1620            zkapp_command: InputGraphQLZkappCommand {
1621                memo: Some("E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH".to_string()),
1622                fee_payer: InputGraphQLFeePayer {
1623                    body: InputGraphQLFeePayerBody {
1624                        public_key: "B62qpD75xH5R19wxZG2uz8whNsHPTioVoYcPV3zfjjSbzTmaHQHKKEV".to_string(),
1625                        fee: "117000000".to_string(),
1626                        valid_until: None,
1627                        nonce: "1128".to_string(),
1628                    },
1629                    authorization: "7mX5Lwu2bdnJPc4DJu7CkwTSR5behoKH8yZh7myCGgYfib5Sq3dfgPQY6LcXdrpQma1NvoLC5i7HLFEQZTnkBFcn96TP57JF".to_string(),
1630                },
1631                account_updates: vec![
1632                    InputGraphQLAccountUpdate {
1633                        body: InputGraphQLAccountUpdateBody {
1634                            call_depth: 0,
1635                            public_key: "B62qpD75xH5R19wxZG2uz8whNsHPTioVoYcPV3zfjjSbzTmaHQHKKEV".to_string(),
1636                            token_id: "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf".to_string(),
1637                            update: InputGraphQLAccountUpdateUpdate {
1638                                app_state: vec![
1639                                    None,
1640                                    None,
1641                                    None,
1642                                    None,
1643                                    None,
1644                                    None,
1645                                    None,
1646                                    None,
1647                                ],
1648                                delegate: None,
1649                                verification_key: None,
1650                                permissions: None,
1651                                zkapp_uri: None,
1652                                token_symbol: None,
1653                                timing: None,
1654                                voting_for: None,
1655                            },
1656                            balance_change: InputGraphQLBalanceChange {
1657                                magnitude: "1000000000".to_string(),
1658                                sgn: "Negative".to_string(),
1659                            },
1660                            increment_nonce: false,
1661                            events: vec![],
1662                            actions: vec![],
1663                            call_data: "0".to_string(),
1664                            preconditions: InputGraphQLPreconditions {
1665                                network: InputGraphQLPreconditionsNetwork {
1666                                    snarked_ledger_hash: None,
1667                                    blockchain_length: None,
1668                                    min_window_density: None,
1669                                    total_currency: None,
1670                                    global_slot_since_genesis: None,
1671                                    staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1672                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1673                                            hash: None,
1674                                            total_currency: None,
1675                                        },
1676                                        seed: None,
1677                                        start_checkpoint: None,
1678                                        lock_checkpoint: None,
1679                                        epoch_length: None,
1680                                    },
1681                                    next_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1682                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1683                                            hash: None,
1684                                            total_currency: None,
1685                                        },
1686                                        seed: None,
1687                                        start_checkpoint: None,
1688                                        lock_checkpoint: None,
1689                                        epoch_length: None,
1690                                    },
1691                                },
1692                                account: InputGraphQLPreconditionsAccount {
1693                                    balance: None,
1694                                    nonce: None,
1695                                    receipt_chain_hash: None,
1696                                    delegate: None,
1697                                    state: vec![
1698                                        None, None, None, None, None, None, None, None
1699                                    ],
1700                                    action_state: None,
1701                                    proved_state: None,
1702                                    is_new: None,
1703                                },
1704                                valid_while: None,
1705                            },
1706                            use_full_commitment: true,
1707                            implicit_account_creation_fee: false,
1708                            may_use_token: InputGraphQLMayUseToken {
1709                                parents_own_token: false,
1710                                inherit_from_parent: false,
1711                            },
1712                            authorization_kind: InputGraphQLAuthorizationKind {
1713                                is_signed: true,
1714                                is_proved: false,
1715                                verification_key_hash: None,
1716                            },
1717                        },
1718                        authorization: InputGraphQLAuthorization {
1719                            proof: None,
1720                            signature: Some("7mX5Lwu2bdnJPc4DJu7CkwTSR5behoKH8yZh7myCGgYfib5Sq3dfgPQY6LcXdrpQma1NvoLC5i7HLFEQZTnkBFcn96TP57JF".to_string()),
1721                        },
1722                    },
1723                    InputGraphQLAccountUpdate {
1724                        body: InputGraphQLAccountUpdateBody {
1725                            call_depth: 0,
1726                            public_key: "B62qqKAQh8M61uvuw3tjJsmRgsEvzRm84Nc9MwXTF3zoqFRZ86rV8qk".to_string(),
1727                            token_id: "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf".to_string(),
1728                            update: InputGraphQLAccountUpdateUpdate {
1729                                app_state: vec![
1730                                    Some("1".to_string()),
1731                                    Some("0".to_string()),
1732                                    Some("0".to_string()),
1733                                    Some("0".to_string()),
1734                                    Some("0".to_string()),
1735                                    Some("0".to_string()),
1736                                    Some("0".to_string()),
1737                                    Some("0".to_string()),
1738                                ],
1739                                delegate: None,
1740                                verification_key: Some(InputGraphQLVerificationKey {
1741                                    data: "AACcenc1yLdGBm4xtUN1dpModROI0zovuy5rz2a94vfdBgG1C75BqviU4vw6JUYqODF8n9ivtfeU5s9PcpEGIP0htil2mfx8v2DB5RuNQ7VxJWkha0TSnJJsOl0FxhjldBbOY3tUZzZxHpPhHOKHz/ZAXRYFIsf2x+7boXC0iPurEX9VcnaJIq+YxxmnSfeYYxHkjxO9lrDBqjXzd5AHMnYyjTPC69B+5In7AOGS6R+A/g3/aR/MKDa4eDVrnsF9Oy/Ay8ahic2sSAZvtn08MdRyk/jm2cLlJbeAAad6Xyz/H9l7JrkbVwDMMPxvHVHs27tNoJCzIlrRzB7pg3ju9aQOu4h3thDr+WSgFQWKvcRPeL7f3TFjIr8WZ2457RgMcTwXwORKbqJCcyKVNOE+FlNwVkOKER+WIpC0OlgGuayPFwQQkbb91jaRlJvahfwkbF2+AJmDnavmNpop9T+/Xak1adXIrsRPeOjC+qIKxIbGimoMOoYzYlevKA80LnJ7HC0IxR+yNLvoSYxDDPNRD+OCCxk5lM2h8IDUiCNWH4FZNJ+doiigKjyZlu/xZ7jHcX7qibu/32KFTX85DPSkQM8dAEkH+vlkHmyXGLF4+xOVKeM0ihV5OEQrOABcgfTkbRsyxNInUBh0WiQyALE2ctjvkRCiE2P24bjFA8SgFmTM7gAKR89XcqLS/NP7lwCEej/L8q8R7sKGMCXmgFYluWH4JBSPDgvMxScfjFS33oBNb7po8cLnAORzohXoYTSgztklD0mKn6EegLbkLtwwr9ObsLz3m7fp/3wkNWFRkY5xzSZN1VybbQbmpyQNCpxd/kdDsvlszqlowkyC8HnKbhnvE0Mrz3ZIk4vSs/UGBSXAoESFCFCPcTq11TCOhE5rumMJErv5LusDHJgrBtQUMibLU9A1YbF7SPDAR2QZd0yx3waAC2F3xF+U682SOKF7oCZl2OICysRHqH+rZ604UfdGG0zWRuP2yg6kfGwcGQbO1ql40WrWTiFhbxxdKC7Gbz4y9Sb7q5EsPt6Z1AIn34/nXB/IWfC0gg/OgfPQTR7uxiTo2OOwjHni1f4KhT4rEmDAQn6ty6/ZRKHPWjUaAREbEw3tC36fI09hCYjjVTEmMAFTApk/tMUu0tC9Dt/vfDgXAlDJBwN5Y2Pt60qWY92skizVcWyWBxp5A8e4cVu3iToxOGUbSHzawovjubcH7qWjIZoghZJ16QB1c0ryiAfHB48OHhs2p/JZWz8Dp7kfcPkeg2Of2NbupJlNVMLIH4IGWaPAscBRkZ+F4oLqOhJ5as7fAzzU8PQdeZi0YgssGDJVmNEHP61I16KZNcxQqR0EUVwhyMmYmpVjvtfhHi/6I3TgYCmfnm6GL2sN144vMWg/gJ+p9a4GcEA0+gK3oCcKcwkq5rm+1Oxo9LWLp92Bdxq3iqfoIFmJ/ANGSbHF8StVmlVsP8zA+xuHylyiww/Lercce7cq0YA5PtYS3ge9IDYwXckBUXb5ikD3alrrv5mvMu6itB7ix2f8lbiF9Fkmc4Bk2ycIWXJDCuBN+2sTFqzUeoT6xY8XWaOcnDvqOgSm/CCSv38umiOE2jEpsKYxhRc6W70UJkrzd3hr2DiSF1I2B+krpUVK1GeOdCLC5sl7YPzk+pF8183uI9wse6UTlqIiroKqsggzLBy/IjAfxS0BxFy5zywXqp+NogFkoTEJmR5MaqOkPfap+OsD1lGScY6+X4WW/HqCWrmA3ZTqDGngQMTGXLCtl6IS/cQpihS1NRbNqOtKTaCB9COQu0oz6RivBlywuaj3MKUdmbQ2gVDj+SGQItCNaXawyPSBjB9VT+68SoJVySQsYPCuEZCb0V/40n/a7RAbyrnNjP+2HwD7p27Pl1RSzqq35xiPdnycD1UeEPLpx/ON65mYCkn+KLQZmkqPio+vA2KmJngWTx+ol4rVFimGm76VT0xCFDsu2K0YX0yoLNH4u2XfmT9NR8gGfkVRCnnNjlbgHQmEwC75+GmEJ5DjD3d+s6IXTQ60MHvxbTHHlnfmPbgKn2SAI0uVoewKC9GyK6dSaboLw3C48jl0E2kyc+7umhCk3kEeWmt//GSjRNhoq+B+mynXiOtgFs/Am2v1TBjSb+6tcijsf5tFJmeGxlCjJnTdNWBkSHpMoo6OFkkpA6/FBAUHLSM7Yv8oYyd0GtwF5cCwQ6aRTbl9oG/mUn5Q92OnDMQcUjpgEho0Dcp2OqZyyxqQSPrbIIZZQrS2HkxBgjcfcSTuSHo7ONqlRjLUpO5yS95VLGXBLLHuCiIMGT+DW6DoJRtRIS+JieVWBoX0YsWgYInXrVlWUv6gDng5AyVFkUIFwZk7/3mVAgvXO83ArVKA4S747jT60w5bgV4Jy55slDM=".to_string(),
1742                                    hash: "11640126627177324946637007967436400725357874055180801746732941023691529117236".to_string(),
1743                                }),
1744                                permissions: Some(InputGraphQLAccountUpdateUpdatePermissions {
1745                                    edit_state: "Proof".to_string(),
1746                                    access: "Proof".to_string(),
1747                                    send: "Proof".to_string(),
1748                                    receive: "Proof".to_string(),
1749                                    set_delegate: "Proof".to_string(),
1750                                    set_permissions: "Proof".to_string(),
1751                                    set_verification_key: InputGraphQLSetVerificationKeyPermissions {
1752                                        auth: "Proof".to_string(),
1753                                        txn_version: "3".to_string(),
1754                                    },
1755                                    set_zkapp_uri: "Proof".to_string(),
1756                                    edit_action_state: "Proof".to_string(),
1757                                    set_token_symbol: "Proof".to_string(),
1758                                    set_timing: "Proof".to_string(),
1759                                    set_voting_for: "Proof".to_string(),
1760                                    increment_nonce: "Proof".to_string(),
1761                                }),
1762                                zkapp_uri: None,
1763                                token_symbol: None,
1764                                timing: None,
1765                                voting_for: None,
1766                            },
1767                            balance_change: InputGraphQLBalanceChange {
1768                                magnitude: "0".to_string(),
1769                                sgn: "Positive".to_string(),
1770                            },
1771                            increment_nonce: true,
1772                            events: vec![],
1773                            actions: vec![],
1774                            call_data: "0".to_string(),
1775                            preconditions: InputGraphQLPreconditions {
1776                                network: InputGraphQLPreconditionsNetwork {
1777                                    snarked_ledger_hash: None,
1778                                    blockchain_length: None,
1779                                    min_window_density: None,
1780                                    total_currency: None,
1781                                    global_slot_since_genesis: None,
1782                                    staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1783                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1784                                            hash: None,
1785                                            total_currency: None,
1786                                        },
1787                                        seed: None,
1788                                        start_checkpoint: None,
1789                                        lock_checkpoint: None,
1790                                        epoch_length: None,
1791                                    },
1792                                    next_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1793                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1794                                            hash: None,
1795                                            total_currency: None,
1796                                        },
1797                                        seed: None,
1798                                        start_checkpoint: None,
1799                                        lock_checkpoint: None,
1800                                        epoch_length: None,
1801                                    },
1802                                },
1803                                account: InputGraphQLPreconditionsAccount {
1804                                    balance: None,
1805                                    nonce: Some(InputGraphQLPreconditionsNetworkBounds {
1806                                        upper: "0".to_string(),
1807                                        lower: "0".to_string(),
1808                                    }),
1809                                    receipt_chain_hash: None,
1810                                    delegate: None,
1811                                    state: vec![
1812                                        None, None, None, None, None, None, None, None
1813                                    ],
1814                                    action_state: None,
1815                                    proved_state: Some(false),
1816                                    is_new: None,
1817                                },
1818                                valid_while: None,
1819                            },
1820                            use_full_commitment: false,
1821                            implicit_account_creation_fee: false,
1822                            may_use_token: InputGraphQLMayUseToken {
1823                                parents_own_token: false,
1824                                inherit_from_parent: false,
1825                            },
1826                            authorization_kind: InputGraphQLAuthorizationKind {
1827                                is_signed: true,
1828                                is_proved: false,
1829                                verification_key_hash: None,
1830                            },
1831                        },
1832                        authorization: InputGraphQLAuthorization {
1833                            proof: None,
1834                            signature: Some("7mXFnDxZBE5iXBfw9LRPXST3sSodXAdTJSWFqX3hBoDA3wv5s2s9TLMDCXgatMvMH4bDttAFyJuezWmbSA81FXeMFZgqcxtt".to_string()),
1835                        },
1836                    },
1837                ],
1838            },
1839        }
1840    }
1841
1842    #[test]
1843    pub fn test_bigint_to_decimal() {
1844        let bigint = BigInt::from_decimal("1").unwrap();
1845        let decimal = serde_json::to_string(&bigint).unwrap();
1846        assert_eq!(
1847            decimal,
1848            "\"0x0000000000000000000000000000000000000000000000000000000000000001\"".to_string()
1849        );
1850    }
1851}