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
use eyre::{bail, eyre};
use filament_app::accounts;
use filament_chain::{Account, Address};
use filament_encoding::FromBech32;

use crate::{
    command::Context,
    terminal::{Args, Help},
};

pub const HELP: Help = Help {
    name: "account",
    description: "Inspect an on-chain account",
    version: env!("CARGO_PKG_VERSION"),
    usage: r#"
Usage

    flt query account <address>

Options

    --height <height> Height at which to query
    "#,
};

pub struct Options {
    address: Address,
    height: Option<u64>,
}

impl Args for Options {
    fn from_args(args: Vec<std::ffi::OsString>) -> eyre::Result<Self> {
        use lexopt::prelude::*;

        let mut parser = lexopt::Parser::from_args(args);
        let mut address: Option<Address> = None;
        let mut height: Option<u64> = None;

        while let Some(arg) = parser.next()? {
            match arg {
                Long("height") => {
                    let val = parser.value()?;
                    let val = val
                        .to_str()
                        .ok_or(eyre!("height is not UTF-8"))?
                        .parse::<u64>()?;

                    height = Some(val);
                },
                Value(addr) if address.is_none() => {
                    let addr = addr.to_str().ok_or(eyre!("address is not UTF-8"))?;
                    address = Some(Address::from_bech32(addr)?);
                },
                _ => bail!(arg.unexpected()),
            }
        }

        Ok(Self {
            address: address.ok_or(eyre!("address is missing"))?,
            height,
        })
    }
}

pub fn run(ctx: Context, opts: Options) -> eyre::Result<()> {
    let account = ctx
        .client
        .query::<Account>(opts.height, accounts::Query::AccountByAddress(opts.address))?;

    dbg!(&account);

    Ok(())
}

#[cfg(test)]
mod test {
    use filament_chain::Address;
    use filament_crypto::SigningKey;
    use filament_encoding::ToBech32 as _;
    use pretty_assertions::assert_eq;
    use rand::thread_rng;

    use super::Options;
    use crate::terminal::Args as _;

    #[test]
    fn options() -> eyre::Result<()> {
        let addr = Address::from(SigningKey::new(thread_rng()).verification_key());

        let opts = Options::from_args(vec!["--height=69".into(), addr.to_bech32()?.into()])?;

        assert_eq!(opts.address, addr);
        assert_eq!(opts.height, Some(69));

        Ok(())
    }
}