mina_tree/account/
conv.rs

1#![allow(clippy::type_complexity)]
2
3use super::{Account, AccountId, AuthRequired, TokenId, VerificationKeyWire};
4use crate::{
5    proofs::{
6        field::FieldWitness,
7        transaction::{make_group, InnerCurve, PlonkVerificationKeyEvals},
8    },
9    scan_state::currency::{Amount, Balance, Nonce, Slot, SlotSpan, TxnVersion},
10    AccountIndex, Permissions, ProofVerified, ReceiptChainHash, SetVerificationKey, Timing,
11    TokenSymbol, VerificationKey, VotingFor, ZkAppAccount,
12};
13use ark_ec::short_weierstrass::Affine;
14use ark_ff::{Field, PrimeField};
15use mina_curves::pasta::Fp;
16use mina_p2p_messages::{
17    bigint::{BigInt, InvalidBigInt},
18    binprot,
19    pseq::PaddedSeq,
20    v2::{
21        self, MinaBaseAccountBinableArgStableV2, MinaBaseAccountIdDigestStableV1,
22        MinaBaseAccountIdStableV2, MinaBaseAccountIndexStableV1, MinaBaseAccountTimingStableV2,
23        MinaBasePermissionsAuthRequiredStableV2, MinaBasePermissionsStableV2,
24        MinaBaseReceiptChainHashStableV1, MinaBaseVerificationKeyWireStableV1,
25        MinaBaseVerificationKeyWireStableV1WrapIndex, NonZeroCurvePointUncompressedStableV1,
26        PicklesBaseProofsVerifiedStableV1, TokenIdKeyHash,
27    },
28};
29
30impl binprot::BinProtRead for TokenId {
31    fn binprot_read<R: std::io::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error>
32    where
33        Self: Sized,
34    {
35        let token_id = TokenIdKeyHash::binprot_read(r)?;
36        let token_id: MinaBaseAccountIdDigestStableV1 = token_id.into_inner();
37        token_id
38            .try_into()
39            .map_err(|e| binprot::Error::CustomError(Box::new(e)))
40    }
41}
42
43impl binprot::BinProtWrite for TokenId {
44    fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
45        let token_id: MinaBaseAccountIdDigestStableV1 = self.clone().into();
46        let token_id: TokenIdKeyHash = token_id.into();
47        token_id.binprot_write(w)?;
48        Ok(())
49    }
50}
51
52impl From<TokenId> for TokenIdKeyHash {
53    fn from(value: TokenId) -> Self {
54        MinaBaseAccountIdDigestStableV1(value.0.into()).into()
55    }
56}
57
58impl From<TokenIdKeyHash> for TokenId {
59    fn from(value: TokenIdKeyHash) -> Self {
60        value.inner().try_into().unwrap()
61    }
62}
63
64impl<F: FieldWitness> TryFrom<(BigInt, BigInt)> for InnerCurve<F>
65where
66    F: Field + From<BigInt>,
67{
68    type Error = InvalidBigInt;
69
70    fn try_from((x, y): (BigInt, BigInt)) -> Result<Self, Self::Error> {
71        Ok(Self::of_affine(make_group::<F>(
72            x.to_field()?,
73            y.to_field()?,
74        )))
75    }
76}
77
78impl<F: FieldWitness> From<InnerCurve<F>> for (BigInt, BigInt)
79where
80    F: Field + Into<BigInt>,
81{
82    fn from(fps: InnerCurve<F>) -> Self {
83        let Affine { x, y, .. } = fps.to_affine();
84        (x.into(), y.into())
85    }
86}
87
88impl<F: FieldWitness> TryFrom<&(BigInt, BigInt)> for InnerCurve<F>
89where
90    F: Field,
91{
92    type Error = InvalidBigInt;
93
94    fn try_from((x, y): &(BigInt, BigInt)) -> Result<Self, Self::Error> {
95        Ok(Self::of_affine(make_group::<F>(
96            x.to_field()?,
97            y.to_field()?,
98        )))
99    }
100}
101
102impl<F: FieldWitness> From<&InnerCurve<F>> for (BigInt, BigInt)
103where
104    F: Field + Into<BigInt>,
105{
106    fn from(fps: &InnerCurve<F>) -> Self {
107        let Affine { x, y, .. } = fps.to_affine();
108        (x.into(), y.into())
109    }
110}
111
112impl binprot::BinProtRead for AccountId {
113    fn binprot_read<R: std::io::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error>
114    where
115        Self: Sized,
116    {
117        let account_id = MinaBaseAccountIdStableV2::binprot_read(r)?;
118        account_id
119            .try_into()
120            .map_err(|e| binprot::Error::CustomError(Box::new(e)))
121    }
122}
123
124impl binprot::BinProtWrite for AccountId {
125    fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
126        let account_id: MinaBaseAccountIdStableV2 = self.clone().into();
127        account_id.binprot_write(w)?;
128        Ok(())
129    }
130}
131
132pub fn array_into<'a, T, U, const N: usize>(value: &'a [T; N]) -> [U; N]
133where
134    T: 'a,
135    U: From<&'a T>,
136{
137    value.each_ref().map(|value| U::from(value))
138}
139
140pub fn array_into_with<'a, T, U, F, const N: usize>(value: &'a [T; N], fun: F) -> [U; N]
141where
142    T: 'a,
143    F: Fn(&T) -> U,
144{
145    value.each_ref().map(fun)
146}
147
148/// Note: Refactor when `core::array::try_map` is stable
149/// <https://github.com/rust-lang/rust/issues/79711>
150pub fn try_array_into_with<'a, T, E, U, F, const N: usize>(
151    value: &'a [T; N],
152    fun: F,
153) -> Result<[U; N], E>
154where
155    T: 'a,
156    F: Fn(&T) -> Result<U, E>,
157    U: std::fmt::Debug,
158{
159    Ok(value
160        .iter()
161        .map(fun)
162        .collect::<Result<Vec<_>, _>>()?
163        .try_into()
164        .unwrap()) // Never fail: `value` contains `N` elements
165}
166
167impl TryFrom<&MinaBaseVerificationKeyWireStableV1> for VerificationKey {
168    type Error = InvalidBigInt;
169
170    fn try_from(vk: &MinaBaseVerificationKeyWireStableV1) -> Result<Self, Self::Error> {
171        let MinaBaseVerificationKeyWireStableV1 {
172            max_proofs_verified,
173            actual_wrap_domain_size,
174            wrap_index,
175        } = vk;
176
177        Ok(VerificationKey {
178            max_proofs_verified: match max_proofs_verified {
179                PicklesBaseProofsVerifiedStableV1::N0 => ProofVerified::N0,
180                PicklesBaseProofsVerifiedStableV1::N1 => ProofVerified::N1,
181                PicklesBaseProofsVerifiedStableV1::N2 => ProofVerified::N2,
182            },
183            actual_wrap_domain_size: match actual_wrap_domain_size {
184                PicklesBaseProofsVerifiedStableV1::N0 => ProofVerified::N0,
185                PicklesBaseProofsVerifiedStableV1::N1 => ProofVerified::N1,
186                PicklesBaseProofsVerifiedStableV1::N2 => ProofVerified::N2,
187            },
188            wrap_index: Box::new(wrap_index.try_into()?),
189            wrap_vk: None,
190        })
191    }
192}
193
194impl TryFrom<&MinaBaseVerificationKeyWireStableV1WrapIndex> for PlonkVerificationKeyEvals<Fp> {
195    type Error = InvalidBigInt;
196
197    fn try_from(value: &MinaBaseVerificationKeyWireStableV1WrapIndex) -> Result<Self, Self::Error> {
198        let MinaBaseVerificationKeyWireStableV1WrapIndex {
199            sigma_comm,
200            coefficients_comm,
201            generic_comm,
202            psm_comm,
203            complete_add_comm,
204            mul_comm,
205            emul_comm,
206            endomul_scalar_comm,
207        } = value;
208
209        let sigma = try_array_into_with(sigma_comm, |s| s.try_into())?;
210        let coefficients = try_array_into_with(coefficients_comm, |s| s.try_into())?;
211
212        Ok(PlonkVerificationKeyEvals {
213            sigma,
214            coefficients,
215            generic: generic_comm.try_into()?,
216            psm: psm_comm.try_into()?,
217            complete_add: complete_add_comm.try_into()?,
218            mul: mul_comm.try_into()?,
219            emul: emul_comm.try_into()?,
220            endomul_scalar: endomul_scalar_comm.try_into()?,
221        })
222    }
223}
224impl TryFrom<MinaBaseVerificationKeyWireStableV1WrapIndex> for PlonkVerificationKeyEvals<Fp> {
225    type Error = InvalidBigInt;
226
227    fn try_from(value: MinaBaseVerificationKeyWireStableV1WrapIndex) -> Result<Self, Self::Error> {
228        (&value).try_into()
229    }
230}
231
232impl From<&VerificationKey> for MinaBaseVerificationKeyWireStableV1 {
233    fn from(vk: &VerificationKey) -> Self {
234        let VerificationKey {
235            max_proofs_verified,
236            actual_wrap_domain_size,
237            wrap_index,
238            wrap_vk: _, // Unused
239        } = vk;
240
241        Self {
242            max_proofs_verified: match max_proofs_verified {
243                super::ProofVerified::N0 => PicklesBaseProofsVerifiedStableV1::N0,
244                super::ProofVerified::N1 => PicklesBaseProofsVerifiedStableV1::N1,
245                super::ProofVerified::N2 => PicklesBaseProofsVerifiedStableV1::N2,
246            },
247            actual_wrap_domain_size: match actual_wrap_domain_size {
248                super::ProofVerified::N0 => PicklesBaseProofsVerifiedStableV1::N0,
249                super::ProofVerified::N1 => PicklesBaseProofsVerifiedStableV1::N1,
250                super::ProofVerified::N2 => PicklesBaseProofsVerifiedStableV1::N2,
251            },
252            wrap_index: wrap_index.as_ref().into(),
253        }
254    }
255}
256
257impl From<&MinaBaseAccountTimingStableV2> for Timing {
258    fn from(timing: &MinaBaseAccountTimingStableV2) -> Self {
259        match timing {
260            MinaBaseAccountTimingStableV2::Untimed => Timing::Untimed,
261            MinaBaseAccountTimingStableV2::Timed {
262                initial_minimum_balance,
263                cliff_time,
264                cliff_amount,
265                vesting_period,
266                vesting_increment,
267            } => Timing::Timed {
268                initial_minimum_balance: Balance::from_u64(initial_minimum_balance.as_u64()),
269                cliff_time: Slot::from_u32(cliff_time.as_u32()),
270                cliff_amount: Amount::from_u64(cliff_amount.as_u64()),
271                vesting_period: SlotSpan::from_u32(vesting_period.as_u32()),
272                vesting_increment: Amount::from_u64(vesting_increment.as_u64()),
273            },
274        }
275    }
276}
277
278impl From<&Timing> for MinaBaseAccountTimingStableV2 {
279    fn from(timing: &Timing) -> Self {
280        use mina_p2p_messages::v2::*;
281
282        match timing {
283            super::Timing::Untimed => MinaBaseAccountTimingStableV2::Untimed,
284            super::Timing::Timed {
285                initial_minimum_balance,
286                cliff_time,
287                cliff_amount,
288                vesting_period,
289                vesting_increment,
290            } => MinaBaseAccountTimingStableV2::Timed {
291                initial_minimum_balance: CurrencyBalanceStableV1(CurrencyAmountStableV1(
292                    UnsignedExtendedUInt64Int64ForVersionTagsStableV1(
293                        initial_minimum_balance.as_u64().into(),
294                    ),
295                )),
296                cliff_time: cliff_time.into(),
297                cliff_amount: CurrencyAmountStableV1(
298                    UnsignedExtendedUInt64Int64ForVersionTagsStableV1(cliff_amount.as_u64().into()),
299                ),
300                vesting_period: vesting_period.into(),
301                vesting_increment: CurrencyAmountStableV1(
302                    UnsignedExtendedUInt64Int64ForVersionTagsStableV1(
303                        vesting_increment.as_u64().into(),
304                    ),
305                ),
306            },
307        }
308    }
309}
310
311impl From<&Account> for mina_p2p_messages::v2::MinaBaseAccountBinableArgStableV2 {
312    fn from(acc: &Account) -> Self {
313        use mina_p2p_messages::v2::*;
314
315        Self {
316            public_key: (&acc.public_key).into(),
317            token_id: (&acc.token_id).into(),
318            token_symbol: acc.token_symbol.as_bytes().into(),
319            balance: CurrencyBalanceStableV1(CurrencyAmountStableV1(
320                UnsignedExtendedUInt64Int64ForVersionTagsStableV1(acc.balance.as_u64().into()),
321            )),
322            nonce: UnsignedExtendedUInt32StableV1(acc.nonce.as_u32().into()),
323            receipt_chain_hash: MinaBaseReceiptChainHashStableV1(acc.receipt_chain_hash.0.into()),
324            delegate: acc.delegate.as_ref().map(|delegate| {
325                let delegate: NonZeroCurvePointUncompressedStableV1 = delegate.into();
326                delegate.into()
327            }),
328            voting_for: DataHashLibStateHashStableV1(acc.voting_for.0.into()).into(),
329            timing: (&acc.timing).into(),
330            permissions: (&acc.permissions).into(),
331            zkapp: acc.zkapp.as_ref().map(|zkapp| {
332                let s = zkapp.app_state;
333                let app_state = MinaBaseZkappStateValueStableV1(PaddedSeq(s.map(|v| v.into())));
334
335                let verification_key = zkapp.verification_key.as_ref().map(|vk| vk.vk().into());
336
337                let seq = zkapp.action_state;
338                let action_state = PaddedSeq(seq.map(|v| v.into()));
339
340                MinaBaseZkappAccountStableV2 {
341                    app_state,
342                    verification_key,
343                    zkapp_version: MinaNumbersNatMake32StableV1(UnsignedExtendedUInt32StableV1(
344                        zkapp.zkapp_version.into(),
345                    )),
346                    action_state,
347                    last_action_slot: (&zkapp.last_action_slot).into(),
348                    proved_state: zkapp.proved_state,
349                    zkapp_uri: (&zkapp.zkapp_uri).into(),
350                }
351            }),
352        }
353    }
354}
355impl From<Account> for mina_p2p_messages::v2::MinaBaseAccountBinableArgStableV2 {
356    fn from(account: Account) -> Self {
357        (&account).into()
358    }
359}
360
361impl From<&AuthRequired> for mina_p2p_messages::v2::MinaBasePermissionsAuthRequiredStableV2 {
362    fn from(perms: &AuthRequired) -> Self {
363        match perms {
364            AuthRequired::None => Self::None,
365            AuthRequired::Either => Self::Either,
366            AuthRequired::Proof => Self::Proof,
367            AuthRequired::Signature => Self::Signature,
368            AuthRequired::Impossible => Self::Impossible,
369            AuthRequired::Both => panic!("doesn't exist in `develop` branch"),
370        }
371    }
372}
373
374impl From<&PlonkVerificationKeyEvals<Fp>>
375    for mina_p2p_messages::v2::MinaBaseVerificationKeyWireStableV1WrapIndex
376{
377    fn from(vk: &PlonkVerificationKeyEvals<Fp>) -> Self {
378        let sigma = PaddedSeq(array_into(&vk.sigma));
379        let coef = PaddedSeq(array_into(&vk.coefficients));
380
381        Self {
382            sigma_comm: sigma,
383            coefficients_comm: coef,
384            generic_comm: (&vk.generic).into(),
385            psm_comm: (&vk.psm).into(),
386            complete_add_comm: (&vk.complete_add).into(),
387            mul_comm: (&vk.mul).into(),
388            emul_comm: (&vk.emul).into(),
389            endomul_scalar_comm: (&vk.endomul_scalar).into(),
390        }
391    }
392}
393impl From<PlonkVerificationKeyEvals<Fp>>
394    for mina_p2p_messages::v2::MinaBaseVerificationKeyWireStableV1WrapIndex
395{
396    fn from(value: PlonkVerificationKeyEvals<Fp>) -> Self {
397        (&value).into()
398    }
399}
400
401// // Following types were written manually
402
403impl From<AccountId> for mina_p2p_messages::v2::MinaBaseAccountIdStableV2 {
404    fn from(account_id: AccountId) -> Self {
405        let public_key: NonZeroCurvePointUncompressedStableV1 = account_id.public_key.into();
406        Self(public_key.into(), account_id.token_id.into())
407    }
408}
409
410impl TryFrom<mina_p2p_messages::v2::MinaBaseAccountIdStableV2> for AccountId {
411    type Error = InvalidBigInt;
412
413    fn try_from(
414        account_id: mina_p2p_messages::v2::MinaBaseAccountIdStableV2,
415    ) -> Result<Self, Self::Error> {
416        Ok(Self {
417            public_key: account_id.0.into_inner().try_into()?,
418            token_id: account_id.1.try_into()?,
419        })
420    }
421}
422
423impl TryFrom<&mina_p2p_messages::v2::MinaBaseAccountIdStableV2> for AccountId {
424    type Error = InvalidBigInt;
425
426    fn try_from(
427        account_id: &mina_p2p_messages::v2::MinaBaseAccountIdStableV2,
428    ) -> Result<Self, Self::Error> {
429        Ok(Self {
430            public_key: account_id.0.clone().into_inner().try_into()?,
431            token_id: account_id.1.clone().try_into()?,
432        })
433    }
434}
435
436impl From<TokenId> for mina_p2p_messages::v2::MinaBaseAccountIdDigestStableV1 {
437    fn from(token_id: TokenId) -> Self {
438        Self(token_id.0.into())
439    }
440}
441
442impl TryFrom<mina_p2p_messages::v2::MinaBaseAccountIdDigestStableV1> for TokenId {
443    type Error = InvalidBigInt;
444
445    fn try_from(
446        token_id: mina_p2p_messages::v2::MinaBaseAccountIdDigestStableV1,
447    ) -> Result<Self, Self::Error> {
448        Ok(Self(token_id.0.try_into()?))
449    }
450}
451
452impl TryFrom<&mina_p2p_messages::v2::MinaBaseAccountIdDigestStableV1> for TokenId {
453    type Error = InvalidBigInt;
454
455    fn try_from(
456        token_id: &mina_p2p_messages::v2::MinaBaseAccountIdDigestStableV1,
457    ) -> Result<Self, Self::Error> {
458        Ok(Self(token_id.0.to_field()?))
459    }
460}
461
462impl From<&TokenId> for mina_p2p_messages::v2::MinaBaseTokenIdStableV2 {
463    fn from(token_id: &TokenId) -> Self {
464        Self(MinaBaseAccountIdDigestStableV1(token_id.0.into()))
465    }
466}
467
468impl From<TokenId> for mina_p2p_messages::v2::MinaBaseTokenIdStableV2 {
469    fn from(token_id: TokenId) -> Self {
470        Self(MinaBaseAccountIdDigestStableV1(token_id.0.into()))
471    }
472}
473
474impl TryFrom<&mina_p2p_messages::v2::MinaBaseTokenIdStableV2> for TokenId {
475    type Error = InvalidBigInt;
476
477    fn try_from(
478        token_id: &mina_p2p_messages::v2::MinaBaseTokenIdStableV2,
479    ) -> Result<Self, Self::Error> {
480        Ok(Self(token_id.to_field()?))
481    }
482}
483
484impl TryFrom<mina_p2p_messages::v2::MinaBaseTokenIdStableV2> for TokenId {
485    type Error = InvalidBigInt;
486
487    fn try_from(
488        token_id: mina_p2p_messages::v2::MinaBaseTokenIdStableV2,
489    ) -> Result<Self, Self::Error> {
490        Ok(Self(token_id.to_field()?))
491    }
492}
493
494impl binprot::BinProtRead for Account {
495    fn binprot_read<R: std::io::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error>
496    where
497        Self: Sized,
498    {
499        let account = MinaBaseAccountBinableArgStableV2::binprot_read(r)?;
500        (&account)
501            .try_into()
502            .map_err(|e| binprot::Error::CustomError(Box::new(e)))
503    }
504}
505
506impl binprot::BinProtWrite for Account {
507    fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
508        let account: MinaBaseAccountBinableArgStableV2 = self.into();
509        account.binprot_write(w)?;
510        Ok(())
511    }
512}
513
514impl From<&MinaBasePermissionsAuthRequiredStableV2> for AuthRequired {
515    fn from(auth: &MinaBasePermissionsAuthRequiredStableV2) -> Self {
516        match auth {
517            MinaBasePermissionsAuthRequiredStableV2::None => Self::None,
518            MinaBasePermissionsAuthRequiredStableV2::Either => Self::Either,
519            MinaBasePermissionsAuthRequiredStableV2::Proof => Self::Proof,
520            MinaBasePermissionsAuthRequiredStableV2::Signature => Self::Signature,
521            MinaBasePermissionsAuthRequiredStableV2::Impossible => Self::Impossible,
522        }
523    }
524}
525
526impl From<&MinaBasePermissionsStableV2> for Permissions<AuthRequired> {
527    fn from(perms: &MinaBasePermissionsStableV2) -> Self {
528        let MinaBasePermissionsStableV2 {
529            edit_state,
530            access,
531            send,
532            receive,
533            set_delegate,
534            set_permissions,
535            set_verification_key: (auth, txn_version),
536            set_zkapp_uri,
537            edit_action_state,
538            set_token_symbol,
539            increment_nonce,
540            set_voting_for,
541            set_timing,
542        } = perms;
543
544        Permissions {
545            edit_state: edit_state.into(),
546            send: send.into(),
547            receive: receive.into(),
548            set_delegate: set_delegate.into(),
549            set_permissions: set_permissions.into(),
550            set_verification_key: SetVerificationKey {
551                auth: auth.into(),
552                txn_version: TxnVersion::from_u32(txn_version.as_u32()),
553            },
554            set_zkapp_uri: set_zkapp_uri.into(),
555            edit_action_state: edit_action_state.into(),
556            set_token_symbol: set_token_symbol.into(),
557            increment_nonce: increment_nonce.into(),
558            set_voting_for: set_voting_for.into(),
559            access: access.into(),
560            set_timing: set_timing.into(),
561        }
562    }
563}
564
565impl From<&Permissions<AuthRequired>> for MinaBasePermissionsStableV2 {
566    fn from(perms: &Permissions<AuthRequired>) -> Self {
567        let Permissions {
568            edit_state,
569            access,
570            send,
571            receive,
572            set_delegate,
573            set_permissions,
574            set_verification_key: SetVerificationKey { auth, txn_version },
575            set_zkapp_uri,
576            edit_action_state,
577            set_token_symbol,
578            increment_nonce,
579            set_voting_for,
580            set_timing,
581        } = perms;
582
583        MinaBasePermissionsStableV2 {
584            edit_state: edit_state.into(),
585            send: send.into(),
586            receive: receive.into(),
587            set_delegate: set_delegate.into(),
588            set_permissions: set_permissions.into(),
589            set_verification_key: (auth.into(), txn_version.as_u32().into()),
590            set_zkapp_uri: set_zkapp_uri.into(),
591            edit_action_state: edit_action_state.into(),
592            set_token_symbol: set_token_symbol.into(),
593            increment_nonce: increment_nonce.into(),
594            set_voting_for: set_voting_for.into(),
595            access: access.into(),
596            set_timing: set_timing.into(),
597        }
598    }
599}
600
601impl TryFrom<&MinaBaseAccountBinableArgStableV2> for Account {
602    type Error = InvalidBigInt;
603
604    fn try_from(acc: &MinaBaseAccountBinableArgStableV2) -> Result<Self, Self::Error> {
605        Ok(Self {
606            public_key: acc.public_key.inner().try_into()?,
607            token_id: acc.token_id.inner().try_into()?,
608            token_symbol: {
609                let s = acc.token_symbol.0.clone();
610                TokenSymbol::from(s)
611            },
612            balance: Balance::from_u64(acc.balance.0 .0 .0 .0),
613            nonce: Nonce::from_u32(acc.nonce.0 .0),
614            receipt_chain_hash: ReceiptChainHash(acc.receipt_chain_hash.to_field()?),
615            delegate: match acc.delegate.as_ref() {
616                Some(delegate) => Some(delegate.try_into()?),
617                None => None,
618            },
619            voting_for: VotingFor(acc.voting_for.to_field()?),
620            timing: (&acc.timing).into(),
621            permissions: (&acc.permissions).into(),
622            zkapp: match acc.zkapp.as_ref() {
623                Some(zkapp) => {
624                    let v2::MinaBaseZkappAccountStableV2 {
625                        app_state,
626                        verification_key,
627                        zkapp_version,
628                        action_state,
629                        last_action_slot,
630                        proved_state,
631                        zkapp_uri,
632                    } = zkapp;
633
634                    Some(Box::new(ZkAppAccount {
635                        app_state: try_array_into_with(app_state, BigInt::to_field)?,
636                        verification_key: match verification_key.as_ref() {
637                            Some(vk) => Some(VerificationKeyWire::new(vk.try_into()?)),
638                            None => None,
639                        },
640                        zkapp_version: zkapp_version.as_u32(),
641                        action_state: try_array_into_with(action_state, BigInt::to_field)?,
642                        last_action_slot: Slot::from_u32(last_action_slot.as_u32()),
643                        proved_state: *proved_state,
644                        zkapp_uri: zkapp_uri.into(),
645                    }))
646                }
647                None => None,
648            },
649        })
650    }
651}
652impl TryFrom<MinaBaseAccountBinableArgStableV2> for Account {
653    type Error = InvalidBigInt;
654
655    fn try_from(account: MinaBaseAccountBinableArgStableV2) -> Result<Self, Self::Error> {
656        (&account).try_into()
657    }
658}
659
660impl From<AccountIndex> for MinaBaseAccountIndexStableV1 {
661    fn from(value: AccountIndex) -> Self {
662        Self(value.as_u64().into())
663    }
664}
665
666impl From<ReceiptChainHash> for mina_p2p_messages::v2::ReceiptChainHash {
667    fn from(value: ReceiptChainHash) -> Self {
668        MinaBaseReceiptChainHashStableV1(value.0.into_bigint().into()).into()
669    }
670}
671
672#[cfg(test)]
673mod tests {
674    use super::*;
675
676    #[cfg(target_family = "wasm")]
677    use wasm_bindgen_test::wasm_bindgen_test as test;
678
679    #[test]
680    fn test_deserialize_account() {
681        let account = Account::rand();
682        let hash = account.hash();
683
684        let bytes = account.serialize();
685
686        elog!("len={:?}", bytes.len());
687        let result: Account = Account::deserialize(&bytes);
688        elog!("account={:#?}", result);
689
690        assert_eq!(hash, result.hash());
691    }
692}