griffin_core/uplc/tx/
to_plutus_data.rs

1use super::script_context::{
2    ScriptContext, ScriptInfo, ScriptPurpose, TimeRange, TxInInfo, TxInfo,
3};
4use crate::pallas_addresses::{
5    Address, ShelleyDelegationPart, ShelleyPaymentPart, StakeAddress, StakePayload,
6};
7use crate::pallas_codec::utils::{
8    AnyUInt, Bytes, Int, KeyValuePairs, MaybeIndefArray, NonEmptyKeyValuePairs, Nullable,
9    PositiveCoin,
10};
11use crate::pallas_crypto::hash::Hash;
12use crate::pallas_primitives::conway::{
13    AssetName, BigInt, Certificate, Coin, Constitution, Constr, DRep, DRepVotingThresholds,
14    DatumOption, ExUnitPrices, ExUnits, GovAction, GovActionId, Mint, PlutusData, PolicyId,
15    PoolVotingThresholds, ProposalProcedure, ProtocolParamUpdate, PseudoScript, RationalNumber,
16    Redeemer, ScriptRef, StakeCredential, TransactionInput, TransactionOutput, Value, Vote, Voter,
17    VotingProcedure,
18};
19use crate::pallas_traverse::ComputeHash;
20use crate::uplc::{
21    ast::Data,
22    machine::runtime::{convert_constr_to_tag, ANY_TAG},
23    tx::script_context::from_alonzo_output,
24};
25use alloc::vec::Vec;
26use num_integer::Integer;
27
28fn wrap_multiple_with_constr(index: u64, data: Vec<PlutusData>) -> PlutusData {
29    let converted = convert_constr_to_tag(index);
30    PlutusData::Constr(Constr {
31        tag: converted.unwrap_or(ANY_TAG),
32        any_constructor: converted.map_or(Some(index), |_| None),
33        fields: if data.is_empty() {
34            MaybeIndefArray::Def(data)
35        } else {
36            MaybeIndefArray::Indef(data)
37        },
38    })
39}
40
41fn wrap_with_constr(index: u64, data: PlutusData) -> PlutusData {
42    wrap_multiple_with_constr(index, vec![data])
43}
44
45fn empty_constr(index: u64) -> PlutusData {
46    wrap_multiple_with_constr(index, vec![])
47}
48
49struct WithWrappedTransactionId<'a, T>(&'a T);
50
51struct WithWrappedStakeCredential<'a, T>(&'a T);
52
53struct WithZeroAdaAsset<'a, T>(&'a T);
54
55struct WithOptionDatum<'a, T>(&'a T);
56
57struct WithArrayRational<'a, T>(&'a T);
58
59struct WithPartialCertificates<'a, T>(&'a T);
60
61struct WithNeverRegistrationDeposit<'a, T>(&'a T);
62
63pub trait ToPlutusData {
64    fn to_plutus_data(&self) -> PlutusData;
65}
66
67#[derive(Debug, PartialEq, Eq, Clone)]
68pub struct MintValue {
69    pub mint_value: Mint,
70}
71
72impl ToPlutusData for bool {
73    fn to_plutus_data(&self) -> PlutusData {
74        match self {
75            false => empty_constr(0),
76            true => empty_constr(1),
77        }
78    }
79}
80impl ToPlutusData for StakeAddress {
81    fn to_plutus_data(&self) -> PlutusData {
82        match self.payload() {
83            StakePayload::Stake(x) => wrap_with_constr(0, x.to_plutus_data()),
84            StakePayload::Script(x) => wrap_with_constr(1, x.to_plutus_data()),
85        }
86    }
87}
88
89impl ToPlutusData for Address {
90    fn to_plutus_data(&self) -> PlutusData {
91        match self {
92            Address::Shelley(shelley_address) => {
93                let payment_part = shelley_address.payment();
94                let stake_part = shelley_address.delegation();
95
96                let payment_part_plutus_data = match payment_part {
97                    ShelleyPaymentPart::Key(payment_keyhash) => {
98                        wrap_with_constr(0, payment_keyhash.to_plutus_data())
99                    }
100                    ShelleyPaymentPart::Script(script_hash) => {
101                        wrap_with_constr(1, script_hash.to_plutus_data())
102                    }
103                };
104
105                let stake_part_plutus_data = match stake_part {
106                    ShelleyDelegationPart::Key(stake_keyhash) => Some(wrap_with_constr(
107                        0,
108                        StakeCredential::AddrKeyhash(*stake_keyhash).to_plutus_data(),
109                    ))
110                    .to_plutus_data(),
111                    ShelleyDelegationPart::Script(script_hash) => Some(wrap_with_constr(
112                        0,
113                        StakeCredential::ScriptHash(*script_hash).to_plutus_data(),
114                    ))
115                    .to_plutus_data(),
116                    ShelleyDelegationPart::Pointer(pointer) => Some(wrap_multiple_with_constr(
117                        1,
118                        vec![
119                            pointer.slot().to_plutus_data(),
120                            pointer.tx_idx().to_plutus_data(),
121                            pointer.cert_idx().to_plutus_data(),
122                        ],
123                    ))
124                    .to_plutus_data(),
125                    ShelleyDelegationPart::Null => None::<StakeCredential>.to_plutus_data(),
126                };
127
128                wrap_multiple_with_constr(0, vec![payment_part_plutus_data, stake_part_plutus_data])
129            }
130            Address::Stake(stake_address) => stake_address.to_plutus_data(),
131            _ => unreachable!(),
132        }
133    }
134}
135
136impl ToPlutusData for WithWrappedTransactionId<'_, TransactionInput> {
137    fn to_plutus_data(&self) -> PlutusData {
138        wrap_multiple_with_constr(
139            0,
140            vec![
141                wrap_with_constr(0, self.0.transaction_id.to_plutus_data()),
142                PlutusData::BigInt(BigInt::Int((self.0.index as i128).try_into().unwrap())),
143            ],
144        )
145    }
146}
147
148impl ToPlutusData for TransactionInput {
149    fn to_plutus_data(&self) -> PlutusData {
150        wrap_multiple_with_constr(
151            0,
152            vec![
153                self.transaction_id.to_plutus_data(),
154                PlutusData::BigInt(BigInt::Int((self.index as i128).try_into().unwrap())),
155            ],
156        )
157    }
158}
159
160impl<const BYTES: usize> ToPlutusData for Hash<BYTES> {
161    fn to_plutus_data(&self) -> PlutusData {
162        PlutusData::BoundedBytes(self.to_vec().into())
163    }
164}
165
166impl ToPlutusData for Bytes {
167    fn to_plutus_data(&self) -> PlutusData {
168        PlutusData::BoundedBytes(self.to_vec().into())
169    }
170}
171
172impl<K: ToPlutusData, V: ToPlutusData> ToPlutusData for (K, V) {
173    fn to_plutus_data(&self) -> PlutusData {
174        wrap_multiple_with_constr(0, vec![self.0.to_plutus_data(), self.1.to_plutus_data()])
175    }
176}
177
178impl<A> ToPlutusData for Vec<A>
179where
180    A: ToPlutusData,
181{
182    fn to_plutus_data(&self) -> PlutusData {
183        Data::list(self.iter().map(|p| p.to_plutus_data()).collect())
184    }
185}
186
187impl<K, V> ToPlutusData for KeyValuePairs<K, V>
188where
189    K: ToPlutusData + Clone,
190    V: ToPlutusData + Clone,
191{
192    fn to_plutus_data(&self) -> PlutusData {
193        let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![];
194        for (key, value) in self.iter() {
195            data_vec.push((key.to_plutus_data(), value.to_plutus_data()))
196        }
197        PlutusData::Map(KeyValuePairs::Def(data_vec))
198    }
199}
200
201impl ToPlutusData for WithWrappedTransactionId<'_, KeyValuePairs<ScriptPurpose, Redeemer>> {
202    fn to_plutus_data(&self) -> PlutusData {
203        let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![];
204        for (key, value) in self.0.iter() {
205            data_vec.push((
206                WithWrappedTransactionId(key).to_plutus_data(),
207                value.to_plutus_data(),
208            ))
209        }
210        PlutusData::Map(KeyValuePairs::Def(data_vec))
211    }
212}
213
214impl ToPlutusData for WithNeverRegistrationDeposit<'_, Vec<Certificate>> {
215    fn to_plutus_data(&self) -> PlutusData {
216        self.0
217            .iter()
218            .map(WithNeverRegistrationDeposit)
219            .collect::<Vec<_>>()
220            .to_plutus_data()
221    }
222}
223
224impl ToPlutusData for WithNeverRegistrationDeposit<'_, KeyValuePairs<ScriptPurpose, Redeemer>> {
225    fn to_plutus_data(&self) -> PlutusData {
226        let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![];
227        for (key, value) in self.0.iter() {
228            data_vec.push((
229                WithNeverRegistrationDeposit(key).to_plutus_data(),
230                value.to_plutus_data(),
231            ))
232        }
233        PlutusData::Map(KeyValuePairs::Def(data_vec))
234    }
235}
236
237impl<A: ToPlutusData> ToPlutusData for Option<A> {
238    fn to_plutus_data(&self) -> PlutusData {
239        match self {
240            None => empty_constr(1),
241            Some(data) => wrap_with_constr(0, data.to_plutus_data()),
242        }
243    }
244}
245
246impl ToPlutusData for Option<DatumOption> {
247    // NoOutputDatum = 0 | OutputDatumHash = 1 | OutputDatum = 2
248    fn to_plutus_data(&self) -> PlutusData {
249        match self {
250            None => empty_constr(0),
251            Some(option) => match option {
252                DatumOption::Hash(hash) => wrap_with_constr(1, hash.to_plutus_data()),
253                DatumOption::Data(data) => wrap_with_constr(2, data.0.clone()),
254            },
255        }
256    }
257}
258
259impl ToPlutusData for AnyUInt {
260    fn to_plutus_data(&self) -> PlutusData {
261        match self {
262            AnyUInt::U8(n) => PlutusData::BigInt(BigInt::Int(Int::from(*n as i64))),
263            AnyUInt::U16(n) => PlutusData::BigInt(BigInt::Int(Int::from(*n as i64))),
264            AnyUInt::U32(n) => PlutusData::BigInt(BigInt::Int(Int::from(*n as i64))),
265            AnyUInt::U64(n) => PlutusData::BigInt(BigInt::Int(Int::try_from(*n as i128).unwrap())),
266            AnyUInt::MajorByte(n) => PlutusData::BigInt(BigInt::Int(Int::from(*n as i64))), // is this correct? I don't know exactly what is does
267        }
268    }
269}
270
271impl ToPlutusData for Int {
272    fn to_plutus_data(&self) -> PlutusData {
273        PlutusData::BigInt(BigInt::Int(*self))
274    }
275}
276
277impl ToPlutusData for BigInt {
278    fn to_plutus_data(&self) -> PlutusData {
279        PlutusData::BigInt(self.clone())
280    }
281}
282
283impl ToPlutusData for i64 {
284    fn to_plutus_data(&self) -> PlutusData {
285        PlutusData::BigInt(BigInt::Int(Int::from(*self)))
286    }
287}
288
289impl ToPlutusData for u32 {
290    fn to_plutus_data(&self) -> PlutusData {
291        PlutusData::BigInt(BigInt::Int(Int::try_from(*self as i128).unwrap()))
292    }
293}
294
295impl ToPlutusData for u64 {
296    fn to_plutus_data(&self) -> PlutusData {
297        PlutusData::BigInt(BigInt::Int(Int::try_from(*self as i128).unwrap()))
298    }
299}
300
301impl ToPlutusData for usize {
302    fn to_plutus_data(&self) -> PlutusData {
303        PlutusData::BigInt(BigInt::Int(Int::try_from(*self as i128).unwrap()))
304    }
305}
306
307impl ToPlutusData for PositiveCoin {
308    fn to_plutus_data(&self) -> PlutusData {
309        u64::from(self).to_plutus_data()
310    }
311}
312
313impl ToPlutusData for WithZeroAdaAsset<'_, Value> {
314    fn to_plutus_data(&self) -> PlutusData {
315        match self.0 {
316            Value::Coin(coin) => {
317                PlutusData::Map(KeyValuePairs::Def(vec![coin_to_plutus_data(coin)]))
318            }
319            Value::Multiasset(coin, multiassets) => value_to_plutus_data(
320                multiassets.iter(),
321                |amount| u64::from(amount).to_plutus_data(),
322                vec![coin_to_plutus_data(coin)],
323            ),
324        }
325    }
326}
327
328impl ToPlutusData for Value {
329    fn to_plutus_data(&self) -> PlutusData {
330        match self {
331            Value::Coin(coin) => PlutusData::Map(KeyValuePairs::Def(if *coin > 0 {
332                vec![coin_to_plutus_data(coin)]
333            } else {
334                vec![]
335            })),
336            Value::Multiasset(coin, multiassets) => value_to_plutus_data(
337                multiassets.iter(),
338                |amount| u64::from(amount).to_plutus_data(),
339                if *coin > 0 {
340                    vec![coin_to_plutus_data(coin)]
341                } else {
342                    vec![]
343                },
344            ),
345        }
346    }
347}
348
349impl ToPlutusData for WithZeroAdaAsset<'_, MintValue> {
350    fn to_plutus_data(&self) -> PlutusData {
351        value_to_plutus_data(
352            self.0.mint_value.iter(),
353            |amount| i64::from(amount).to_plutus_data(),
354            vec![(
355                Bytes::from(vec![]).to_plutus_data(),
356                PlutusData::Map(KeyValuePairs::Def(vec![(
357                    AssetName::from(vec![]).to_plutus_data(),
358                    0_i64.to_plutus_data(),
359                )])),
360            )],
361        )
362    }
363}
364
365impl ToPlutusData for MintValue {
366    fn to_plutus_data(&self) -> PlutusData {
367        value_to_plutus_data(
368            self.mint_value.iter(),
369            |amount| i64::from(amount).to_plutus_data(),
370            vec![],
371        )
372    }
373}
374
375fn value_to_plutus_data<'a, I, Q>(
376    mint: I,
377    from_quantity: fn(&'a Q) -> PlutusData,
378    mut data_vec: Vec<(PlutusData, PlutusData)>,
379) -> PlutusData
380where
381    I: Iterator<Item = &'a (PolicyId, NonEmptyKeyValuePairs<AssetName, Q>)>,
382    Q: Clone,
383{
384    for (policy_id, assets) in mint {
385        let mut assets_vec = vec![];
386        for (asset, amount) in assets.iter() {
387            assets_vec.push((asset.to_plutus_data(), from_quantity(amount)));
388        }
389        data_vec.push((
390            policy_id.to_plutus_data(),
391            PlutusData::Map(KeyValuePairs::Def(assets_vec)),
392        ));
393    }
394
395    PlutusData::Map(KeyValuePairs::Def(data_vec))
396}
397
398fn coin_to_plutus_data(coin: &Coin) -> (PlutusData, PlutusData) {
399    (
400        Bytes::from(vec![]).to_plutus_data(),
401        PlutusData::Map(KeyValuePairs::Def(vec![(
402            AssetName::from(vec![]).to_plutus_data(),
403            coin.to_plutus_data(),
404        )])),
405    )
406}
407
408impl ToPlutusData for ScriptRef {
409    fn to_plutus_data(&self) -> PlutusData {
410        match &self {
411            PseudoScript::NativeScript(native_script) => {
412                native_script.compute_hash().to_plutus_data()
413            }
414            PseudoScript::PlutusV1Script(plutus_v1) => plutus_v1.compute_hash().to_plutus_data(),
415            PseudoScript::PlutusV2Script(plutus_v2) => plutus_v2.compute_hash().to_plutus_data(),
416            PseudoScript::PlutusV3Script(plutus_v3) => plutus_v3.compute_hash().to_plutus_data(),
417        }
418    }
419}
420
421impl<'a> ToPlutusData for WithOptionDatum<'a, WithZeroAdaAsset<'a, Vec<TransactionOutput>>> {
422    fn to_plutus_data(&self) -> PlutusData {
423        Data::list(
424            self.0
425                 .0
426                .iter()
427                .map(|p| WithOptionDatum(&WithZeroAdaAsset(p)).to_plutus_data())
428                .collect(),
429        )
430    }
431}
432
433impl ToPlutusData for WithZeroAdaAsset<'_, Vec<TransactionOutput>> {
434    fn to_plutus_data(&self) -> PlutusData {
435        Data::list(
436            self.0
437                .iter()
438                .map(|p| WithZeroAdaAsset(p).to_plutus_data())
439                .collect(),
440        )
441    }
442}
443
444impl<'a> ToPlutusData for WithOptionDatum<'a, WithZeroAdaAsset<'a, TransactionOutput>> {
445    fn to_plutus_data(&self) -> PlutusData {
446        match self.0 .0 {
447            TransactionOutput::Legacy(legacy_output) => {
448                WithOptionDatum(&WithZeroAdaAsset(&from_alonzo_output(legacy_output)))
449                    .to_plutus_data()
450            }
451
452            TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr(
453                0,
454                vec![
455                    Address::from_bytes(&post_alonzo_output.address)
456                        .unwrap()
457                        .to_plutus_data(),
458                    WithZeroAdaAsset(&post_alonzo_output.value).to_plutus_data(),
459                    match post_alonzo_output.datum_option {
460                        Some(DatumOption::Hash(hash)) => Some(hash).to_plutus_data(),
461                        _ => None::<Hash<32>>.to_plutus_data(),
462                    },
463                ],
464            ),
465        }
466    }
467}
468
469impl ToPlutusData for WithZeroAdaAsset<'_, TransactionOutput> {
470    fn to_plutus_data(&self) -> PlutusData {
471        match self.0 {
472            TransactionOutput::Legacy(legacy_output) => {
473                WithZeroAdaAsset(&from_alonzo_output(legacy_output)).to_plutus_data()
474            }
475            TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr(
476                0,
477                vec![
478                    Address::from_bytes(&post_alonzo_output.address)
479                        .unwrap()
480                        .to_plutus_data(),
481                    WithZeroAdaAsset(&post_alonzo_output.value).to_plutus_data(),
482                    post_alonzo_output.datum_option.to_plutus_data(),
483                    post_alonzo_output
484                        .script_ref
485                        .as_ref()
486                        .map(|s| s.clone().unwrap())
487                        .to_plutus_data(),
488                ],
489            ),
490        }
491    }
492}
493
494impl ToPlutusData for TransactionOutput {
495    fn to_plutus_data(&self) -> PlutusData {
496        match self {
497            TransactionOutput::Legacy(legacy_output) => {
498                from_alonzo_output(legacy_output).to_plutus_data()
499            }
500            TransactionOutput::PostAlonzo(post_alonzo_output) => wrap_multiple_with_constr(
501                0,
502                vec![
503                    Address::from_bytes(&post_alonzo_output.address)
504                        .unwrap()
505                        .to_plutus_data(),
506                    post_alonzo_output.value.to_plutus_data(),
507                    post_alonzo_output.datum_option.to_plutus_data(),
508                    post_alonzo_output
509                        .script_ref
510                        .as_ref()
511                        .map(|s| s.clone().unwrap())
512                        .to_plutus_data(),
513                ],
514            ),
515        }
516    }
517}
518
519impl ToPlutusData for StakeCredential {
520    fn to_plutus_data(&self) -> PlutusData {
521        match self {
522            StakeCredential::AddrKeyhash(addr_keyhas) => {
523                wrap_with_constr(0, addr_keyhas.to_plutus_data())
524            }
525            StakeCredential::ScriptHash(script_hash) => {
526                wrap_with_constr(1, script_hash.to_plutus_data())
527            }
528        }
529    }
530}
531
532impl ToPlutusData for WithPartialCertificates<'_, Vec<Certificate>> {
533    fn to_plutus_data(&self) -> PlutusData {
534        self.0
535            .iter()
536            .map(WithPartialCertificates)
537            .collect::<Vec<_>>()
538            .to_plutus_data()
539    }
540}
541
542impl ToPlutusData for WithPartialCertificates<'_, Certificate> {
543    fn to_plutus_data(&self) -> PlutusData {
544        match self.0 {
545            Certificate::StakeRegistration(stake_credential) => {
546                wrap_with_constr(0, stake_credential.to_plutus_data())
547            }
548
549            Certificate::StakeDeregistration(stake_credential) => {
550                wrap_with_constr(1, stake_credential.to_plutus_data())
551            }
552
553            Certificate::StakeDelegation(stake_credential, pool_keyhash) => {
554                wrap_multiple_with_constr(
555                    2,
556                    vec![
557                        stake_credential.to_plutus_data(),
558                        pool_keyhash.to_plutus_data(),
559                    ],
560                )
561            }
562
563            Certificate::PoolRegistration {
564                operator,
565                vrf_keyhash,
566                pledge: _,
567                cost: _,
568                margin: _,
569                reward_account: _,
570                pool_owners: _,
571                relays: _,
572                pool_metadata: _,
573            } => wrap_multiple_with_constr(
574                3,
575                vec![operator.to_plutus_data(), vrf_keyhash.to_plutus_data()],
576            ),
577
578            Certificate::PoolRetirement(pool_keyhash, epoch) => wrap_multiple_with_constr(
579                4,
580                vec![pool_keyhash.to_plutus_data(), epoch.to_plutus_data()],
581            ),
582
583            certificate => {
584                unreachable!("unexpected certificate type in V1/V2 script context: {certificate:?}")
585            }
586        }
587    }
588}
589
590impl ToPlutusData for WithNeverRegistrationDeposit<'_, Certificate> {
591    fn to_plutus_data(&self) -> PlutusData {
592        match self.0 {
593            Certificate::StakeRegistration(stake_credential) => wrap_multiple_with_constr(
594                0,
595                vec![
596                    stake_credential.to_plutus_data(),
597                    None::<PlutusData>.to_plutus_data(),
598                ],
599            ),
600
601            Certificate::Reg(stake_credential, _) => wrap_multiple_with_constr(
602                0,
603                vec![
604                    stake_credential.to_plutus_data(),
605                    None::<PlutusData>.to_plutus_data(),
606                ],
607            ),
608
609            Certificate::StakeDeregistration(stake_credential) => wrap_multiple_with_constr(
610                1,
611                vec![
612                    stake_credential.to_plutus_data(),
613                    None::<PlutusData>.to_plutus_data(),
614                ],
615            ),
616
617            Certificate::UnReg(stake_credential, _) => wrap_multiple_with_constr(
618                1,
619                vec![
620                    stake_credential.to_plutus_data(),
621                    None::<PlutusData>.to_plutus_data(),
622                ],
623            ),
624
625            Certificate::StakeDelegation(stake_credential, pool_id) => wrap_multiple_with_constr(
626                2,
627                vec![
628                    stake_credential.to_plutus_data(),
629                    wrap_with_constr(0, pool_id.to_plutus_data()),
630                ],
631            ),
632
633            Certificate::VoteDeleg(stake_credential, drep) => wrap_multiple_with_constr(
634                2,
635                vec![
636                    stake_credential.to_plutus_data(),
637                    wrap_with_constr(1, drep.to_plutus_data()),
638                ],
639            ),
640
641            Certificate::StakeVoteDeleg(stake_credential, pool_id, drep) => {
642                wrap_multiple_with_constr(
643                    2,
644                    vec![
645                        stake_credential.to_plutus_data(),
646                        wrap_multiple_with_constr(
647                            2,
648                            vec![pool_id.to_plutus_data(), drep.to_plutus_data()],
649                        ),
650                    ],
651                )
652            }
653
654            Certificate::StakeRegDeleg(stake_credential, pool_id, deposit) => {
655                wrap_multiple_with_constr(
656                    3,
657                    vec![
658                        stake_credential.to_plutus_data(),
659                        wrap_multiple_with_constr(0, vec![pool_id.to_plutus_data()]),
660                        deposit.to_plutus_data(),
661                    ],
662                )
663            }
664
665            Certificate::VoteRegDeleg(stake_credential, drep, deposit) => {
666                wrap_multiple_with_constr(
667                    3,
668                    vec![
669                        stake_credential.to_plutus_data(),
670                        wrap_multiple_with_constr(1, vec![drep.to_plutus_data()]),
671                        deposit.to_plutus_data(),
672                    ],
673                )
674            }
675
676            Certificate::StakeVoteRegDeleg(stake_credential, pool_id, drep, deposit) => {
677                wrap_multiple_with_constr(
678                    3,
679                    vec![
680                        stake_credential.to_plutus_data(),
681                        wrap_multiple_with_constr(
682                            2,
683                            vec![pool_id.to_plutus_data(), drep.to_plutus_data()],
684                        ),
685                        deposit.to_plutus_data(),
686                    ],
687                )
688            }
689
690            Certificate::RegDRepCert(drep_credential, deposit, _anchor) => {
691                wrap_multiple_with_constr(
692                    4,
693                    vec![drep_credential.to_plutus_data(), deposit.to_plutus_data()],
694                )
695            }
696
697            Certificate::UpdateDRepCert(drep_credential, _anchor) => {
698                wrap_multiple_with_constr(5, vec![drep_credential.to_plutus_data()])
699            }
700
701            Certificate::UnRegDRepCert(drep_credential, deposit) => wrap_multiple_with_constr(
702                6,
703                vec![drep_credential.to_plutus_data(), deposit.to_plutus_data()],
704            ),
705
706            Certificate::PoolRegistration {
707                operator,
708                vrf_keyhash,
709                pledge: _,
710                cost: _,
711                margin: _,
712                reward_account: _,
713                pool_owners: _,
714                relays: _,
715                pool_metadata: _,
716            } => wrap_multiple_with_constr(
717                7,
718                vec![operator.to_plutus_data(), vrf_keyhash.to_plutus_data()],
719            ),
720
721            Certificate::PoolRetirement(pool_keyhash, epoch) => wrap_multiple_with_constr(
722                8,
723                vec![pool_keyhash.to_plutus_data(), epoch.to_plutus_data()],
724            ),
725
726            Certificate::AuthCommitteeHot(cold_credential, hot_credential) => {
727                wrap_multiple_with_constr(
728                    9,
729                    vec![
730                        cold_credential.to_plutus_data(),
731                        hot_credential.to_plutus_data(),
732                    ],
733                )
734            }
735
736            Certificate::ResignCommitteeCold(cold_credential, _anchor) => {
737                wrap_multiple_with_constr(10, vec![cold_credential.to_plutus_data()])
738            }
739        }
740    }
741}
742
743impl ToPlutusData for DRep {
744    fn to_plutus_data(&self) -> PlutusData {
745        match self {
746            DRep::Key(hash) => {
747                wrap_with_constr(0, StakeCredential::AddrKeyhash(*hash).to_plutus_data())
748            }
749            DRep::Script(hash) => {
750                wrap_with_constr(0, StakeCredential::ScriptHash(*hash).to_plutus_data())
751            }
752            DRep::Abstain => empty_constr(1),
753            DRep::NoConfidence => empty_constr(2),
754        }
755    }
756}
757
758impl ToPlutusData for Redeemer {
759    fn to_plutus_data(&self) -> PlutusData {
760        self.data.clone()
761    }
762}
763
764impl ToPlutusData for PlutusData {
765    fn to_plutus_data(&self) -> PlutusData {
766        self.clone()
767    }
768}
769
770impl ToPlutusData for TimeRange {
771    fn to_plutus_data(&self) -> PlutusData {
772        fn bound(bound: Option<u64>, is_lower: bool) -> PlutusData {
773            match bound {
774                Some(x) => wrap_multiple_with_constr(
775                    0,
776                    vec![
777                        wrap_with_constr(1, x.to_plutus_data()),
778                        // NOTE: Finite lower bounds are always inclusive, unlike upper bounds.
779                        is_lower.to_plutus_data(),
780                    ],
781                ),
782                None => wrap_multiple_with_constr(
783                    0,
784                    vec![
785                        empty_constr(if is_lower { 0 } else { 2 }),
786                        // NOTE: Infinite bounds are always exclusive, by convention.
787                        true.to_plutus_data(),
788                    ],
789                ),
790            }
791        }
792
793        wrap_multiple_with_constr(
794            0,
795            vec![
796                bound(self.lower_bound, true),
797                bound(self.upper_bound, false),
798            ],
799        )
800    }
801}
802
803impl<'a> ToPlutusData
804    for WithOptionDatum<'a, WithZeroAdaAsset<'a, WithWrappedTransactionId<'a, Vec<TxInInfo>>>>
805{
806    fn to_plutus_data(&self) -> PlutusData {
807        Data::list(
808            self.0
809                 .0
810                 .0
811                .iter()
812                .map(|p| {
813                    WithOptionDatum(&WithZeroAdaAsset(&WithWrappedTransactionId(p)))
814                        .to_plutus_data()
815                })
816                .collect(),
817        )
818    }
819}
820
821impl<'a> ToPlutusData for WithZeroAdaAsset<'a, WithWrappedTransactionId<'a, Vec<TxInInfo>>> {
822    fn to_plutus_data(&self) -> PlutusData {
823        Data::list(
824            self.0
825                 .0
826                .iter()
827                .map(|p| WithZeroAdaAsset(&WithWrappedTransactionId(p)).to_plutus_data())
828                .collect(),
829        )
830    }
831}
832
833impl<'a> ToPlutusData for WithZeroAdaAsset<'a, WithWrappedTransactionId<'a, TxInInfo>> {
834    fn to_plutus_data(&self) -> PlutusData {
835        wrap_multiple_with_constr(
836            0,
837            vec![
838                WithWrappedTransactionId(&self.0 .0.out_ref).to_plutus_data(),
839                WithZeroAdaAsset(&self.0 .0.resolved).to_plutus_data(),
840            ],
841        )
842    }
843}
844
845impl<'a> ToPlutusData
846    for WithOptionDatum<'a, WithZeroAdaAsset<'a, WithWrappedTransactionId<'a, TxInInfo>>>
847{
848    fn to_plutus_data(&self) -> PlutusData {
849        wrap_multiple_with_constr(
850            0,
851            vec![
852                WithWrappedTransactionId(&self.0 .0 .0.out_ref).to_plutus_data(),
853                WithOptionDatum(&WithZeroAdaAsset(&self.0 .0 .0.resolved)).to_plutus_data(),
854            ],
855        )
856    }
857}
858
859impl ToPlutusData for TxInInfo {
860    fn to_plutus_data(&self) -> PlutusData {
861        wrap_multiple_with_constr(
862            0,
863            vec![
864                self.out_ref.to_plutus_data(),
865                self.resolved.to_plutus_data(),
866            ],
867        )
868    }
869}
870
871// NOTE: This is a _small_ abuse of the 'WithWrappedTransactionId'. We know the wrapped
872// is needed for V1 and V2, and it also appears that for V1 and V2, the certifying
873// purpose mustn't include the certificate index. So, we also short-circuit it here.
874impl ToPlutusData for WithWrappedTransactionId<'_, ScriptPurpose> {
875    fn to_plutus_data(&self) -> PlutusData {
876        match self.0 {
877            ScriptPurpose::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()),
878            ScriptPurpose::Spending(out_ref, ()) => {
879                wrap_with_constr(1, WithWrappedTransactionId(out_ref).to_plutus_data())
880            }
881            ScriptPurpose::Rewarding(stake_credential) => wrap_with_constr(
882                2,
883                WithWrappedStakeCredential(stake_credential).to_plutus_data(),
884            ),
885            ScriptPurpose::Certifying(_, dcert) => {
886                wrap_with_constr(3, WithPartialCertificates(dcert).to_plutus_data())
887            }
888            purpose => {
889                unreachable!("unsupported purpose for V1 or V2 script context: {purpose:?}")
890            }
891        }
892    }
893}
894
895impl ToPlutusData for WithNeverRegistrationDeposit<'_, ScriptPurpose> {
896    fn to_plutus_data(&self) -> PlutusData {
897        match self.0 {
898            ScriptPurpose::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()),
899            ScriptPurpose::Spending(out_ref, ()) => wrap_with_constr(1, out_ref.to_plutus_data()),
900            ScriptPurpose::Rewarding(stake_credential) => {
901                wrap_with_constr(2, stake_credential.to_plutus_data())
902            }
903            ScriptPurpose::Certifying(ix, dcert) => wrap_multiple_with_constr(
904                3,
905                vec![
906                    ix.to_plutus_data(),
907                    WithNeverRegistrationDeposit(dcert).to_plutus_data(),
908                ],
909            ),
910            ScriptPurpose::Voting(voter) => {
911                wrap_multiple_with_constr(4, vec![voter.to_plutus_data()])
912            }
913            ScriptPurpose::Proposing(ix, procedure) => {
914                wrap_multiple_with_constr(5, vec![ix.to_plutus_data(), procedure.to_plutus_data()])
915            }
916        }
917    }
918}
919
920impl ToPlutusData for ProposalProcedure {
921    fn to_plutus_data(&self) -> PlutusData {
922        wrap_multiple_with_constr(
923            0,
924            vec![
925                self.deposit.to_plutus_data(),
926                Address::from_bytes(&self.reward_account)
927                    .unwrap()
928                    .to_plutus_data(),
929                self.gov_action.to_plutus_data(),
930            ],
931        )
932    }
933}
934
935impl<T> ToPlutusData for Nullable<T>
936where
937    T: ToPlutusData + Clone,
938{
939    fn to_plutus_data(&self) -> PlutusData {
940        match self {
941            Nullable::Some(t) => wrap_with_constr(0, t.to_plutus_data()),
942            Nullable::Null | Nullable::Undefined => empty_constr(1),
943        }
944    }
945}
946
947impl ToPlutusData for GovActionId {
948    fn to_plutus_data(&self) -> PlutusData {
949        wrap_multiple_with_constr(
950            0,
951            vec![
952                self.transaction_id.to_plutus_data(),
953                self.action_index.to_plutus_data(),
954            ],
955        )
956    }
957}
958
959impl ToPlutusData for ProtocolParamUpdate {
960    fn to_plutus_data(&self) -> PlutusData {
961        let mut pparams = Vec::with_capacity(30);
962
963        let mut push = |ix: usize, p: PlutusData| {
964            pparams.push((ix.to_plutus_data(), p));
965        };
966
967        if let Some(p) = self.minfee_a {
968            push(0, p.to_plutus_data());
969        }
970
971        if let Some(p) = self.minfee_b {
972            push(1, p.to_plutus_data());
973        }
974
975        if let Some(p) = self.max_block_body_size {
976            push(2, p.to_plutus_data());
977        }
978
979        if let Some(p) = self.max_transaction_size {
980            push(3, p.to_plutus_data());
981        }
982
983        if let Some(p) = self.max_block_header_size {
984            push(4, p.to_plutus_data());
985        }
986
987        if let Some(p) = self.key_deposit {
988            push(5, p.to_plutus_data());
989        }
990
991        if let Some(p) = self.pool_deposit {
992            push(6, p.to_plutus_data());
993        }
994
995        if let Some(p) = self.maximum_epoch {
996            push(7, p.to_plutus_data());
997        }
998
999        if let Some(p) = self.desired_number_of_stake_pools {
1000            push(8, p.to_plutus_data());
1001        }
1002
1003        if let Some(ref p) = self.pool_pledge_influence {
1004            push(9, WithArrayRational(p).to_plutus_data());
1005        }
1006
1007        if let Some(ref p) = self.expansion_rate {
1008            push(10, WithArrayRational(p).to_plutus_data());
1009        }
1010
1011        if let Some(ref p) = self.treasury_growth_rate {
1012            push(11, WithArrayRational(p).to_plutus_data());
1013        }
1014
1015        if let Some(p) = self.min_pool_cost {
1016            push(16, p.to_plutus_data());
1017        }
1018
1019        if let Some(p) = self.ada_per_utxo_byte {
1020            push(17, p.to_plutus_data());
1021        }
1022
1023        #[allow(clippy::redundant_pattern_matching)]
1024        if let Some(_) = self.cost_models_for_script_languages {
1025            unimplemented!("TODO: ToPlutusData for cost models.");
1026        }
1027
1028        if let Some(ref p) = self.execution_costs {
1029            push(19, p.to_plutus_data());
1030        }
1031
1032        if let Some(p) = self.max_tx_ex_units {
1033            push(20, p.to_plutus_data());
1034        }
1035
1036        if let Some(p) = self.max_block_ex_units {
1037            push(21, p.to_plutus_data());
1038        }
1039
1040        if let Some(p) = self.max_value_size {
1041            push(22, p.to_plutus_data());
1042        }
1043
1044        if let Some(p) = self.collateral_percentage {
1045            push(23, p.to_plutus_data());
1046        }
1047
1048        if let Some(p) = self.max_collateral_inputs {
1049            push(24, p.to_plutus_data());
1050        }
1051
1052        if let Some(ref p) = self.pool_voting_thresholds {
1053            push(25, p.to_plutus_data());
1054        }
1055
1056        if let Some(ref p) = self.drep_voting_thresholds {
1057            push(26, p.to_plutus_data());
1058        }
1059
1060        if let Some(p) = self.min_committee_size {
1061            push(27, p.to_plutus_data());
1062        }
1063
1064        if let Some(p) = self.committee_term_limit {
1065            push(28, p.to_plutus_data());
1066        }
1067
1068        if let Some(p) = self.governance_action_validity_period {
1069            push(29, p.to_plutus_data());
1070        }
1071
1072        if let Some(p) = self.governance_action_deposit {
1073            push(30, p.to_plutus_data());
1074        }
1075
1076        if let Some(p) = self.drep_deposit {
1077            push(31, p.to_plutus_data());
1078        }
1079
1080        if let Some(p) = self.drep_inactivity_period {
1081            push(32, p.to_plutus_data());
1082        }
1083
1084        if let Some(ref p) = self.minfee_refscript_cost_per_byte {
1085            push(33, WithArrayRational(p).to_plutus_data());
1086        }
1087
1088        Data::map(pparams)
1089    }
1090}
1091
1092impl ToPlutusData for PoolVotingThresholds {
1093    fn to_plutus_data(&self) -> PlutusData {
1094        vec![
1095            WithArrayRational(&self.motion_no_confidence).to_plutus_data(),
1096            WithArrayRational(&self.committee_normal).to_plutus_data(),
1097            WithArrayRational(&self.committee_no_confidence).to_plutus_data(),
1098            WithArrayRational(&self.hard_fork_initiation).to_plutus_data(),
1099            WithArrayRational(&self.security_voting_threshold).to_plutus_data(),
1100        ]
1101        .to_plutus_data()
1102    }
1103}
1104
1105impl ToPlutusData for DRepVotingThresholds {
1106    fn to_plutus_data(&self) -> PlutusData {
1107        vec![
1108            WithArrayRational(&self.motion_no_confidence).to_plutus_data(),
1109            WithArrayRational(&self.committee_normal).to_plutus_data(),
1110            WithArrayRational(&self.committee_no_confidence).to_plutus_data(),
1111            WithArrayRational(&self.update_constitution).to_plutus_data(),
1112            WithArrayRational(&self.hard_fork_initiation).to_plutus_data(),
1113            WithArrayRational(&self.pp_network_group).to_plutus_data(),
1114            WithArrayRational(&self.pp_economic_group).to_plutus_data(),
1115            WithArrayRational(&self.pp_technical_group).to_plutus_data(),
1116            WithArrayRational(&self.pp_governance_group).to_plutus_data(),
1117            WithArrayRational(&self.treasury_withdrawal).to_plutus_data(),
1118        ]
1119        .to_plutus_data()
1120    }
1121}
1122
1123impl ToPlutusData for ExUnitPrices {
1124    fn to_plutus_data(&self) -> PlutusData {
1125        vec![
1126            WithArrayRational(&self.mem_price).to_plutus_data(),
1127            WithArrayRational(&self.step_price).to_plutus_data(),
1128        ]
1129        .to_plutus_data()
1130    }
1131}
1132
1133impl ToPlutusData for ExUnits {
1134    fn to_plutus_data(&self) -> PlutusData {
1135        vec![self.mem.to_plutus_data(), self.steps.to_plutus_data()].to_plutus_data()
1136    }
1137}
1138
1139impl ToPlutusData for GovAction {
1140    fn to_plutus_data(&self) -> PlutusData {
1141        match self {
1142            GovAction::ParameterChange(previous_action, params, guardrail) => {
1143                wrap_multiple_with_constr(
1144                    0,
1145                    vec![
1146                        previous_action.to_plutus_data(),
1147                        params.as_ref().to_plutus_data(),
1148                        guardrail.to_plutus_data(),
1149                    ],
1150                )
1151            }
1152            GovAction::HardForkInitiation(previous_action, version) => wrap_multiple_with_constr(
1153                1,
1154                vec![previous_action.to_plutus_data(), version.to_plutus_data()],
1155            ),
1156            GovAction::TreasuryWithdrawals(withdrawals, guardrail) => wrap_multiple_with_constr(
1157                2,
1158                vec![
1159                    KeyValuePairs::from(
1160                        withdrawals
1161                            .iter()
1162                            .map(|(reward_account, amount)| {
1163                                (
1164                                    Address::from_bytes(reward_account)
1165                                        .expect("Invalid stake address in treasury withdrawal?"),
1166                                    *amount,
1167                                )
1168                            })
1169                            .collect::<Vec<_>>(),
1170                    )
1171                    .to_plutus_data(),
1172                    guardrail.to_plutus_data(),
1173                ],
1174            ),
1175            GovAction::NoConfidence(previous_action) => {
1176                wrap_with_constr(3, previous_action.to_plutus_data())
1177            }
1178            GovAction::UpdateCommittee(previous_action, removed, added, quorum) => {
1179                wrap_multiple_with_constr(
1180                    4,
1181                    vec![
1182                        previous_action.to_plutus_data(),
1183                        removed.to_plutus_data(),
1184                        added.to_plutus_data(),
1185                        quorum.to_plutus_data(),
1186                    ],
1187                )
1188            }
1189            GovAction::NewConstitution(previous_action, constitution) => wrap_multiple_with_constr(
1190                5,
1191                vec![
1192                    previous_action.to_plutus_data(),
1193                    constitution.to_plutus_data(),
1194                ],
1195            ),
1196            GovAction::Information => empty_constr(6),
1197        }
1198    }
1199}
1200
1201impl ToPlutusData for Constitution {
1202    fn to_plutus_data(&self) -> PlutusData {
1203        wrap_with_constr(0, self.guardrail_script.to_plutus_data())
1204    }
1205}
1206
1207impl ToPlutusData for RationalNumber {
1208    fn to_plutus_data(&self) -> PlutusData {
1209        let gcd = self.numerator.gcd(&self.denominator);
1210        (self.numerator / gcd, self.denominator / gcd).to_plutus_data()
1211    }
1212}
1213
1214impl ToPlutusData for WithArrayRational<'_, RationalNumber> {
1215    fn to_plutus_data(&self) -> PlutusData {
1216        let gcd = self.0.numerator.gcd(&self.0.denominator);
1217        vec![self.0.numerator / gcd, self.0.denominator / gcd].to_plutus_data()
1218    }
1219}
1220
1221impl ToPlutusData for WithWrappedStakeCredential<'_, Vec<(Address, Coin)>> {
1222    fn to_plutus_data(&self) -> PlutusData {
1223        self.0
1224            .iter()
1225            .map(|(reward_account, amount)| {
1226                (
1227                    wrap_with_constr(0, reward_account.to_plutus_data()),
1228                    *amount,
1229                )
1230            })
1231            .collect::<Vec<_>>()
1232            .to_plutus_data()
1233    }
1234}
1235
1236impl ToPlutusData for WithWrappedStakeCredential<'_, KeyValuePairs<Address, Coin>> {
1237    fn to_plutus_data(&self) -> PlutusData {
1238        KeyValuePairs::from(
1239            self.0
1240                .iter()
1241                .map(|(reward_account, amount)| {
1242                    (
1243                        wrap_with_constr(0, reward_account.to_plutus_data()),
1244                        *amount,
1245                    )
1246                })
1247                .collect::<Vec<_>>(),
1248        )
1249        .to_plutus_data()
1250    }
1251}
1252
1253impl ToPlutusData for WithWrappedStakeCredential<'_, StakeCredential> {
1254    fn to_plutus_data(&self) -> PlutusData {
1255        wrap_with_constr(0, self.0.to_plutus_data())
1256    }
1257}
1258
1259impl ToPlutusData for Voter {
1260    fn to_plutus_data(&self) -> PlutusData {
1261        match self {
1262            Voter::ConstitutionalCommitteeScript(hash) => {
1263                wrap_with_constr(0, StakeCredential::ScriptHash(*hash).to_plutus_data())
1264            }
1265            Voter::ConstitutionalCommitteeKey(hash) => {
1266                wrap_with_constr(0, StakeCredential::AddrKeyhash(*hash).to_plutus_data())
1267            }
1268            Voter::DRepScript(hash) => {
1269                wrap_with_constr(1, StakeCredential::ScriptHash(*hash).to_plutus_data())
1270            }
1271            Voter::DRepKey(hash) => {
1272                wrap_with_constr(1, StakeCredential::AddrKeyhash(*hash).to_plutus_data())
1273            }
1274            Voter::StakePoolKey(hash) => wrap_with_constr(2, hash.to_plutus_data()),
1275        }
1276    }
1277}
1278
1279impl ToPlutusData for VotingProcedure {
1280    fn to_plutus_data(&self) -> PlutusData {
1281        self.vote.to_plutus_data()
1282    }
1283}
1284
1285impl ToPlutusData for Vote {
1286    fn to_plutus_data(&self) -> PlutusData {
1287        match self {
1288            Vote::No => empty_constr(0),
1289            Vote::Yes => empty_constr(1),
1290            Vote::Abstain => empty_constr(2),
1291        }
1292    }
1293}
1294
1295impl<T> ToPlutusData for WithNeverRegistrationDeposit<'_, ScriptInfo<T>>
1296where
1297    T: ToPlutusData,
1298{
1299    fn to_plutus_data(&self) -> PlutusData {
1300        match self.0 {
1301            ScriptInfo::Minting(policy_id) => wrap_with_constr(0, policy_id.to_plutus_data()),
1302            ScriptInfo::Spending(out_ref, datum) => {
1303                wrap_multiple_with_constr(1, vec![out_ref.to_plutus_data(), datum.to_plutus_data()])
1304            }
1305            ScriptInfo::Rewarding(stake_credential) => {
1306                wrap_with_constr(2, stake_credential.to_plutus_data())
1307            }
1308            ScriptInfo::Certifying(ix, dcert) => wrap_multiple_with_constr(
1309                3,
1310                vec![
1311                    ix.to_plutus_data(),
1312                    WithNeverRegistrationDeposit(dcert).to_plutus_data(),
1313                ],
1314            ),
1315            ScriptInfo::Voting(voter) => wrap_multiple_with_constr(4, vec![voter.to_plutus_data()]),
1316            ScriptInfo::Proposing(ix, procedure) => {
1317                wrap_multiple_with_constr(5, vec![ix.to_plutus_data(), procedure.to_plutus_data()])
1318            }
1319        }
1320    }
1321}
1322
1323impl ToPlutusData for TxInfo {
1324    fn to_plutus_data(&self) -> PlutusData {
1325        match self {
1326            TxInfo::V1(tx_info) => wrap_multiple_with_constr(
1327                0,
1328                vec![
1329                    WithOptionDatum(&WithZeroAdaAsset(&WithWrappedTransactionId(
1330                        &tx_info.inputs,
1331                    )))
1332                    .to_plutus_data(),
1333                    WithOptionDatum(&WithZeroAdaAsset(&tx_info.outputs)).to_plutus_data(),
1334                    WithZeroAdaAsset(&tx_info.fee).to_plutus_data(),
1335                    WithZeroAdaAsset(&tx_info.mint).to_plutus_data(),
1336                    WithPartialCertificates(&tx_info.certificates).to_plutus_data(),
1337                    WithWrappedStakeCredential(&tx_info.withdrawals).to_plutus_data(),
1338                    tx_info.valid_range.to_plutus_data(),
1339                    tx_info.signatories.to_plutus_data(),
1340                    tx_info.data.to_plutus_data(),
1341                    wrap_with_constr(0, tx_info.id.to_plutus_data()),
1342                ],
1343            ),
1344            TxInfo::V2(tx_info) => wrap_multiple_with_constr(
1345                0,
1346                vec![
1347                    WithZeroAdaAsset(&WithWrappedTransactionId(&tx_info.inputs)).to_plutus_data(),
1348                    WithZeroAdaAsset(&WithWrappedTransactionId(&tx_info.reference_inputs))
1349                        .to_plutus_data(),
1350                    WithZeroAdaAsset(&tx_info.outputs).to_plutus_data(),
1351                    WithZeroAdaAsset(&tx_info.fee).to_plutus_data(),
1352                    WithZeroAdaAsset(&tx_info.mint).to_plutus_data(),
1353                    WithPartialCertificates(&tx_info.certificates).to_plutus_data(),
1354                    WithWrappedStakeCredential(&tx_info.withdrawals).to_plutus_data(),
1355                    tx_info.valid_range.to_plutus_data(),
1356                    tx_info.signatories.to_plutus_data(),
1357                    WithWrappedTransactionId(&tx_info.redeemers).to_plutus_data(),
1358                    tx_info.data.to_plutus_data(),
1359                    wrap_with_constr(0, tx_info.id.to_plutus_data()),
1360                ],
1361            ),
1362            TxInfo::V3(tx_info) => wrap_multiple_with_constr(
1363                0,
1364                vec![
1365                    tx_info.inputs.to_plutus_data(),
1366                    tx_info.reference_inputs.to_plutus_data(),
1367                    tx_info.outputs.to_plutus_data(),
1368                    tx_info.fee.to_plutus_data(),
1369                    tx_info.mint.to_plutus_data(),
1370                    WithNeverRegistrationDeposit(&tx_info.certificates).to_plutus_data(),
1371                    tx_info.withdrawals.to_plutus_data(),
1372                    tx_info.valid_range.to_plutus_data(),
1373                    tx_info.signatories.to_plutus_data(),
1374                    WithNeverRegistrationDeposit(&tx_info.redeemers).to_plutus_data(),
1375                    tx_info.data.to_plutus_data(),
1376                    tx_info.id.to_plutus_data(),
1377                    tx_info.votes.to_plutus_data(),
1378                    tx_info.proposal_procedures.to_plutus_data(),
1379                    tx_info.current_treasury_amount.to_plutus_data(),
1380                    tx_info.treasury_donation.to_plutus_data(),
1381                ],
1382            ),
1383        }
1384    }
1385}
1386
1387impl ToPlutusData for ScriptContext {
1388    fn to_plutus_data(&self) -> PlutusData {
1389        match self {
1390            ScriptContext::V1V2 { tx_info, purpose } => wrap_multiple_with_constr(
1391                0,
1392                vec![
1393                    tx_info.to_plutus_data(),
1394                    WithWrappedTransactionId(purpose.as_ref()).to_plutus_data(),
1395                ],
1396            ),
1397            ScriptContext::V3 {
1398                tx_info,
1399                redeemer,
1400                purpose,
1401            } => wrap_multiple_with_constr(
1402                0,
1403                vec![
1404                    tx_info.to_plutus_data(),
1405                    redeemer.to_plutus_data(),
1406                    WithNeverRegistrationDeposit(purpose.as_ref()).to_plutus_data(),
1407                ],
1408            ),
1409        }
1410    }
1411}