1use std::{fmt, str::FromStr};
4
5use anyhow::anyhow;
6use cardano_serialization_lib as csl;
7#[cfg(feature = "lbf")]
8use lbr_prelude::json::Json;
9use nom::{
10 character::complete::char,
11 combinator::{all_consuming, map, map_res},
12 error::{context, VerboseError},
13 sequence::{preceded, tuple},
14 Finish, IResult,
15};
16use num_bigint::BigInt;
17#[cfg(feature = "serde")]
18use serde::{Deserialize, Serialize};
19
20#[cfg(feature = "chrono")]
21pub use crate::v1::transaction::POSIXTimeConversionError;
22pub use crate::v2::transaction::{
23 DCert, POSIXTime, POSIXTimeRange, TransactionOutput, TransactionOutputWithExtraInfo,
24 WithdrawalsWithExtraInfo,
25};
26use crate::{
27 self as plutus_ledger_api,
28 aux::{big_int, guard_bytes},
29 csl::{
30 csl_to_pla::FromCSL,
31 pla_to_csl::{TryFromPLA, TryFromPLAError, TryToCSL},
32 },
33 error::ConversionError,
34 plutus_data::{IsPlutusData, PlutusData},
35 v2::{
36 address::Credential,
37 assoc_map::AssocMap,
38 crypto::{PaymentPubKeyHash, StakePubKeyHash},
39 datum::{Datum, DatumHash},
40 redeemer::Redeemer,
41 script::ScriptHash,
42 value::{CurrencySymbol, Lovelace, Value},
43 },
44};
45
46use super::{
47 crypto::{ledger_bytes, Ed25519PubKeyHash, LedgerBytes},
48 ratio::Rational,
49};
50
51#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
61#[is_plutus_data_derive_strategy = "Newtype"]
62#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
63#[cfg_attr(feature = "lbf", derive(Json))]
64pub struct TransactionHash(pub LedgerBytes);
65
66impl fmt::Display for TransactionHash {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(f, "{}", self.0)
69 }
70}
71
72impl TransactionHash {
73 pub fn from_bytes(bytes: Vec<u8>) -> Result<Self, ConversionError> {
74 Ok(TransactionHash(LedgerBytes(guard_bytes(
75 "ScriptHash",
76 bytes,
77 32,
78 )?)))
79 }
80}
81
82impl FromCSL<csl::TransactionHash> for TransactionHash {
83 fn from_csl(value: &csl::TransactionHash) -> Self {
84 TransactionHash(LedgerBytes(value.to_bytes()))
85 }
86}
87
88impl TryFromPLA<TransactionHash> for csl::TransactionHash {
89 fn try_from_pla(val: &TransactionHash) -> Result<Self, TryFromPLAError> {
90 csl::TransactionHash::from_bytes(val.0 .0.to_owned())
91 .map_err(TryFromPLAError::CSLDeserializeError)
92 }
93}
94
95pub(crate) fn transaction_hash(input: &str) -> IResult<&str, TransactionHash, VerboseError<&str>> {
99 context(
100 "transaction_hash",
101 map_res(ledger_bytes, |LedgerBytes(bytes)| {
102 TransactionHash::from_bytes(bytes)
103 }),
104 )(input)
105}
106
107impl FromStr for TransactionHash {
108 type Err = ConversionError;
109
110 fn from_str(s: &str) -> Result<Self, Self::Err> {
111 all_consuming(transaction_hash)(s)
112 .finish()
113 .map_err(|err| {
114 ConversionError::ParseError(anyhow!(
115 "Error while parsing TransactionHash '{}': {}",
116 s,
117 err
118 ))
119 })
120 .map(|(_, cs)| cs)
121 }
122}
123
124#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
133#[is_plutus_data_derive_strategy = "Constr"]
134#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
135#[cfg_attr(feature = "lbf", derive(Json))]
136pub struct TransactionInput {
137 pub transaction_id: TransactionHash,
138 pub index: BigInt,
139}
140
141impl fmt::Display for TransactionInput {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 write!(f, "{}#{}", self.transaction_id.0, self.index)
145 }
146}
147
148impl FromCSL<csl::TransactionInput> for TransactionInput {
149 fn from_csl(value: &csl::TransactionInput) -> Self {
150 TransactionInput {
151 transaction_id: TransactionHash::from_csl(&value.transaction_id()),
152 index: BigInt::from_csl(&value.index()),
153 }
154 }
155}
156
157impl TryFromPLA<TransactionInput> for csl::TransactionInput {
158 fn try_from_pla(val: &TransactionInput) -> Result<Self, TryFromPLAError> {
159 Ok(csl::TransactionInput::new(
160 &val.transaction_id.try_to_csl()?,
161 val.index.try_to_csl()?,
162 ))
163 }
164}
165
166impl FromCSL<csl::TransactionInputs> for Vec<TransactionInput> {
167 fn from_csl(value: &csl::TransactionInputs) -> Self {
168 (0..value.len())
169 .map(|idx| TransactionInput::from_csl(&value.get(idx)))
170 .collect()
171 }
172}
173
174impl TryFromPLA<Vec<TransactionInput>> for csl::TransactionInputs {
175 fn try_from_pla(val: &Vec<TransactionInput>) -> Result<Self, TryFromPLAError> {
176 val.iter()
177 .try_fold(csl::TransactionInputs::new(), |mut acc, input| {
178 acc.add(&input.try_to_csl()?);
179 Ok(acc)
180 })
181 }
182}
183
184pub(crate) fn transaction_input(
188 input: &str,
189) -> IResult<&str, TransactionInput, VerboseError<&str>> {
190 map(
191 tuple((transaction_hash, preceded(char('#'), big_int))),
192 |(transaction_id, index)| TransactionInput {
193 transaction_id,
194 index,
195 },
196 )(input)
197}
198
199impl FromStr for TransactionInput {
200 type Err = ConversionError;
201
202 fn from_str(s: &str) -> Result<Self, Self::Err> {
203 all_consuming(transaction_input)(s)
204 .finish()
205 .map_err(|err| {
206 ConversionError::ParseError(anyhow!(
207 "Error while parsing TransactionInput '{}': {}",
208 s,
209 err
210 ))
211 })
212 .map(|(_, cs)| cs)
213 }
214}
215
216#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
221#[is_plutus_data_derive_strategy = "Newtype"]
222#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
223#[cfg_attr(feature = "lbf", derive(Json))]
224pub struct ColdCommitteeCredential(pub Credential);
225
226#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
231#[is_plutus_data_derive_strategy = "Newtype"]
232#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
233#[cfg_attr(feature = "lbf", derive(Json))]
234pub struct HotCommitteeCredential(pub Credential);
235
236#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
241#[is_plutus_data_derive_strategy = "Newtype"]
242#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
243#[cfg_attr(feature = "lbf", derive(Json))]
244pub struct DRepCredential(pub Credential);
245
246#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
251#[is_plutus_data_derive_strategy = "Constr"]
252#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
253#[cfg_attr(feature = "lbf", derive(Json))]
254pub enum DRep {
255 DRep(DRepCredential),
256 AlwaysAbstain,
257 AlwaysNoConfidence,
258}
259
260#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
265#[is_plutus_data_derive_strategy = "Constr"]
266#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
267#[cfg_attr(feature = "lbf", derive(Json))]
268pub enum Delegatee {
269 Stake(StakePubKeyHash),
270 Vote(DRep),
271 StakeVote(StakePubKeyHash, DRep),
272}
273
274#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
279#[is_plutus_data_derive_strategy = "Constr"]
280#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
281#[cfg_attr(feature = "lbf", derive(Json))]
282pub enum TxCert {
283 RegStaking(Credential, Option<Lovelace>),
285 UnRegStaking(Credential, Option<Lovelace>),
287 DelegStaking(Credential, Delegatee),
289 RegDeleg(Credential, Delegatee, Lovelace),
291 RegDRep(DRepCredential, Lovelace),
293 UpdateDRep(DRepCredential),
295 UnRegDRep(DRepCredential, Lovelace),
297 PoolRegister(
299 Ed25519PubKeyHash,
301 Ed25519PubKeyHash,
303 ),
304 PoolRetire(Ed25519PubKeyHash, BigInt),
306 AuthHotCommittee(ColdCommitteeCredential, HotCommitteeCredential),
308 ResignColdCommittee(ColdCommitteeCredential),
309}
310
311#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
316#[is_plutus_data_derive_strategy = "Constr"]
317#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
318#[cfg_attr(feature = "lbf", derive(Json))]
319pub enum Voter {
320 CommitteeVoter(HotCommitteeCredential),
321 DRepVoter(DRepCredential),
322 StakePoolVoter(Ed25519PubKeyHash),
323}
324
325#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
330#[is_plutus_data_derive_strategy = "Constr"]
331#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
332#[cfg_attr(feature = "lbf", derive(Json))]
333pub enum Vote {
334 VoteNo,
335 VoteYes,
336 Abstain,
337}
338
339#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
345#[is_plutus_data_derive_strategy = "Constr"]
346#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
347#[cfg_attr(feature = "lbf", derive(Json))]
348pub struct GovernanceActionId {
349 pub tx_id: TransactionHash,
350 pub gov_action_id: BigInt,
351}
352
353#[derive(Clone, Debug, PartialEq, Eq, IsPlutusData)]
358#[is_plutus_data_derive_strategy = "Constr"]
359#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
360#[cfg_attr(feature = "lbf", derive(Json))]
361pub struct Committee {
362 pub members: AssocMap<ColdCommitteeCredential, BigInt>,
364 pub quorum: Rational,
366}
367
368#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
373#[is_plutus_data_derive_strategy = "Constr"]
374#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
375#[cfg_attr(feature = "lbf", derive(Json))]
376pub struct Constitution {
377 pub constitution_script: Option<ScriptHash>,
379}
380
381#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
386#[is_plutus_data_derive_strategy = "Constr"]
387#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
388#[cfg_attr(feature = "lbf", derive(Json))]
389pub struct ProtocolVersion {
390 pub major: BigInt,
391 pub minor: BigInt,
392}
393
394#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
401#[is_plutus_data_derive_strategy = "Newtype"]
402#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
403#[cfg_attr(feature = "lbf", derive(Json))]
404pub struct ChangedParameters(pub PlutusData);
405
406#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, IsPlutusData)]
411#[is_plutus_data_derive_strategy = "Constr"]
412#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
413#[cfg_attr(feature = "lbf", derive(Json))]
414pub enum GovernanceAction {
415 ParameterChange(
417 Option<GovernanceActionId>,
418 ChangedParameters,
419 Option<ScriptHash>,
421 ),
422 HardForkInitiation(Option<GovernanceActionId>, ProtocolVersion),
424 TreasuryWithdrawals(
426 AssocMap<Credential, Lovelace>,
427 Option<ScriptHash>,
429 ),
430 NoConfidence(Option<GovernanceActionId>),
432 UpdateCommittee(
434 Option<GovernanceActionId>,
435 Vec<ColdCommitteeCredential>,
437 AssocMap<ColdCommitteeCredential, BigInt>,
439 Rational,
441 ),
442 NewConstitution(Option<GovernanceActionId>, Constitution),
444 InfoAction,
445}
446
447#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, IsPlutusData)]
452#[is_plutus_data_derive_strategy = "Constr"]
453#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
454#[cfg_attr(feature = "lbf", derive(Json))]
455pub struct ProposalProcedure {
456 pub deposit: Lovelace,
457 pub return_addr: Credential,
458 pub governance_action: GovernanceAction,
459}
460
461#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, IsPlutusData)]
466#[is_plutus_data_derive_strategy = "Constr"]
467#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
468#[cfg_attr(feature = "lbf", derive(Json))]
469pub enum ScriptPurpose {
470 Minting(CurrencySymbol),
471 Spending(TransactionInput),
472 Rewarding(Credential),
473 Certifying(
474 BigInt,
476 TxCert,
477 ),
478 Voting(Voter),
479 Proposing(
480 BigInt,
482 ProposalProcedure,
483 ),
484}
485
486#[derive(Clone, Debug, PartialEq, Eq, IsPlutusData)]
491#[is_plutus_data_derive_strategy = "Constr"]
492#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
493#[cfg_attr(feature = "lbf", derive(Json))]
494pub enum ScriptInfo {
495 Minting(CurrencySymbol),
496 Spending(TransactionInput, Option<Datum>),
497 Rewarding(Credential),
498 Certifying(BigInt, TxCert),
499 Voting(Voter),
500 Proposing(BigInt, ProposalProcedure),
501}
502
503#[derive(Clone, Debug, PartialEq, Eq, IsPlutusData)]
508#[is_plutus_data_derive_strategy = "Constr"]
509#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
510#[cfg_attr(feature = "lbf", derive(Json))]
511pub struct TransactionInfo {
512 pub inputs: Vec<TxInInfo>,
513 pub reference_inputs: Vec<TxInInfo>,
514 pub outputs: Vec<TransactionOutput>,
515 pub fee: Lovelace,
516 pub mint: Value,
517 pub tx_certs: Vec<TxCert>,
518 pub wdrl: AssocMap<Credential, Lovelace>,
519 pub valid_range: POSIXTimeRange,
520 pub signatories: Vec<PaymentPubKeyHash>,
521 pub redeemers: AssocMap<ScriptPurpose, Redeemer>,
522 pub datums: AssocMap<DatumHash, Datum>,
523 pub id: TransactionHash,
524 pub votes: AssocMap<Voter, AssocMap<GovernanceActionId, Vote>>,
525 pub proposal_procedures: Vec<ProposalProcedure>,
526 pub current_treasury_amount: Option<Lovelace>,
527 pub treasury_donation: Option<Lovelace>,
528}
529
530#[derive(Clone, Debug, PartialEq, Eq, IsPlutusData)]
536#[is_plutus_data_derive_strategy = "Constr"]
537#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
538#[cfg_attr(feature = "lbf", derive(Json))]
539pub struct TxInInfo {
540 pub reference: TransactionInput,
541 pub output: TransactionOutput,
542}
543
544impl From<(TransactionInput, TransactionOutput)> for TxInInfo {
545 fn from((reference, output): (TransactionInput, TransactionOutput)) -> TxInInfo {
546 TxInInfo { reference, output }
547 }
548}
549
550#[derive(Clone, Debug, PartialEq, Eq, IsPlutusData)]
555#[is_plutus_data_derive_strategy = "Constr"]
556#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
557#[cfg_attr(feature = "lbf", derive(Json))]
558pub struct ScriptContext {
559 pub tx_info: TransactionInfo,
560 pub redeemer: Redeemer,
561 pub script_info: ScriptInfo,
562}