1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::client::{Client, ClientType, CryptoClient};
use crate::types::{Amount, ClientOptions, Currency, Symbol, SyncItem, SyncStats, WalletBalance};
use crate::Result;
use async_trait::async_trait;
use num_bigint::BigInt;
use std::str::FromStr;

#[derive(Clone)]
pub struct SiacoinClient {
    url: String,
}

pub fn get_client(client_type: ClientType, options: ClientOptions) -> crate::Result<Box<Client>> {
    match client_type {
        //@todo need url to come as well.
        ClientType::HTTP => Ok(Box::new(SiacoinClient::new(options))),
        //Hack for here.
        ClientType::RPC => Ok(Box::new(SiacoinClient::new(options))),
        _ => Err(crate::error::ClientError::UnsupportedType(client_type)),
    }
}

impl SiacoinClient {
    pub fn new(options: ClientOptions) -> Self {
        SiacoinClient {
            url: options.url.clone(),
        }
    }
}

#[async_trait]
impl CryptoClient for SiacoinClient {
    async fn sync_stats(&self) -> SyncStats {
        let result: serde_json::Value = match surf::get(&self.url)
            .header("User-Agent", "Sia-Agent")
            .recv_json()
            .await
        {
            Ok(r) => r,
            Err(_e) => {
                //@todo completely revamp this section should probably return a error like I say
                //below, but we want to make sure that the monitor understands to re-try.
                // info!("Node appeared to not be ready yet. Sleeping for 60 seconds");
                async_std::task::sleep(std::time::Duration::from_secs(60)).await;
                //We should return an error here... but oh well
                return SyncStats {
                    current_block: 0,
                    syncing: true,
                    sync_item: SyncItem::VerificationProgress,
                    estimated_sync_item_remaining: 0.0,
                };
            }
        };

        let syncing = result
            .as_object()
            .unwrap()
            .get("synced")
            .unwrap()
            .as_bool()
            .unwrap();
        let height = result
            .as_object()
            .unwrap()
            .get("height")
            .unwrap()
            .as_u64()
            .unwrap();

        SyncStats {
            current_block: height,
            syncing,
            sync_item: SyncItem::VerificationProgress,
            estimated_sync_item_remaining: 0.0,
        }
    }

    async fn wallet_balance(&self, _identifier: &str) -> Result<WalletBalance> {
        let result: serde_json::Value = surf::get(format!("{}/{}", &self.url, "wallet"))
            .header("User-Agent", "Sia-Agent")
            .recv_json()
            .await?;

        let mut siacoin_multipler = BigInt::from(10);
        siacoin_multipler = siacoin_multipler.pow(24);

        let mut confirmed_balance =
            BigInt::from_str(result["confirmedsiacoinbalance"].as_str().unwrap()).unwrap();
        confirmed_balance = confirmed_balance * siacoin_multipler.clone();

        let mut unconfirmed_outgoing =
            BigInt::from_str(result["unconfirmedoutgoingsiacoins"].as_str().unwrap()).unwrap();
        unconfirmed_outgoing = unconfirmed_outgoing * siacoin_multipler.clone();

        let mut unconfirmed_incoming =
            BigInt::from_str(result["unconfirmedincomingsiacoins"].as_str().unwrap()).unwrap();
        unconfirmed_incoming = unconfirmed_incoming * siacoin_multipler;

        let unconfirmed_balance =
            confirmed_balance.clone() - unconfirmed_incoming - unconfirmed_outgoing;

        Ok(WalletBalance {
            //We need bigints here actually.
            confirmed_balance: Amount {
                value: confirmed_balance,
                currency: Currency {
                    symbol: Symbol::SIA,
                    decimals: 24,
                },
            },
            unconfirmed_balance: Amount {
                value: unconfirmed_balance,
                currency: Currency {
                    symbol: Symbol::SIA,
                    decimals: 24,
                },
            },
        })
    }

    fn client_type(&self) -> ClientType {
        ClientType::HTTP
    }
}