1use std::collections::BTreeMap;
4use std::future::Future;
5use std::str::FromStr;
6
7use chrono::{DateTime, Duration, Utc};
8use plutus_ledger_api::csl::{csl_to_pla::ToPLA, lib as csl};
9use plutus_ledger_api::v3::{
10 address::Address,
11 datum::OutputDatum,
12 transaction::{TransactionInput, TransactionOutput},
13 value::Value,
14};
15use serde::Deserialize;
16use thiserror::Error;
17
18use crate::utils::script::Script;
19
20pub trait ChainQuery {
22 fn get_network(&self) -> Network;
24
25 fn query_system_start(&self) -> impl Future<Output = Result<DateTime<Utc>, ChainQueryError>>;
26
27 fn query_era_summaries(&self)
28 -> impl Future<Output = Result<Vec<EraSummary>, ChainQueryError>>;
29 fn query_protocol_params(
31 &self,
32 ) -> impl Future<Output = Result<ProtocolParameters, ChainQueryError>>;
33
34 fn query_tip(&self) -> impl Future<Output = Result<ChainTip, ChainQueryError>>;
35
36 fn query_utxos_by_addr(
38 &self,
39 address: &Address,
40 ) -> impl Future<Output = Result<BTreeMap<TransactionInput, FullTransactionOutput>, ChainQueryError>>;
41
42 fn query_utxos_by_ref(
43 &self,
44 references: Vec<&TransactionInput>,
45 ) -> impl Future<Output = Result<BTreeMap<TransactionInput, FullTransactionOutput>, ChainQueryError>>;
46}
47
48#[derive(Debug, Clone, Deserialize)]
50pub enum Network {
51 Testnet = 0b0000,
52 Mainnet = 0b0001,
53}
54
55impl Network {
56 pub fn to_network_id(&self) -> u8 {
57 match self {
58 Network::Testnet => 0b0000,
59 Network::Mainnet => 0b0001,
60 }
61 }
62}
63
64impl FromStr for Network {
65 type Err = String;
66
67 fn from_str(str: &str) -> Result<Network, Self::Err> {
68 match str {
69 "mainnet" => Ok(Network::Mainnet),
70 "testnet" => Ok(Network::Testnet),
71 _ => Err(format!("Invalid network variant: {}", str)),
72 }
73 }
74}
75
76#[derive(Error, Debug)]
77#[error(transparent)]
78pub struct ChainQueryError(pub anyhow::Error);
79
80#[derive(Debug, Clone)]
81pub struct EraSummary {
82 pub start: EraTime,
83 pub end: Option<EraTime>,
84 pub parameters: EraParameters,
85}
86
87#[derive(Debug, Clone)]
88pub struct EraTime {
89 pub time: Duration,
90 pub slot: u64,
91 pub epoch: u64,
92}
93
94#[derive(Debug, Clone)]
95pub struct EraParameters {
96 pub epoch_length: u64,
97 pub slot_length: u64,
98 pub safe_zone: Option<u64>,
99}
100
101#[derive(Debug, Clone)]
104pub struct ProtocolParameters {
105 pub min_fee_coefficient: csl::Coin,
106 pub min_fee_constant: csl::Coin,
107 pub min_fee_reference_scripts: Option<csl::UnitInterval>,
108 pub min_utxo_deposit_coefficient: csl::Coin,
109 pub min_utxo_deposit_constant: csl::Coin,
110 pub max_transaction_size: Option<u32>,
113 pub max_value_size: Option<u32>,
114 pub stake_credential_deposit: csl::Coin,
116 pub stake_pool_deposit: csl::Coin,
117 pub plutus_cost_models: Option<csl::Costmdls>,
127 pub script_execution_prices: Option<csl::ExUnitPrices>,
128 }
142
143#[derive(Debug, Clone)]
144pub enum ChainTip {
145 Origin,
146 Point { slot: u64, id: String },
147}
148
149impl ChainTip {
150 pub fn slot(&self) -> u64 {
151 match self {
152 ChainTip::Origin => 0,
153 ChainTip::Point { slot, id: _ } => *slot,
154 }
155 }
156}
157
158#[derive(Debug, Clone)]
159pub struct FullTransactionOutput {
160 pub address: Address,
161 pub value: Value,
162 pub datum: OutputDatum,
163 pub reference_script: Option<Script>,
164}
165
166impl From<FullTransactionOutput> for TransactionOutput {
167 fn from(full_tx_out: FullTransactionOutput) -> TransactionOutput {
168 TransactionOutput {
169 address: full_tx_out.address,
170 value: full_tx_out.value,
171 datum: full_tx_out.datum,
172 reference_script: full_tx_out.reference_script.map(|script| match script {
173 Script::PlutusScript(script) => script.hash().to_pla(),
174 Script::NativeScript(script) => script.hash().to_pla(),
175 }),
176 }
177 }
178}
179
180impl From<&FullTransactionOutput> for TransactionOutput {
181 fn from(full_tx_out: &FullTransactionOutput) -> TransactionOutput {
182 full_tx_out.clone().into()
183 }
184}