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, Copy, Deserialize)]
50pub enum Network {
51 Testnet = 0b0000,
52 Mainnet = 0b0001,
53}
54
55impl Network {
56 pub fn to_network_id(&self) -> u8 {
57 *self as u8
58 }
59}
60
61impl FromStr for Network {
62 type Err = String;
63
64 fn from_str(str: &str) -> Result<Network, Self::Err> {
65 match str {
66 "mainnet" => Ok(Network::Mainnet),
67 "testnet" => Ok(Network::Testnet),
68 _ => Err(format!("Invalid network variant: {}", str)),
69 }
70 }
71}
72
73#[derive(Error, Debug)]
74#[error(transparent)]
75pub struct ChainQueryError(pub anyhow::Error);
76
77#[derive(Debug, Clone)]
78pub struct EraSummary {
79 pub start: EraTime,
80 pub end: Option<EraTime>,
81 pub parameters: EraParameters,
82}
83
84#[derive(Debug, Clone)]
85pub struct EraTime {
86 pub time: Duration,
87 pub slot: u64,
88 pub epoch: u64,
89}
90
91#[derive(Debug, Clone)]
92pub struct EraParameters {
93 pub epoch_length: u64,
94 pub slot_length: u64,
95 pub safe_zone: Option<u64>,
96}
97
98#[derive(Debug, Clone)]
101pub struct ProtocolParameters {
102 pub min_fee_coefficient: csl::Coin,
103 pub min_fee_constant: csl::Coin,
104 pub min_fee_reference_scripts: Option<csl::UnitInterval>,
105 pub min_utxo_deposit_coefficient: csl::Coin,
106 pub min_utxo_deposit_constant: csl::Coin,
107 pub max_transaction_size: Option<u32>,
110 pub max_value_size: Option<u32>,
111 pub stake_credential_deposit: csl::Coin,
113 pub stake_pool_deposit: csl::Coin,
114 pub plutus_cost_models: Option<csl::Costmdls>,
124 pub script_execution_prices: Option<csl::ExUnitPrices>,
125 }
139
140#[derive(Debug, Clone)]
141pub enum ChainTip {
142 Origin,
143 Point { slot: u64, id: String },
144}
145
146impl ChainTip {
147 pub fn slot(&self) -> u64 {
148 match self {
149 ChainTip::Origin => 0,
150 ChainTip::Point { slot, id: _ } => *slot,
151 }
152 }
153}
154
155#[derive(Debug, Clone)]
156pub struct FullTransactionOutput {
157 pub address: Address,
158 pub value: Value,
159 pub datum: OutputDatum,
160 pub reference_script: Option<Script>,
161}
162
163impl From<FullTransactionOutput> for TransactionOutput {
164 fn from(full_tx_out: FullTransactionOutput) -> TransactionOutput {
165 TransactionOutput {
166 address: full_tx_out.address,
167 value: full_tx_out.value,
168 datum: full_tx_out.datum,
169 reference_script: full_tx_out.reference_script.map(|script| match script {
170 Script::PlutusScript(script) => script.hash().to_pla(),
171 Script::NativeScript(script) => script.hash().to_pla(),
172 }),
173 }
174 }
175}
176
177impl From<&FullTransactionOutput> for TransactionOutput {
178 fn from(full_tx_out: &FullTransactionOutput) -> TransactionOutput {
179 full_tx_out.clone().into()
180 }
181}