mina_tree/account/
conv.rs

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