whisky_provider/blockfrost/
mod.rs

1mod evaluator;
2mod fetcher;
3pub mod models;
4mod submitter;
5pub mod utils;
6use std::collections::HashMap;
7
8use whisky_common::*;
9
10use reqwest::RequestBuilder;
11use serde::Serialize;
12
13#[derive(Debug, Clone)]
14pub struct Blockfrost {
15    project_id: String,
16    http_client: reqwest::Client,
17    pub base_url: String,
18}
19
20impl Blockfrost {
21    pub fn new(project_id: String, network: String) -> Self {
22        let base_url = format!("https://cardano-{}.blockfrost.io/api/v0", &network);
23        let http_client = reqwest::Client::builder()
24            .timeout(std::time::Duration::from_secs(300))
25            .build()
26            .expect("Failed to create HTTP client");
27
28        Blockfrost {
29            project_id,
30            http_client,
31            base_url,
32        }
33    }
34
35    async fn send_request(
36        &self,
37        req: RequestBuilder,
38        response_body: &mut String,
39    ) -> Result<(), Box<dyn std::error::Error>> {
40        let req = req
41            .header("Accept", "application/json")
42            .header("project_id", &self.project_id)
43            .build()?;
44
45        let response = self.http_client.execute(req).await?;
46
47        if response.status().is_success() {
48            *response_body = response.text().await?;
49            Ok(())
50        } else {
51            Err(format!("Error: {}", response.status()).into())
52        }
53    }
54
55    pub async fn get(&self, url: &str) -> Result<String, WError> {
56        let req = self.http_client.get(format!("{}{}", &self.base_url, url));
57        let mut response_body = String::new();
58        self.send_request(req, &mut response_body)
59            .await
60            .map_err(WError::from_err("Blockfrost - get - send_request"))?;
61        Ok(response_body)
62    }
63
64    pub async fn post<T: Serialize>(&self, url: &str, body: T) -> Result<String, WError> {
65        let json_body = serde_json::to_string(&body)
66            .map_err(WError::from_err("Blockfrost - post - json_body"))?;
67
68        let req = self
69            .http_client
70            .post(format!("{}{}", &self.base_url, url))
71            .header("Content-Type", "application/json")
72            .body(json_body);
73
74        let mut response_body = String::new();
75        self.send_request(req, &mut response_body)
76            .await
77            .map_err(WError::from_err("Blockfrost - post - send_request"))?;
78        Ok(response_body)
79    }
80
81    async fn fetch_specific_script(&self, script_hash: &str) -> Result<models::Script, WError> {
82        let url = format!("/scripts/{}", script_hash);
83
84        let resp = self
85            .get(&url)
86            .await
87            .map_err(WError::from_err("blockfrost::fetch_specific_script"))?;
88
89        let script: models::Script = serde_json::from_str(&resp).map_err(WError::from_err(
90            "blockfrost::fetch_specific_script type error",
91        ))?;
92
93        Ok(script)
94    }
95    async fn fetch_plutus_script_cbor(&self, script_hash: &str) -> Result<String, WError> {
96        let url = format!("/scripts/{}/cbor", script_hash);
97
98        let resp = self
99            .get(&url)
100            .await
101            .map_err(WError::from_err("blockfrost::fetch_plutus_script_cbor"))?;
102
103        let script_cbor: HashMap<String, String> = serde_json::from_str(&resp).map_err(
104            WError::from_err("blockfrost::fetch_plutus_script_cbor type error"),
105        )?;
106        let cbor = script_cbor["cbor"].clone();
107
108        Ok(cbor)
109    }
110
111    async fn fetch_native_script_json(
112        &self,
113        script_hash: &str,
114    ) -> Result<serde_json::Value, WError> {
115        let url = format!("/scripts/{}/json", script_hash);
116
117        let resp = self
118            .get(&url)
119            .await
120            .map_err(WError::from_err("blockfrost::fetch_native_script_json"))?;
121
122        let script_json: HashMap<String, serde_json::Value> = serde_json::from_str(&resp).map_err(
123            WError::from_err("blockfrost::fetch_native_script_json type error"),
124        )?;
125        let json = script_json["json"].clone();
126
127        Ok(json)
128    }
129}
130
131#[derive(Clone, Debug)]
132pub struct BlockfrostProvider {
133    pub blockfrost_client: Blockfrost,
134}
135
136impl BlockfrostProvider {
137    pub fn new(api_key: &str, network: &str) -> BlockfrostProvider {
138        let blockfrost_client = Blockfrost::new(api_key.to_string(), network.to_string());
139        BlockfrostProvider { blockfrost_client }
140    }
141}