mina_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            (None, None) => Ok(MinaBaseControlStableV2::NoneGiven),
328            _ => Err(ConversionError::Custom(
329                "Either signature or proof must be provided, but not both".into(),
330            )),
331        }
332    }
333}
334
335#[derive(GraphQLObject, Debug)]
336pub struct GraphQLAccountUpdateBody {
337    pub public_key: String,
338    pub token_id: String,
339    pub use_full_commitment: bool,
340    pub increment_nonce: bool,
341    pub update: GraphQLAccountUpdateUpdate,
342    pub balance_change: GraphQLBalanceChange,
343    pub events: Vec<Vec<String>>,
344    pub actions: Vec<Vec<String>>,
345    pub call_data: String,
346    pub call_depth: i32,
347    pub preconditions: GraphQLPreconditions,
348    pub may_use_token: GraphQLMayUseToken,
349    pub authorization_kind: GraphQLAuthorizationKind,
350    pub implicit_account_creation_fee: bool,
351}
352
353#[derive(GraphQLInputObject, Debug)]
354pub struct InputGraphQLAccountUpdateBody {
355    pub public_key: String,
356    pub token_id: String,
357    pub use_full_commitment: bool,
358    pub increment_nonce: bool,
359    pub update: InputGraphQLAccountUpdateUpdate,
360    pub balance_change: InputGraphQLBalanceChange,
361    pub events: Vec<Vec<String>>,
362    pub actions: Vec<Vec<String>>,
363    pub call_data: String,
364    pub call_depth: i32,
365    pub preconditions: InputGraphQLPreconditions,
366    pub may_use_token: InputGraphQLMayUseToken,
367    pub authorization_kind: InputGraphQLAuthorizationKind,
368    pub implicit_account_creation_fee: bool,
369}
370
371#[derive(GraphQLObject, Debug)]
372pub struct GraphQLAuthorizationKind {
373    pub is_signed: bool,
374    pub is_proved: bool,
375    pub verification_key_hash: Option<String>,
376}
377
378#[derive(GraphQLInputObject, Debug)]
379pub struct InputGraphQLAuthorizationKind {
380    pub is_signed: bool,
381    pub is_proved: bool,
382    pub verification_key_hash: Option<String>,
383}
384
385impl From<MinaBaseAccountUpdateAuthorizationKindStableV1> for GraphQLAuthorizationKind {
386    fn from(value: MinaBaseAccountUpdateAuthorizationKindStableV1) -> Self {
387        match value {
388            MinaBaseAccountUpdateAuthorizationKindStableV1::Signature => GraphQLAuthorizationKind {
389                is_signed: true,
390                is_proved: false,
391                verification_key_hash: None,
392            },
393            MinaBaseAccountUpdateAuthorizationKindStableV1::Proof(proof) => {
394                GraphQLAuthorizationKind {
395                    is_signed: false,
396                    is_proved: true,
397                    verification_key_hash: Some(proof.to_decimal()),
398                }
399            }
400            MinaBaseAccountUpdateAuthorizationKindStableV1::NoneGiven => GraphQLAuthorizationKind {
401                is_signed: false,
402                is_proved: false,
403                verification_key_hash: None,
404            },
405        }
406    }
407}
408
409impl TryFrom<InputGraphQLAuthorizationKind> for MinaBaseAccountUpdateAuthorizationKindStableV1 {
410    type Error = ConversionError;
411    fn try_from(value: InputGraphQLAuthorizationKind) -> Result<Self, Self::Error> {
412        if value.is_signed {
413            return Ok(MinaBaseAccountUpdateAuthorizationKindStableV1::Signature);
414        }
415
416        if value.is_proved {
417            match &value.verification_key_hash {
418                Some(vk_hash) => {
419                    let big_int = BigInt::from_decimal(vk_hash)?;
420                    return Ok(MinaBaseAccountUpdateAuthorizationKindStableV1::Proof(
421                        big_int,
422                    ));
423                }
424                None => {
425                    return Err(ConversionError::MissingField(
426                        "verification_key_hash".to_string(),
427                    ));
428                }
429            }
430        }
431
432        Ok(MinaBaseAccountUpdateAuthorizationKindStableV1::NoneGiven)
433    }
434}
435
436#[derive(GraphQLObject, Debug)]
437pub struct GraphQLMayUseToken {
438    pub parents_own_token: bool,
439    pub inherit_from_parent: bool,
440}
441
442#[derive(GraphQLInputObject, Debug)]
443pub struct InputGraphQLMayUseToken {
444    pub parents_own_token: bool,
445    pub inherit_from_parent: bool,
446}
447
448impl From<MinaBaseAccountUpdateMayUseTokenStableV1> for GraphQLMayUseToken {
449    fn from(value: MinaBaseAccountUpdateMayUseTokenStableV1) -> Self {
450        match value {
451            MinaBaseAccountUpdateMayUseTokenStableV1::ParentsOwnToken => GraphQLMayUseToken {
452                parents_own_token: true,
453                inherit_from_parent: false,
454            },
455            MinaBaseAccountUpdateMayUseTokenStableV1::InheritFromParent => GraphQLMayUseToken {
456                parents_own_token: false,
457                inherit_from_parent: true,
458            },
459            MinaBaseAccountUpdateMayUseTokenStableV1::No => GraphQLMayUseToken {
460                parents_own_token: false,
461                inherit_from_parent: false,
462            },
463        }
464    }
465}
466
467impl From<InputGraphQLMayUseToken> for MinaBaseAccountUpdateMayUseTokenStableV1 {
468    fn from(value: InputGraphQLMayUseToken) -> Self {
469        if value.parents_own_token {
470            MinaBaseAccountUpdateMayUseTokenStableV1::ParentsOwnToken
471        } else if value.inherit_from_parent {
472            MinaBaseAccountUpdateMayUseTokenStableV1::InheritFromParent
473        } else {
474            MinaBaseAccountUpdateMayUseTokenStableV1::No
475        }
476    }
477}
478
479#[derive(GraphQLObject, Debug)]
480pub struct GraphQLEvent {
481    pub event: String,
482    pub data: String,
483}
484
485#[derive(GraphQLInputObject, Debug)]
486pub struct InputGraphQLEvent {
487    pub event: String,
488    pub data: String,
489}
490
491#[derive(GraphQLObject, Debug)]
492pub struct GraphQLAction {
493    pub action: String,
494    pub data: String,
495}
496
497#[derive(GraphQLInputObject, Debug)]
498pub struct InputGraphQLAction {
499    pub action: String,
500    pub data: String,
501}
502
503#[derive(GraphQLObject, Debug)]
504pub struct GraphQLPreconditions {
505    pub network: GraphQLPreconditionsNetwork,
506    pub account: GraphQLPreconditionsAccount,
507    pub valid_while: Option<GraphQLPreconditionsNetworkBounds>,
508}
509
510#[derive(GraphQLInputObject, Debug)]
511pub struct InputGraphQLPreconditions {
512    pub network: InputGraphQLPreconditionsNetwork,
513    pub account: InputGraphQLPreconditionsAccount,
514    pub valid_while: Option<InputGraphQLPreconditionsNetworkBounds>,
515}
516
517#[derive(GraphQLObject, Debug)]
518pub struct GraphQLPreconditionsAccount {
519    pub balance: Option<GraphQLPreconditionsNetworkBounds>,
520    pub nonce: Option<GraphQLPreconditionsNetworkBounds>,
521    pub receipt_chain_hash: Option<String>,
522    pub delegate: Option<String>,
523    pub state: Vec<Option<String>>,
524    pub action_state: Option<String>,
525    pub proved_state: Option<bool>,
526    pub is_new: Option<bool>,
527}
528
529#[derive(GraphQLInputObject, Debug)]
530pub struct InputGraphQLPreconditionsAccount {
531    pub balance: Option<InputGraphQLPreconditionsNetworkBounds>,
532    pub nonce: Option<InputGraphQLPreconditionsNetworkBounds>,
533    pub receipt_chain_hash: Option<String>,
534    pub delegate: Option<String>,
535    pub state: Vec<Option<String>>,
536    pub action_state: Option<String>,
537    pub proved_state: Option<bool>,
538    pub is_new: Option<bool>,
539}
540
541impl From<MinaBaseAccountUpdateAccountPreconditionStableV1> for GraphQLPreconditionsAccount {
542    fn from(value: MinaBaseAccountUpdateAccountPreconditionStableV1) -> Self {
543        Self {
544            balance: if let MinaBaseZkappPreconditionAccountStableV2Balance::Check(v) =
545                value.0.balance
546            {
547                Some(GraphQLPreconditionsNetworkBounds {
548                    upper: v.upper.as_u64().to_string(),
549                    lower: v.lower.as_u64().to_string(),
550                })
551            } else {
552                None
553            },
554            nonce: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(v) =
555                value.0.nonce
556            {
557                Some(GraphQLPreconditionsNetworkBounds {
558                    upper: v.upper.as_u32().to_string(),
559                    lower: v.lower.as_u32().to_string(),
560                })
561            } else {
562                None
563            },
564            receipt_chain_hash:
565                if let MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash::Check(v) =
566                    value.0.receipt_chain_hash
567                {
568                    Some(v.to_decimal())
569                } else {
570                    None
571                },
572            delegate: if let MinaBaseZkappPreconditionAccountStableV2Delegate::Check(v) =
573                value.0.delegate
574            {
575                Some(v.to_string())
576            } else {
577                None
578            },
579            state: value
580                .0
581                .state
582                .clone()
583                .iter()
584                .map(|v| {
585                    if let MinaBaseZkappPreconditionAccountStableV2StateA::Check(state_value) = v {
586                        Some(state_value.to_decimal())
587                    } else {
588                        None
589                    }
590                })
591                .collect(),
592            action_state: if let MinaBaseZkappPreconditionAccountStableV2StateA::Check(value) =
593                value.0.action_state
594            {
595                Some(value.to_decimal())
596            } else {
597                None
598            },
599            proved_state: if let MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(v) =
600                value.0.proved_state
601            {
602                Some(v)
603            } else {
604                None
605            },
606            is_new: if let MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(v) =
607                value.0.is_new
608            {
609                Some(v)
610            } else {
611                None
612            },
613        }
614    }
615}
616
617impl TryFrom<InputGraphQLPreconditionsAccount>
618    for MinaBaseAccountUpdateAccountPreconditionStableV1
619{
620    type Error = ConversionError;
621    fn try_from(value: InputGraphQLPreconditionsAccount) -> Result<Self, Self::Error> {
622        let state: Result<Vec<_>, _> = value
623            .state
624            .iter()
625            .map(|v| {
626                if let Some(state) = v {
627                    BigInt::from_decimal(state)
628                        .map(MinaBaseZkappPreconditionAccountStableV2StateA::Check)
629                } else {
630                    Ok(MinaBaseZkappPreconditionAccountStableV2StateA::Ignore)
631                }
632            })
633            .collect();
634
635        let state = state?;
636        Ok(Self(MinaBaseZkappPreconditionAccountStableV2 {
637            balance: if let Some(balance) = value.balance {
638                MinaBaseZkappPreconditionAccountStableV2Balance::Check(
639                    MinaBaseZkappPreconditionAccountStableV2BalanceA {
640                        lower: CurrencyBalanceStableV1(CurrencyAmountStableV1(
641                            balance.lower.parse::<u64>()?.into(),
642                        )),
643                        upper: CurrencyBalanceStableV1(CurrencyAmountStableV1(
644                            balance.upper.parse::<u64>()?.into(),
645                        )),
646                    },
647                )
648            } else {
649                MinaBaseZkappPreconditionAccountStableV2Balance::Ignore
650            },
651            nonce: if let Some(nonce) = value.nonce {
652                MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
653                    MinaBaseZkappPreconditionProtocolStateStableV1LengthA {
654                        lower: (nonce.lower.parse::<u32>()?).into(),
655                        upper: (nonce.upper.parse::<u32>()?).into(),
656                    },
657                )
658            } else {
659                MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore
660            },
661            receipt_chain_hash: if let Some(receipt_chain_hash) = value.receipt_chain_hash {
662                MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash::Check(
663                    MinaBaseReceiptChainHashStableV1(BigInt::from_decimal(&receipt_chain_hash)?),
664                )
665            } else {
666                MinaBaseZkappPreconditionAccountStableV2ReceiptChainHash::Ignore
667            },
668            delegate: if let Some(delegate) = value.delegate {
669                MinaBaseZkappPreconditionAccountStableV2Delegate::Check(
670                    AccountPublicKey::from_str(&delegate)?.into(),
671                )
672            } else {
673                MinaBaseZkappPreconditionAccountStableV2Delegate::Ignore
674            },
675            state: PaddedSeq(
676                state
677                    .try_into()
678                    .map_err(|_| ConversionError::InvalidLength)?,
679            ),
680            action_state: if let Some(action_state) = value.action_state {
681                MinaBaseZkappPreconditionAccountStableV2StateA::Check(BigInt::from_decimal(
682                    &action_state,
683                )?)
684            } else {
685                MinaBaseZkappPreconditionAccountStableV2StateA::Ignore
686            },
687            proved_state: if let Some(proved_state) = value.proved_state {
688                MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(proved_state)
689            } else {
690                MinaBaseZkappPreconditionAccountStableV2ProvedState::Ignore
691            },
692            is_new: if let Some(is_new) = value.is_new {
693                MinaBaseZkappPreconditionAccountStableV2ProvedState::Check(is_new)
694            } else {
695                MinaBaseZkappPreconditionAccountStableV2ProvedState::Ignore
696            },
697        }))
698    }
699}
700#[derive(GraphQLObject, Debug)]
701pub struct GraphQLPreconditionsNetwork {
702    pub snarked_ledger_hash: Option<String>,
703    pub blockchain_length: Option<GraphQLPreconditionsNetworkBounds>,
704    pub min_window_density: Option<GraphQLPreconditionsNetworkBounds>,
705    pub total_currency: Option<GraphQLPreconditionsNetworkBounds>,
706    pub global_slot_since_genesis: Option<GraphQLPreconditionsNetworkBounds>,
707    pub staking_epoch_data: GraphQLPreconditionsNetworkEpochData,
708    pub next_epoch_data: GraphQLPreconditionsNetworkEpochData,
709}
710
711#[derive(GraphQLInputObject, Debug)]
712pub struct InputGraphQLPreconditionsNetwork {
713    pub snarked_ledger_hash: Option<String>,
714    pub blockchain_length: Option<InputGraphQLPreconditionsNetworkBounds>,
715    pub min_window_density: Option<InputGraphQLPreconditionsNetworkBounds>,
716    pub total_currency: Option<InputGraphQLPreconditionsNetworkBounds>,
717    pub global_slot_since_genesis: Option<InputGraphQLPreconditionsNetworkBounds>,
718    pub staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData,
719    pub next_epoch_data: InputGraphQLPreconditionsNetworkEpochData,
720}
721
722#[derive(GraphQLObject, Debug)]
723pub struct GraphQLPreconditionsNetworkEpochData {
724    pub ledger: GraphQLPreconditionsNetworkLedger,
725    pub seed: Option<String>,
726    pub start_checkpoint: Option<String>,
727    pub lock_checkpoint: Option<String>,
728    pub epoch_length: Option<GraphQLPreconditionsNetworkBounds>,
729}
730
731#[derive(GraphQLInputObject, Debug)]
732pub struct InputGraphQLPreconditionsNetworkEpochData {
733    pub ledger: InputGraphQLPreconditionsNetworkLedger,
734    pub seed: Option<String>,
735    pub start_checkpoint: Option<String>,
736    pub lock_checkpoint: Option<String>,
737    pub epoch_length: Option<InputGraphQLPreconditionsNetworkBounds>,
738}
739
740#[derive(GraphQLObject, Debug)]
741pub struct GraphQLPreconditionsNetworkLedger {
742    pub hash: Option<String>,
743    pub total_currency: Option<GraphQLPreconditionsNetworkBounds>,
744}
745
746#[derive(GraphQLInputObject, Debug)]
747pub struct InputGraphQLPreconditionsNetworkLedger {
748    pub hash: Option<String>,
749    pub total_currency: Option<InputGraphQLPreconditionsNetworkBounds>,
750}
751#[derive(GraphQLObject, Debug)]
752pub struct GraphQLPreconditionsNetworkBounds {
753    pub upper: String,
754    pub lower: String,
755}
756
757#[derive(GraphQLInputObject, Debug)]
758pub struct InputGraphQLPreconditionsNetworkBounds {
759    pub upper: String,
760    pub lower: String,
761}
762
763impl From<MinaBaseZkappPreconditionProtocolStateEpochDataStableV1>
764    for GraphQLPreconditionsNetworkEpochData
765{
766    fn from(value: MinaBaseZkappPreconditionProtocolStateEpochDataStableV1) -> Self {
767        Self {
768            ledger: GraphQLPreconditionsNetworkLedger::from(value.ledger),
769            seed: if let MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed::Check(v) = value.seed {
770                Some(v.to_string())
771            } else {
772                None
773            },
774            start_checkpoint: if let MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(v) = value.start_checkpoint {
775                Some(v.to_string())
776            } else {
777                None
778            },
779            lock_checkpoint: if let MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(v) = value.lock_checkpoint {
780                Some(v.to_string())
781            } else {
782                None
783            },
784            epoch_length: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(v) = value.epoch_length {
785                Some(GraphQLPreconditionsNetworkBounds {
786                    upper: v.upper.as_u32().to_string(),
787                    lower: v.lower.as_u32().to_string(),
788                })
789            } else {
790                None
791            },
792        }
793    }
794}
795
796impl TryFrom<InputGraphQLPreconditionsNetworkEpochData>
797    for MinaBaseZkappPreconditionProtocolStateEpochDataStableV1
798{
799    type Error = ConversionError;
800    fn try_from(value: InputGraphQLPreconditionsNetworkEpochData) -> Result<Self, Self::Error> {
801        Ok(Self {
802            ledger: value.ledger.try_into()?,
803            seed: if let Some(seed) = value.seed {
804                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed::Check(
805                    seed.parse()?,
806                )
807            } else {
808                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochSeed::Ignore
809            },
810            start_checkpoint: if let Some(start_checkpoint) = value.start_checkpoint {
811                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(
812                    start_checkpoint.parse()?,
813                )
814            } else {
815                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Ignore
816            },
817            lock_checkpoint: if let Some(lock_checkpoint) = value.lock_checkpoint {
818                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Check(
819                    lock_checkpoint.parse()?,
820                )
821            } else {
822                MinaBaseZkappPreconditionProtocolStateEpochDataStableV1StartCheckpoint::Ignore
823            },
824            epoch_length: if let Some(epoch_length) = value.epoch_length {
825                MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
826                    MinaBaseZkappPreconditionProtocolStateStableV1LengthA {
827                        lower: (epoch_length.lower.parse::<u32>()?).into(),
828                        upper: (epoch_length.upper.parse::<u32>()?).into(),
829                    },
830                )
831            } else {
832                MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore
833            },
834        })
835    }
836}
837impl From<MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger>
838    for GraphQLPreconditionsNetworkLedger
839{
840    fn from(value: MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger) -> Self {
841        Self {
842            hash: if let MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(v) =
843                value.hash
844            {
845                Some(v.to_string())
846            } else {
847                None
848            },
849            total_currency: if let MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(v) =
850                value.total_currency
851            {
852                Some(GraphQLPreconditionsNetworkBounds {
853                    upper: v.upper.as_u64().to_string(),
854                    lower: v.lower.as_u64().to_string(),
855                })
856            } else {
857                None
858            },
859        }
860    }
861}
862
863impl TryFrom<InputGraphQLPreconditionsNetworkLedger>
864    for MinaBaseZkappPreconditionProtocolStateEpochDataStableV1EpochLedger
865{
866    type Error = ConversionError;
867    fn try_from(value: InputGraphQLPreconditionsNetworkLedger) -> Result<Self, Self::Error> {
868        Ok(Self {
869            hash: if let Some(hash) = value.hash {
870                MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(
871                    hash.parse()?,
872                )
873            } else {
874                MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Ignore
875            },
876            total_currency: if let Some(total_currency) = value.total_currency {
877                MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(
878                    MinaBaseZkappPreconditionProtocolStateStableV1AmountA {
879                        lower: CurrencyAmountStableV1(
880                            (total_currency.lower.parse::<u64>()?).into(),
881                        ),
882                        upper: CurrencyAmountStableV1(
883                            (total_currency.upper.parse::<u64>()?).into(),
884                        ),
885                    },
886                )
887            } else {
888                MinaBaseZkappPreconditionProtocolStateStableV1Amount::Ignore
889            },
890        })
891    }
892}
893
894impl From<MinaBaseZkappPreconditionProtocolStateStableV1> for GraphQLPreconditionsNetwork {
895    fn from(value: MinaBaseZkappPreconditionProtocolStateStableV1) -> Self {
896        Self {
897            snarked_ledger_hash:
898                if let MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(v) =
899                    value.snarked_ledger_hash
900                {
901                    Some(v.to_string())
902                } else {
903                    None
904                },
905            blockchain_length: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
906                v,
907            ) = value.blockchain_length
908            {
909                Some(GraphQLPreconditionsNetworkBounds {
910                    upper: v.upper.as_u32().to_string(),
911                    lower: v.lower.as_u32().to_string(),
912                })
913            } else {
914                None
915            },
916            min_window_density: if let MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
917                v,
918            ) = value.min_window_density
919            {
920                Some(GraphQLPreconditionsNetworkBounds {
921                    upper: v.upper.as_u32().to_string(),
922                    lower: v.lower.as_u32().to_string(),
923                })
924            } else {
925                None
926            },
927            total_currency: if let MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(v) =
928                value.total_currency
929            {
930                Some(GraphQLPreconditionsNetworkBounds {
931                    upper: v.upper.as_u64().to_string(),
932                    lower: v.lower.as_u64().to_string(),
933                })
934            } else {
935                None
936            },
937            global_slot_since_genesis:
938                if let MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(v) =
939                    value.global_slot_since_genesis
940                {
941                    Some(GraphQLPreconditionsNetworkBounds {
942                        upper: v.upper.as_u32().to_string(),
943                        lower: v.lower.as_u32().to_string(),
944                    })
945                } else {
946                    None
947                },
948            staking_epoch_data: GraphQLPreconditionsNetworkEpochData::from(
949                value.staking_epoch_data,
950            ),
951            next_epoch_data: GraphQLPreconditionsNetworkEpochData::from(value.next_epoch_data),
952        }
953    }
954}
955
956impl TryFrom<InputGraphQLPreconditionsNetwork> for MinaBaseZkappPreconditionProtocolStateStableV1 {
957    type Error = ConversionError;
958    fn try_from(value: InputGraphQLPreconditionsNetwork) -> Result<Self, Self::Error> {
959        Ok(Self {
960            snarked_ledger_hash: if let Some(snarked_ledger_hash) = value.snarked_ledger_hash {
961                MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Check(
962                    snarked_ledger_hash.parse()?,
963                )
964            } else {
965                MinaBaseZkappPreconditionProtocolStateStableV1SnarkedLedgerHash::Ignore
966            },
967            blockchain_length: if let Some(blockchain_length) = value.blockchain_length {
968                MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
969                    MinaBaseZkappPreconditionProtocolStateStableV1LengthA {
970                        lower: (blockchain_length.lower.parse::<u32>()?).into(),
971                        upper: (blockchain_length.upper.parse::<u32>()?).into(),
972                    },
973                )
974            } else {
975                MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore
976            },
977            min_window_density: if let Some(min_window_density) = value.min_window_density {
978                MinaBaseZkappPreconditionProtocolStateStableV1Length::Check(
979                    MinaBaseZkappPreconditionProtocolStateStableV1LengthA {
980                        lower: (min_window_density.lower.parse::<u32>()?).into(),
981                        upper: (min_window_density.upper.parse::<u32>()?).into(),
982                    },
983                )
984            } else {
985                MinaBaseZkappPreconditionProtocolStateStableV1Length::Ignore
986            },
987            total_currency: if let Some(total_currency) = value.total_currency {
988                MinaBaseZkappPreconditionProtocolStateStableV1Amount::Check(
989                    MinaBaseZkappPreconditionProtocolStateStableV1AmountA {
990                        lower: CurrencyAmountStableV1(
991                            (total_currency.lower.parse::<u64>()?).into(),
992                        ),
993                        upper: CurrencyAmountStableV1(
994                            (total_currency.upper.parse::<u64>()?).into(),
995                        ),
996                    },
997                )
998            } else {
999                MinaBaseZkappPreconditionProtocolStateStableV1Amount::Ignore
1000            },
1001            global_slot_since_genesis: if let Some(global_slot_since_genesis) =
1002                value.global_slot_since_genesis
1003            {
1004                MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(
1005                    MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlotA {
1006                        lower: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1007                            (global_slot_since_genesis.lower.parse::<u32>()?).into(),
1008                        ),
1009                        upper: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1010                            (global_slot_since_genesis.upper.parse::<u32>()?).into(),
1011                        ),
1012                    },
1013                )
1014            } else {
1015                MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Ignore
1016            },
1017            staking_epoch_data: value.staking_epoch_data.try_into()?,
1018            next_epoch_data: value.next_epoch_data.try_into()?,
1019        })
1020    }
1021}
1022
1023#[derive(GraphQLObject, Debug)]
1024pub struct GraphQLAccountUpdateUpdate {
1025    pub app_state: Vec<Option<String>>,
1026    pub delegate: Option<String>,
1027    pub verification_key: Option<GraphQLVerificationKey>,
1028    pub permissions: Option<GraphQLAccountUpdateUpdatePermissions>,
1029    pub zkapp_uri: Option<String>,
1030    pub token_symbol: Option<String>,
1031    pub timing: Option<GraphQLTiming>,
1032    pub voting_for: Option<String>,
1033}
1034
1035#[derive(GraphQLObject, Debug)]
1036pub struct GraphQLVerificationKey {
1037    pub data: String,
1038    pub hash: String,
1039}
1040
1041#[derive(GraphQLInputObject, Debug)]
1042pub struct InputGraphQLAccountUpdateUpdate {
1043    pub app_state: Vec<Option<String>>,
1044    pub delegate: Option<String>,
1045    pub verification_key: Option<InputGraphQLVerificationKey>,
1046    pub permissions: Option<InputGraphQLAccountUpdateUpdatePermissions>,
1047    pub zkapp_uri: Option<String>,
1048    pub token_symbol: Option<String>,
1049    pub timing: Option<InputGraphQLTiming>,
1050    pub voting_for: Option<String>,
1051}
1052
1053#[derive(GraphQLInputObject, Debug)]
1054pub struct InputGraphQLVerificationKey {
1055    pub data: String,
1056    pub hash: String,
1057}
1058
1059#[derive(GraphQLObject, Debug)]
1060pub struct GraphQLAccountUpdateUpdatePermissions {
1061    pub edit_state: String,
1062    pub access: String,
1063    pub send: String,
1064    pub receive: String,
1065    pub set_delegate: String,
1066    pub set_permissions: String,
1067    pub set_verification_key: GraphQLSetVerificationKeyPermissions,
1068    pub set_zkapp_uri: String,
1069    pub edit_action_state: String,
1070    pub set_token_symbol: String,
1071    pub set_timing: String,
1072    pub set_voting_for: String,
1073    pub increment_nonce: String,
1074}
1075
1076#[derive(GraphQLObject, Debug)]
1077pub struct GraphQLSetVerificationKeyPermissions {
1078    pub auth: String,
1079    pub txn_version: String,
1080}
1081
1082#[derive(GraphQLInputObject, Debug)]
1083pub struct InputGraphQLAccountUpdateUpdatePermissions {
1084    pub edit_state: String,
1085    pub access: String,
1086    pub send: String,
1087    pub receive: String,
1088    pub set_delegate: String,
1089    pub set_permissions: String,
1090    pub set_verification_key: InputGraphQLSetVerificationKeyPermissions,
1091    pub set_zkapp_uri: String,
1092    pub edit_action_state: String,
1093    pub set_token_symbol: String,
1094    pub set_timing: String,
1095    pub set_voting_for: String,
1096    pub increment_nonce: String,
1097}
1098
1099#[derive(GraphQLInputObject, Debug)]
1100pub struct InputGraphQLSetVerificationKeyPermissions {
1101    pub auth: String,
1102    pub txn_version: String,
1103}
1104
1105impl From<MinaBasePermissionsStableV2> for GraphQLAccountUpdateUpdatePermissions {
1106    fn from(value: MinaBasePermissionsStableV2) -> Self {
1107        Self {
1108            edit_state: value.edit_state.to_string(),
1109            access: value.access.to_string(),
1110            send: value.send.to_string(),
1111            receive: value.receive.to_string(),
1112            set_delegate: value.set_delegate.to_string(),
1113            set_permissions: value.set_permissions.to_string(),
1114            set_verification_key: GraphQLSetVerificationKeyPermissions {
1115                auth: value.set_verification_key.0.to_string(),
1116                txn_version: value.set_verification_key.1.as_u32().to_string(),
1117            },
1118            set_zkapp_uri: value.set_zkapp_uri.to_string(),
1119            edit_action_state: value.edit_action_state.to_string(),
1120            set_token_symbol: value.set_token_symbol.to_string(),
1121            set_timing: value.set_timing.to_string(),
1122            set_voting_for: value.set_voting_for.to_string(),
1123            increment_nonce: value.increment_nonce.to_string(),
1124        }
1125    }
1126}
1127
1128impl TryFrom<InputGraphQLAccountUpdateUpdatePermissions> for MinaBasePermissionsStableV2 {
1129    type Error = ConversionError;
1130    fn try_from(value: InputGraphQLAccountUpdateUpdatePermissions) -> Result<Self, Self::Error> {
1131        Ok(Self {
1132            edit_state: value.edit_state.parse()?,
1133            access: value.access.parse()?,
1134            send: value.send.parse()?,
1135            receive: value.receive.parse()?,
1136            set_delegate: value.set_delegate.parse()?,
1137            set_permissions: value.set_permissions.parse()?,
1138            set_verification_key: (
1139                value.set_verification_key.auth.parse()?,
1140                value
1141                    .set_verification_key
1142                    .txn_version
1143                    .parse::<u32>()?
1144                    .into(),
1145            ),
1146            set_zkapp_uri: value.set_zkapp_uri.parse()?,
1147            edit_action_state: value.edit_action_state.parse()?,
1148            set_token_symbol: value.set_token_symbol.parse()?,
1149            set_timing: value.set_timing.parse()?,
1150            set_voting_for: value.set_voting_for.parse()?,
1151            increment_nonce: value.increment_nonce.parse()?,
1152        })
1153    }
1154}
1155
1156#[derive(GraphQLObject, Debug)]
1157pub struct GraphQLBalanceChange {
1158    pub magnitude: String,
1159    pub sgn: String,
1160}
1161
1162#[derive(GraphQLInputObject, Debug)]
1163pub struct InputGraphQLBalanceChange {
1164    pub magnitude: String,
1165    pub sgn: String,
1166}
1167
1168#[derive(GraphQLObject, Debug)]
1169pub struct GraphQLFailureReason {
1170    pub index: String,
1171    pub failures: Vec<String>,
1172}
1173
1174impl From<MinaStateBlockchainStateValueStableV2SignedAmount> for GraphQLBalanceChange {
1175    fn from(value: MinaStateBlockchainStateValueStableV2SignedAmount) -> Self {
1176        Self {
1177            magnitude: value.magnitude.as_u64().to_string(),
1178            sgn: value.sgn.to_string(),
1179        }
1180    }
1181}
1182
1183impl TryFrom<InputGraphQLBalanceChange> for MinaStateBlockchainStateValueStableV2SignedAmount {
1184    type Error = ConversionError;
1185    fn try_from(value: InputGraphQLBalanceChange) -> Result<Self, Self::Error> {
1186        Ok(Self {
1187            magnitude: CurrencyAmountStableV1(value.magnitude.parse::<u64>()?.into()),
1188            sgn: value
1189                .sgn
1190                .parse()
1191                .map_err(|_| ConversionError::WrongVariant)?,
1192        })
1193    }
1194}
1195
1196impl From<MinaBaseAccountUpdatePreconditionsStableV1> for GraphQLPreconditions {
1197    fn from(value: MinaBaseAccountUpdatePreconditionsStableV1) -> Self {
1198        Self {
1199            network: GraphQLPreconditionsNetwork::from(value.network),
1200            account: GraphQLPreconditionsAccount::from(value.account),
1201            valid_while: if let MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(v) =
1202                value.valid_while
1203            {
1204                Some(GraphQLPreconditionsNetworkBounds {
1205                    upper: v.upper.as_u32().to_string(),
1206                    lower: v.lower.as_u32().to_string(),
1207                })
1208            } else {
1209                None
1210            },
1211        }
1212    }
1213}
1214
1215impl TryFrom<InputGraphQLPreconditions> for MinaBaseAccountUpdatePreconditionsStableV1 {
1216    type Error = ConversionError;
1217    fn try_from(value: InputGraphQLPreconditions) -> Result<Self, Self::Error> {
1218        Ok(Self {
1219            network: value.network.try_into()?,
1220            account: value.account.try_into()?,
1221            valid_while: if let Some(v) = value.valid_while {
1222                MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Check(
1223                    MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlotA {
1224                        upper: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1225                            (v.upper.parse::<u32>()?).into(),
1226                        ),
1227                        lower: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1228                            (v.lower.parse::<u32>()?).into(),
1229                        ),
1230                    },
1231                )
1232            } else {
1233                MinaBaseZkappPreconditionProtocolStateStableV1GlobalSlot::Ignore
1234            },
1235        })
1236    }
1237}
1238
1239impl TryFrom<MinaBaseVerificationKeyWireStableV1> for GraphQLVerificationKey {
1240    type Error = ConversionError;
1241
1242    fn try_from(value: MinaBaseVerificationKeyWireStableV1) -> Result<Self, Self::Error> {
1243        Ok(Self {
1244            data: value.to_base64()?,
1245            hash: VerificationKey::try_from(&value)
1246                .map_err(|_| ConversionError::InvalidBigInt)?
1247                .hash()
1248                .to_decimal(),
1249        })
1250    }
1251}
1252
1253impl TryFrom<InputGraphQLVerificationKey> for MinaBaseVerificationKeyWireStableV1 {
1254    type Error = ConversionError;
1255
1256    fn try_from(value: InputGraphQLVerificationKey) -> Result<Self, Self::Error> {
1257        Ok(Self::from_base64(&value.data)?)
1258    }
1259}
1260
1261impl TryFrom<MinaBaseAccountUpdateUpdateStableV1> for GraphQLAccountUpdateUpdate {
1262    type Error = ConversionError;
1263
1264    fn try_from(value: MinaBaseAccountUpdateUpdateStableV1) -> Result<Self, Self::Error> {
1265        Ok(Self {
1266            app_state: value
1267                .app_state
1268                .0
1269                .into_iter()
1270                .map(|v| {
1271                    if let MinaBaseAccountUpdateUpdateStableV1AppStateA::Set(value) = v {
1272                        Some(value.to_decimal())
1273                    } else {
1274                        None
1275                    }
1276                })
1277                .collect(),
1278            delegate: if let MinaBaseAccountUpdateUpdateStableV1Delegate::Set(v) = value.delegate {
1279                Some(v.to_string())
1280            } else {
1281                None
1282            },
1283            verification_key: if let MinaBaseAccountUpdateUpdateStableV1VerificationKey::Set(v) =
1284                value.verification_key
1285            {
1286                Some(GraphQLVerificationKey::try_from(*v)?)
1287            } else {
1288                None
1289            },
1290            permissions: if let MinaBaseAccountUpdateUpdateStableV1Permissions::Set(v) =
1291                value.permissions
1292            {
1293                Some(GraphQLAccountUpdateUpdatePermissions::from(*v))
1294            } else {
1295                None
1296            },
1297            zkapp_uri: if let MinaBaseAccountUpdateUpdateStableV1ZkappUri::Set(v) = value.zkapp_uri
1298            {
1299                Some(v.to_string())
1300            } else {
1301                None
1302            },
1303            token_symbol: if let MinaBaseAccountUpdateUpdateStableV1TokenSymbol::Set(v) =
1304                value.token_symbol
1305            {
1306                Some(v.to_string())
1307            } else {
1308                None
1309            },
1310            timing: if let MinaBaseAccountUpdateUpdateStableV1Timing::Set(v) = value.timing {
1311                Some(GraphQLTiming::from(*v))
1312            } else {
1313                None
1314            },
1315            voting_for: if let MinaBaseAccountUpdateUpdateStableV1VotingFor::Set(v) =
1316                value.voting_for
1317            {
1318                Some(v.to_string())
1319            } else {
1320                None
1321            },
1322        })
1323    }
1324}
1325
1326impl TryFrom<InputGraphQLAccountUpdateUpdate> for MinaBaseAccountUpdateUpdateStableV1 {
1327    type Error = ConversionError;
1328    fn try_from(value: InputGraphQLAccountUpdateUpdate) -> Result<Self, Self::Error> {
1329        let app_state: Vec<_> = value
1330            .app_state
1331            .iter()
1332            .map(|v| {
1333                if let Some(v) = v {
1334                    Ok(MinaBaseAccountUpdateUpdateStableV1AppStateA::Set(
1335                        BigInt::from_decimal(v)?,
1336                    ))
1337                } else {
1338                    Ok(MinaBaseAccountUpdateUpdateStableV1AppStateA::Keep)
1339                }
1340            })
1341            .collect::<Result<Vec<_>, ConversionError>>()?;
1342        Ok(Self {
1343            app_state: PaddedSeq(
1344                app_state
1345                    .try_into()
1346                    .map_err(|_| ConversionError::InvalidLength)?,
1347            ),
1348            delegate: if let Some(delegate) = value.delegate {
1349                MinaBaseAccountUpdateUpdateStableV1Delegate::Set(
1350                    AccountPublicKey::from_str(&delegate)?.into(),
1351                )
1352            } else {
1353                MinaBaseAccountUpdateUpdateStableV1Delegate::Keep
1354            },
1355            verification_key: if let Some(vk) = value.verification_key {
1356                MinaBaseAccountUpdateUpdateStableV1VerificationKey::Set(Box::new(
1357                    MinaBaseVerificationKeyWireStableV1::try_from(vk)?,
1358                ))
1359            } else {
1360                MinaBaseAccountUpdateUpdateStableV1VerificationKey::Keep
1361            },
1362            permissions: if let Some(permissions) = value.permissions {
1363                MinaBaseAccountUpdateUpdateStableV1Permissions::Set(Box::new(
1364                    MinaBasePermissionsStableV2::try_from(permissions)?,
1365                ))
1366            } else {
1367                MinaBaseAccountUpdateUpdateStableV1Permissions::Keep
1368            },
1369            zkapp_uri: if let Some(zkapp_uri) = value.zkapp_uri {
1370                MinaBaseAccountUpdateUpdateStableV1ZkappUri::Set(ZkAppUri::from(zkapp_uri.as_str()))
1371            } else {
1372                MinaBaseAccountUpdateUpdateStableV1ZkappUri::Keep
1373            },
1374            token_symbol: if let Some(token_symbol) = value.token_symbol {
1375                MinaBaseAccountUpdateUpdateStableV1TokenSymbol::Set(TokenSymbol::from(
1376                    token_symbol.as_str(),
1377                ))
1378            } else {
1379                MinaBaseAccountUpdateUpdateStableV1TokenSymbol::Keep
1380            },
1381            timing: if let Some(timing) = value.timing {
1382                MinaBaseAccountUpdateUpdateStableV1Timing::Set(Box::new(
1383                    MinaBaseAccountUpdateUpdateTimingInfoStableV1::try_from(timing)?,
1384                ))
1385            } else {
1386                MinaBaseAccountUpdateUpdateStableV1Timing::Keep
1387            },
1388            voting_for: if let Some(voting_for) = value.voting_for {
1389                MinaBaseAccountUpdateUpdateStableV1VotingFor::Set(StateHash::from_str(&voting_for)?)
1390            } else {
1391                MinaBaseAccountUpdateUpdateStableV1VotingFor::Keep
1392            },
1393        })
1394    }
1395}
1396
1397impl From<MinaBaseAccountUpdateFeePayerStableV1> for GraphQLFeePayer {
1398    fn from(value: MinaBaseAccountUpdateFeePayerStableV1) -> Self {
1399        Self {
1400            authorization: value.authorization.to_string(),
1401            body: GraphQLFeePayerBody {
1402                public_key: value.body.public_key.to_string(),
1403                fee: value.body.fee.as_u64().to_string(),
1404                valid_until: value.body.valid_until.map(|v| v.as_u32().to_string()),
1405                nonce: value.body.nonce.to_string(),
1406            },
1407        }
1408    }
1409}
1410
1411impl TryFrom<InputGraphQLFeePayer> for MinaBaseAccountUpdateFeePayerStableV1 {
1412    type Error = ConversionError;
1413
1414    fn try_from(value: InputGraphQLFeePayer) -> Result<Self, Self::Error> {
1415        Ok(Self {
1416            authorization: value.authorization.parse()?,
1417            body: MinaBaseAccountUpdateBodyFeePayerStableV1 {
1418                public_key: value.body.public_key.parse()?,
1419                fee: CurrencyFeeStableV1(value.body.fee.parse::<u64>()?.into()),
1420                valid_until: value
1421                    .body
1422                    .valid_until
1423                    .map(|v| -> Result<_, ConversionError> {
1424                        Ok(MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(
1425                            v.parse::<u32>()?.into(),
1426                        ))
1427                    })
1428                    .transpose()?,
1429                nonce: value.body.nonce.parse::<u32>()?.into(),
1430            },
1431        })
1432    }
1433}
1434
1435impl TryFrom<MinaBaseAccountUpdateTStableV1> for GraphQLAccountUpdate {
1436    type Error = ConversionError;
1437
1438    fn try_from(value: MinaBaseAccountUpdateTStableV1) -> Result<Self, Self::Error> {
1439        Ok(Self {
1440            body: GraphQLAccountUpdateBody {
1441                public_key: value.body.public_key.to_string(),
1442                token_id: value.body.token_id.to_string(),
1443                use_full_commitment: value.body.use_full_commitment,
1444                increment_nonce: value.body.increment_nonce,
1445                update: GraphQLAccountUpdateUpdate::try_from(value.body.update)?,
1446                balance_change: GraphQLBalanceChange::from(value.body.balance_change),
1447                events: value
1448                    .body
1449                    .events
1450                    .0
1451                    .into_iter()
1452                    .map(|v| v.into_iter().map(|i| i.to_decimal()).collect())
1453                    .collect(),
1454                actions: value
1455                    .body
1456                    .actions
1457                    .0
1458                    .into_iter()
1459                    .map(|v| v.into_iter().map(|i| i.to_decimal()).collect())
1460                    .collect(),
1461                call_data: value.body.call_data.to_decimal(),
1462                // TODO(adonagy): figure out call depth
1463                call_depth: 0,
1464                preconditions: GraphQLPreconditions::from(value.body.preconditions),
1465                may_use_token: GraphQLMayUseToken::from(value.body.may_use_token),
1466                authorization_kind: GraphQLAuthorizationKind::from(value.body.authorization_kind),
1467                implicit_account_creation_fee: value.body.implicit_account_creation_fee,
1468            },
1469            authorization: GraphQLAuthorization::try_from(value.authorization)?,
1470        })
1471    }
1472}
1473
1474impl TryFrom<InputGraphQLAccountUpdate> for MinaBaseAccountUpdateTStableV1 {
1475    type Error = ConversionError;
1476
1477    fn try_from(value: InputGraphQLAccountUpdate) -> Result<Self, Self::Error> {
1478        Ok(Self {
1479            body: MinaBaseAccountUpdateBodyStableV1 {
1480                public_key: value.body.public_key.parse()?,
1481                token_id: value.body.token_id.parse()?,
1482                update: value.body.update.try_into()?,
1483                balance_change: value.body.balance_change.try_into()?,
1484                increment_nonce: value.body.increment_nonce,
1485                events: MinaBaseAccountUpdateBodyEventsStableV1(
1486                    value
1487                        .body
1488                        .events
1489                        .into_iter()
1490                        .map(|v| {
1491                            v.into_iter()
1492                                .map(|i| BigInt::from_decimal(&i).map_err(ConversionError::from))
1493                                .collect::<Result<_, _>>()
1494                        })
1495                        .collect::<Result<_, _>>()?,
1496                ),
1497                actions: MinaBaseAccountUpdateBodyEventsStableV1(
1498                    value
1499                        .body
1500                        .actions
1501                        .into_iter()
1502                        .map(|v| {
1503                            v.into_iter()
1504                                .map(|i| BigInt::from_decimal(&i).map_err(ConversionError::from))
1505                                .collect::<Result<_, _>>()
1506                        })
1507                        .collect::<Result<_, _>>()?,
1508                ),
1509                call_data: BigInt::from_decimal(&value.body.call_data)?,
1510                preconditions: value.body.preconditions.try_into()?,
1511                use_full_commitment: value.body.use_full_commitment,
1512                implicit_account_creation_fee: value.body.implicit_account_creation_fee,
1513                may_use_token: value.body.may_use_token.into(),
1514                authorization_kind: value.body.authorization_kind.try_into()?,
1515            },
1516            authorization: value.authorization.try_into()?,
1517        })
1518    }
1519}
1520
1521impl TryFrom<InputGraphQLTiming> for MinaBaseAccountUpdateUpdateTimingInfoStableV1 {
1522    type Error = ConversionError;
1523
1524    fn try_from(value: InputGraphQLTiming) -> Result<Self, Self::Error> {
1525        let cliff_time: u32 = value.cliff_time.try_into()?;
1526        let vesting_period: u32 = value.vesting_period.try_into()?;
1527        Ok(Self {
1528            initial_minimum_balance: CurrencyBalanceStableV1(CurrencyAmountStableV1(
1529                value.initial_minimum_balance.parse::<u64>()?.into(),
1530            )),
1531            cliff_time: MinaNumbersGlobalSlotSinceGenesisMStableV1::SinceGenesis(cliff_time.into()),
1532            cliff_amount: CurrencyAmountStableV1(value.cliff_amount.parse::<u64>()?.into()),
1533            vesting_period: MinaNumbersGlobalSlotSpanStableV1::GlobalSlotSpan(
1534                vesting_period.into(),
1535            ),
1536            vesting_increment: CurrencyAmountStableV1(
1537                value.vesting_increment.parse::<u64>()?.into(),
1538            ),
1539        })
1540    }
1541}
1542
1543#[cfg(test)]
1544mod test {
1545    use std::str::FromStr;
1546
1547    use mina_p2p_messages::{
1548        binprot::BinProtRead,
1549        v2::{
1550            MinaBaseSignedCommandMemoStableV1, MinaBaseUserCommandStableV2,
1551            MinaBaseZkappCommandTStableV1WireStableV1,
1552        },
1553    };
1554
1555    use super::*;
1556
1557    #[test]
1558    fn test_empty_memo() {
1559        use ledger::scan_state::transaction_logic::Memo;
1560
1561        let expected = "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH";
1562        let empty_memo = Memo::from_str("").unwrap();
1563        let mina_empty_memo = MinaBaseSignedCommandMemoStableV1::from(&empty_memo);
1564        assert_eq!(mina_empty_memo.to_base58check(), expected);
1565        let empty_memo = Memo::empty();
1566        let mina_empty_memo = MinaBaseSignedCommandMemoStableV1::from(&empty_memo);
1567        assert_eq!(mina_empty_memo.to_base58check(), expected);
1568    }
1569
1570    #[test]
1571    fn test_parse_zkapp_bug_1464_no_proof_nor_signature() {
1572        let input = create_input_graphql_zkapp_bug_1464();
1573        let _converted: MinaBaseUserCommandStableV2 = input
1574            .zkapp_command
1575            .try_into()
1576            .expect("Failed to parse input");
1577    }
1578
1579    #[test]
1580    fn test_zkapp_from_input() {
1581        let bytes = include_bytes!("../../../../tests/files/zkapps/valid_zkapp.bin");
1582        let zkapp =
1583            MinaBaseZkappCommandTStableV1WireStableV1::binprot_read(&mut bytes.as_slice()).unwrap();
1584
1585        let serialized_valid = serde_json::to_string_pretty(&zkapp).unwrap();
1586
1587        std::fs::write("zkapp_valid.json", &serialized_valid).unwrap();
1588
1589        let from_input = create_input_graphql_zkapp();
1590        let converted: MinaBaseUserCommandStableV2 = from_input.zkapp_command.try_into().unwrap();
1591        if let MinaBaseUserCommandStableV2::ZkappCommand(zkapp_cmd) = converted {
1592            let serialized_converted = serde_json::to_string_pretty(&zkapp_cmd).unwrap();
1593            std::fs::write("zkapp_converted.json", &serialized_converted).unwrap();
1594            assert_eq!(serialized_valid, serialized_converted);
1595        } else {
1596            unreachable!()
1597        }
1598    }
1599
1600    #[test]
1601    fn test_authorization_kind() {
1602        let kind = InputGraphQLAuthorizationKind {
1603            is_signed: false,
1604            is_proved: true,
1605            verification_key_hash: Some(
1606                "19951435866906059835892103359374709356309230417850637795098911039647240505427"
1607                    .to_string(),
1608            ),
1609        };
1610        let converted: Result<MinaBaseAccountUpdateAuthorizationKindStableV1, ConversionError> =
1611            kind.try_into();
1612
1613        assert!(converted.is_ok());
1614    }
1615
1616    #[test]
1617    fn test_authorization_proof() {
1618        let proof = InputGraphQLAuthorization {
1619            signature: None,
1620            proof: Some(
1621                include_str!("../../../../tests/files/zkapps/proof_string.txt").to_string(),
1622            ),
1623        };
1624        let converted: Result<MinaBaseControlStableV2, _> = proof.try_into();
1625        assert!(converted.is_ok());
1626
1627        let proof = InputGraphQLAuthorization {
1628            signature: None,
1629            proof: None,
1630        };
1631        let converted: MinaBaseControlStableV2 =
1632            proof.try_into().expect("Error parsing None given auth");
1633
1634        assert_eq!(converted, MinaBaseControlStableV2::NoneGiven);
1635    }
1636
1637    fn create_input_graphql_zkapp() -> InputGraphQLZkapp {
1638        InputGraphQLZkapp {
1639            zkapp_command: InputGraphQLZkappCommand {
1640                memo: Some("E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH".to_string()),
1641                fee_payer: InputGraphQLFeePayer {
1642                    body: InputGraphQLFeePayerBody {
1643                        public_key: "B62qpD75xH5R19wxZG2uz8whNsHPTioVoYcPV3zfjjSbzTmaHQHKKEV".to_string(),
1644                        fee: "117000000".to_string(),
1645                        valid_until: None,
1646                        nonce: "1128".to_string(),
1647                    },
1648                    authorization: "7mX5Lwu2bdnJPc4DJu7CkwTSR5behoKH8yZh7myCGgYfib5Sq3dfgPQY6LcXdrpQma1NvoLC5i7HLFEQZTnkBFcn96TP57JF".to_string(),
1649                },
1650                account_updates: vec![
1651                    InputGraphQLAccountUpdate {
1652                        body: InputGraphQLAccountUpdateBody {
1653                            call_depth: 0,
1654                            public_key: "B62qpD75xH5R19wxZG2uz8whNsHPTioVoYcPV3zfjjSbzTmaHQHKKEV".to_string(),
1655                            token_id: "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf".to_string(),
1656                            update: InputGraphQLAccountUpdateUpdate {
1657                                app_state: vec![
1658                                    None,
1659                                    None,
1660                                    None,
1661                                    None,
1662                                    None,
1663                                    None,
1664                                    None,
1665                                    None,
1666                                ],
1667                                delegate: None,
1668                                verification_key: None,
1669                                permissions: None,
1670                                zkapp_uri: None,
1671                                token_symbol: None,
1672                                timing: None,
1673                                voting_for: None,
1674                            },
1675                            balance_change: InputGraphQLBalanceChange {
1676                                magnitude: "1000000000".to_string(),
1677                                sgn: "Negative".to_string(),
1678                            },
1679                            increment_nonce: false,
1680                            events: vec![],
1681                            actions: vec![],
1682                            call_data: "0".to_string(),
1683                            preconditions: InputGraphQLPreconditions {
1684                                network: InputGraphQLPreconditionsNetwork {
1685                                    snarked_ledger_hash: None,
1686                                    blockchain_length: None,
1687                                    min_window_density: None,
1688                                    total_currency: None,
1689                                    global_slot_since_genesis: None,
1690                                    staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1691                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1692                                            hash: None,
1693                                            total_currency: None,
1694                                        },
1695                                        seed: None,
1696                                        start_checkpoint: None,
1697                                        lock_checkpoint: None,
1698                                        epoch_length: None,
1699                                    },
1700                                    next_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1701                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1702                                            hash: None,
1703                                            total_currency: None,
1704                                        },
1705                                        seed: None,
1706                                        start_checkpoint: None,
1707                                        lock_checkpoint: None,
1708                                        epoch_length: None,
1709                                    },
1710                                },
1711                                account: InputGraphQLPreconditionsAccount {
1712                                    balance: None,
1713                                    nonce: None,
1714                                    receipt_chain_hash: None,
1715                                    delegate: None,
1716                                    state: vec![
1717                                        None, None, None, None, None, None, None, None
1718                                    ],
1719                                    action_state: None,
1720                                    proved_state: None,
1721                                    is_new: None,
1722                                },
1723                                valid_while: None,
1724                            },
1725                            use_full_commitment: true,
1726                            implicit_account_creation_fee: false,
1727                            may_use_token: InputGraphQLMayUseToken {
1728                                parents_own_token: false,
1729                                inherit_from_parent: false,
1730                            },
1731                            authorization_kind: InputGraphQLAuthorizationKind {
1732                                is_signed: true,
1733                                is_proved: false,
1734                                verification_key_hash: None,
1735                            },
1736                        },
1737                        authorization: InputGraphQLAuthorization {
1738                            proof: None,
1739                            signature: Some("7mX5Lwu2bdnJPc4DJu7CkwTSR5behoKH8yZh7myCGgYfib5Sq3dfgPQY6LcXdrpQma1NvoLC5i7HLFEQZTnkBFcn96TP57JF".to_string()),
1740                        },
1741                    },
1742                    InputGraphQLAccountUpdate {
1743                        body: InputGraphQLAccountUpdateBody {
1744                            call_depth: 0,
1745                            public_key: "B62qqKAQh8M61uvuw3tjJsmRgsEvzRm84Nc9MwXTF3zoqFRZ86rV8qk".to_string(),
1746                            token_id: "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf".to_string(),
1747                            update: InputGraphQLAccountUpdateUpdate {
1748                                app_state: vec![
1749                                    Some("1".to_string()),
1750                                    Some("0".to_string()),
1751                                    Some("0".to_string()),
1752                                    Some("0".to_string()),
1753                                    Some("0".to_string()),
1754                                    Some("0".to_string()),
1755                                    Some("0".to_string()),
1756                                    Some("0".to_string()),
1757                                ],
1758                                delegate: None,
1759                                verification_key: Some(InputGraphQLVerificationKey {
1760                                    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(),
1761                                    hash: "11640126627177324946637007967436400725357874055180801746732941023691529117236".to_string(),
1762                                }),
1763                                permissions: Some(InputGraphQLAccountUpdateUpdatePermissions {
1764                                    edit_state: "Proof".to_string(),
1765                                    access: "Proof".to_string(),
1766                                    send: "Proof".to_string(),
1767                                    receive: "Proof".to_string(),
1768                                    set_delegate: "Proof".to_string(),
1769                                    set_permissions: "Proof".to_string(),
1770                                    set_verification_key: InputGraphQLSetVerificationKeyPermissions {
1771                                        auth: "Proof".to_string(),
1772                                        txn_version: "3".to_string(),
1773                                    },
1774                                    set_zkapp_uri: "Proof".to_string(),
1775                                    edit_action_state: "Proof".to_string(),
1776                                    set_token_symbol: "Proof".to_string(),
1777                                    set_timing: "Proof".to_string(),
1778                                    set_voting_for: "Proof".to_string(),
1779                                    increment_nonce: "Proof".to_string(),
1780                                }),
1781                                zkapp_uri: None,
1782                                token_symbol: None,
1783                                timing: None,
1784                                voting_for: None,
1785                            },
1786                            balance_change: InputGraphQLBalanceChange {
1787                                magnitude: "0".to_string(),
1788                                sgn: "Positive".to_string(),
1789                            },
1790                            increment_nonce: true,
1791                            events: vec![],
1792                            actions: vec![],
1793                            call_data: "0".to_string(),
1794                            preconditions: InputGraphQLPreconditions {
1795                                network: InputGraphQLPreconditionsNetwork {
1796                                    snarked_ledger_hash: None,
1797                                    blockchain_length: None,
1798                                    min_window_density: None,
1799                                    total_currency: None,
1800                                    global_slot_since_genesis: None,
1801                                    staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1802                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1803                                            hash: None,
1804                                            total_currency: None,
1805                                        },
1806                                        seed: None,
1807                                        start_checkpoint: None,
1808                                        lock_checkpoint: None,
1809                                        epoch_length: None,
1810                                    },
1811                                    next_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1812                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1813                                            hash: None,
1814                                            total_currency: None,
1815                                        },
1816                                        seed: None,
1817                                        start_checkpoint: None,
1818                                        lock_checkpoint: None,
1819                                        epoch_length: None,
1820                                    },
1821                                },
1822                                account: InputGraphQLPreconditionsAccount {
1823                                    balance: None,
1824                                    nonce: Some(InputGraphQLPreconditionsNetworkBounds {
1825                                        upper: "0".to_string(),
1826                                        lower: "0".to_string(),
1827                                    }),
1828                                    receipt_chain_hash: None,
1829                                    delegate: None,
1830                                    state: vec![
1831                                        None, None, None, None, None, None, None, None
1832                                    ],
1833                                    action_state: None,
1834                                    proved_state: Some(false),
1835                                    is_new: None,
1836                                },
1837                                valid_while: None,
1838                            },
1839                            use_full_commitment: false,
1840                            implicit_account_creation_fee: false,
1841                            may_use_token: InputGraphQLMayUseToken {
1842                                parents_own_token: false,
1843                                inherit_from_parent: false,
1844                            },
1845                            authorization_kind: InputGraphQLAuthorizationKind {
1846                                is_signed: true,
1847                                is_proved: false,
1848                                verification_key_hash: None,
1849                            },
1850                        },
1851                        authorization: InputGraphQLAuthorization {
1852                            proof: None,
1853                            signature: Some("7mXFnDxZBE5iXBfw9LRPXST3sSodXAdTJSWFqX3hBoDA3wv5s2s9TLMDCXgatMvMH4bDttAFyJuezWmbSA81FXeMFZgqcxtt".to_string()),
1854                        },
1855                    },
1856                ],
1857            },
1858        }
1859    }
1860
1861    fn create_input_graphql_zkapp_bug_1464() -> InputGraphQLZkapp {
1862        InputGraphQLZkapp {
1863            zkapp_command: InputGraphQLZkappCommand {
1864                memo: Some("E4YdMZb5VHHE51HPFPs1zUHnyus1q7RW61tWq1F4FNYrp5FKtKZMh".to_string()),
1865                fee_payer: InputGraphQLFeePayer {
1866                    body: InputGraphQLFeePayerBody {
1867                        public_key: "B62qmGcEhZsZ2EMh2EzRXDJEmaD9PUJcW5xdNq2im2xNVuX2bsEPjoj".to_string(),
1868                        fee: "200000000".to_string(),
1869                        valid_until: None,
1870                        nonce: "250".to_string(),
1871                    },
1872                    authorization: "7mXMa44TWfDGtQmsfGtkRogZVzGVYqosP6qkXCBApsjoZ2ye2Y5AL2VWzp7m5CxkTjZhcoqtDVJkiQRm38tAmQdhpTTsSEr6".to_string(),
1873                },
1874                account_updates: vec![
1875                    InputGraphQLAccountUpdate {
1876                        body: InputGraphQLAccountUpdateBody {
1877                            call_depth: 0,
1878                            public_key: "B62qmGcEhZsZ2EMh2EzRXDJEmaD9PUJcW5xdNq2im2xNVuX2bsEPjoj".to_string(),
1879                            token_id: "wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf".to_string(),
1880                            update: InputGraphQLAccountUpdateUpdate {
1881                                app_state: vec![
1882                                    None,
1883                                    None,
1884                                    None,
1885                                    None,
1886                                    None,
1887                                    None,
1888                                    None,
1889                                    None,
1890                                ],
1891                                delegate: None,
1892                                verification_key: None,
1893                                permissions: None,
1894                                zkapp_uri: None,
1895                                token_symbol: None,
1896                                timing: None,
1897                                voting_for: None,
1898                            },
1899                            balance_change: InputGraphQLBalanceChange {
1900                                magnitude: "0".to_string(),
1901                                sgn: "Positive".to_string(),
1902                            },
1903                            increment_nonce: false,
1904                            events: vec![vec![
1905                        "852".to_owned(),
1906                        "993".to_owned(),
1907                        "540".to_owned(),
1908                        "951".to_owned(),
1909                        "340".to_owned()
1910                            ]],
1911                            actions: vec![],
1912                            call_data: "0".to_string(),
1913                            preconditions: InputGraphQLPreconditions {
1914                                network: InputGraphQLPreconditionsNetwork {
1915                                    snarked_ledger_hash: None,
1916                                    blockchain_length: None,
1917                                    min_window_density: None,
1918                                    total_currency: None,
1919                                    global_slot_since_genesis: None,
1920                                    staking_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1921                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1922                                            hash: None,
1923                                            total_currency: None,
1924                                        },
1925                                        seed: None,
1926                                        start_checkpoint: None,
1927                                        lock_checkpoint: None,
1928                                        epoch_length: None,
1929                                    },
1930                                    next_epoch_data: InputGraphQLPreconditionsNetworkEpochData {
1931                                        ledger: InputGraphQLPreconditionsNetworkLedger {
1932                                            hash: None,
1933                                            total_currency: None,
1934                                        },
1935                                        seed: None,
1936                                        start_checkpoint: None,
1937                                        lock_checkpoint: None,
1938                                        epoch_length: None,
1939                                    },
1940                                },
1941                                account: InputGraphQLPreconditionsAccount {
1942                                    balance: None,
1943                                    nonce: None,
1944                                    receipt_chain_hash: None,
1945                                    delegate: None,
1946                                    state: vec![
1947                                        None, None, None, None, None, None, None, None
1948                                    ],
1949                                    action_state: None,
1950                                    proved_state: None,
1951                                    is_new: None,
1952                                },
1953                                valid_while: None,
1954                            },
1955                            use_full_commitment: false,
1956                            implicit_account_creation_fee: false,
1957                            may_use_token: InputGraphQLMayUseToken {
1958                                parents_own_token: false,
1959                                inherit_from_parent: false,
1960                            },
1961                            authorization_kind: InputGraphQLAuthorizationKind {
1962                                is_signed: false,
1963                                is_proved: false,
1964                                verification_key_hash: Some("3392518251768960475377392625298437850623664973002200885669375116181514017494".parse().unwrap()),
1965                            },
1966                        },
1967                        authorization: InputGraphQLAuthorization {
1968                            proof: None,
1969                            signature: None
1970                        },
1971                    },
1972                ],
1973            },
1974        }
1975    }
1976
1977    #[test]
1978    pub fn test_bigint_to_decimal() {
1979        let bigint = BigInt::from_decimal("1").unwrap();
1980        let decimal = serde_json::to_string(&bigint).unwrap();
1981        assert_eq!(
1982            decimal,
1983            "\"0x0000000000000000000000000000000000000000000000000000000000000001\"".to_string()
1984        );
1985    }
1986}