Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wallet identify subcommand #304

Merged
merged 16 commits into from
Aug 22, 2022
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use {
options::Options,
ordinal::Ordinal,
purse::Purse,
rarity::Rarity,
sat_point::SatPoint,
subcommand::Subcommand,
},
Expand Down Expand Up @@ -85,6 +86,7 @@ mod nft;
mod options;
mod ordinal;
mod purse;
mod rarity;
mod sat_point;
mod subcommand;

Expand Down
45 changes: 2 additions & 43 deletions src/ordinal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,8 @@ impl Ordinal {
format!("{}.{}", self.height(), self.third())
}

pub(crate) fn rarity(self) -> &'static str {
let Degree {
hour,
minute,
second,
third,
} = self.degree();

if hour == 0 && minute == 0 && second == 0 && third == 0 {
"mythic"
} else if minute == 0 && second == 0 && third == 0 {
"legendary"
} else if minute == 0 && third == 0 {
"epic"
} else if second == 0 && third == 0 {
"rare"
} else if third == 0 {
"uncommon"
} else {
"common"
}
pub(crate) fn rarity(self) -> Rarity {
self.into()
}

pub(crate) fn name(self) -> String {
Expand Down Expand Up @@ -498,28 +479,6 @@ mod tests {
assert_eq!(Ordinal(2067187500000000 + 1).cycle(), 1);
}

#[test]
fn rarity() {
assert_eq!(Ordinal(0).rarity(), "mythic");
assert_eq!(Ordinal(1).rarity(), "common");

assert_eq!(Ordinal(50 * 100_000_000 - 1).rarity(), "common");
assert_eq!(Ordinal(50 * 100_000_000).rarity(), "uncommon");
assert_eq!(Ordinal(50 * 100_000_000 + 1).rarity(), "common");

assert_eq!(Ordinal(50 * 100_000_000 * 2016 - 1).rarity(), "common");
assert_eq!(Ordinal(50 * 100_000_000 * 2016).rarity(), "rare");
assert_eq!(Ordinal(50 * 100_000_000 * 2016 + 1).rarity(), "common");

assert_eq!(Ordinal(50 * 100_000_000 * 210000 - 1).rarity(), "common");
assert_eq!(Ordinal(50 * 100_000_000 * 210000).rarity(), "epic");
assert_eq!(Ordinal(50 * 100_000_000 * 210000 + 1).rarity(), "common");

assert_eq!(Ordinal(2067187500000000 - 1).rarity(), "common");
assert_eq!(Ordinal(2067187500000000).rarity(), "legendary");
assert_eq!(Ordinal(2067187500000000 + 1).rarity(), "common");
}

#[test]
fn third() {
assert_eq!(Ordinal(0).third(), 0);
Expand Down
92 changes: 92 additions & 0 deletions src/rarity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use super::*;

#[derive(Debug, PartialEq, PartialOrd)]
pub(crate) enum Rarity {
Common,
Uncommon,
Rare,
Epic,
Legendary,
Mythic,
}

impl Display for Rarity {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Common => "common",
Self::Uncommon => "uncommon",
Self::Rare => "rare",
Self::Epic => "epic",
Self::Legendary => "legendary",
Self::Mythic => "mythic",
}
)
}
}

impl From<Ordinal> for Rarity {
fn from(ordinal: Ordinal) -> Self {
let Degree {
hour,
minute,
second,
third,
} = ordinal.degree();

if hour == 0 && minute == 0 && second == 0 && third == 0 {
Self::Mythic
} else if minute == 0 && second == 0 && third == 0 {
Self::Legendary
} else if minute == 0 && third == 0 {
Self::Epic
} else if second == 0 && third == 0 {
Self::Rare
} else if third == 0 {
Self::Uncommon
} else {
Self::Common
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn rarity() {
assert_eq!(Ordinal(0).rarity(), Rarity::Mythic);
assert_eq!(Ordinal(1).rarity(), Rarity::Common);

assert_eq!(Ordinal(50 * 100_000_000 - 1).rarity(), Rarity::Common);
assert_eq!(Ordinal(50 * 100_000_000).rarity(), Rarity::Uncommon);
assert_eq!(Ordinal(50 * 100_000_000 + 1).rarity(), Rarity::Common);

assert_eq!(
Ordinal(50 * 100_000_000 * 2016 - 1).rarity(),
Rarity::Common
);
assert_eq!(Ordinal(50 * 100_000_000 * 2016).rarity(), Rarity::Rare);
assert_eq!(
Ordinal(50 * 100_000_000 * 2016 + 1).rarity(),
Rarity::Common
);

assert_eq!(
Ordinal(50 * 100_000_000 * 210000 - 1).rarity(),
Rarity::Common
);
assert_eq!(Ordinal(50 * 100_000_000 * 210000).rarity(), Rarity::Epic);
assert_eq!(
Ordinal(50 * 100_000_000 * 210000 + 1).rarity(),
Rarity::Common
);

assert_eq!(Ordinal(2067187500000000 - 1).rarity(), Rarity::Common);
assert_eq!(Ordinal(2067187500000000).rarity(), Rarity::Legendary);
assert_eq!(Ordinal(2067187500000000 + 1).rarity(), Rarity::Common);
}
}
2 changes: 1 addition & 1 deletion src/subcommand/server/templates/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::*;
#[derive(Display)]
pub(crate) struct HomeHtml {
last: u64,
blocks: Vec<(&'static str, BlockHash)>,
blocks: Vec<(Rarity, BlockHash)>,
}

impl HomeHtml {
Expand Down
3 changes: 3 additions & 0 deletions src/subcommand/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use super::*;

mod balance;
mod fund;
mod identify;
mod init;
mod send;
mod utxos;
Expand All @@ -10,6 +11,7 @@ mod utxos;
pub(crate) enum Wallet {
Balance,
Fund,
Identify,
Init,
Send(send::Send),
Utxos,
Expand All @@ -20,6 +22,7 @@ impl Wallet {
match self {
Self::Balance => balance::run(options),
Self::Fund => fund::run(options),
Self::Identify => identify::run(options),
Self::Init => init::run(options),
Self::Send(send) => send.run(options),
Self::Utxos => utxos::run(options),
Expand Down
39 changes: 39 additions & 0 deletions src/subcommand/wallet/identify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use super::*;

pub(crate) fn run(options: Options) -> Result {
let index = Index::index(&options)?;

let mut ordinals = Purse::load(&options)?
.wallet
.list_unspent()?
.into_iter()
.map(|utxo| {
index.list(utxo.outpoint).and_then(|list| match list {
Some(List::Unspent(ranges)) => Ok(
ranges
.into_iter()
.map(|(start, _end)| Ordinal(start))
.filter(|ordinal| ordinal.rarity() > Rarity::Common)
.map(|ordinal| (ordinal, utxo.outpoint))
.collect(),
),
Some(List::Spent(txid)) => Err(anyhow!(
"UTXO {} unspent in wallet but spent in index by transaction {txid}",
utxo.outpoint
)),
None => Ok(Vec::new()),
})
})
.collect::<Result<Vec<Vec<(Ordinal, OutPoint)>>, _>>()?
.into_iter()
.flatten()
.collect::<Vec<(Ordinal, OutPoint)>>();

ordinals.sort_by(|(ordinal_a, _), (ordinal_b, _)| ordinal_a.cmp(ordinal_b));

for (ordinal, outpoint) in ordinals {
println!("{ordinal} {} {outpoint}", ordinal.rarity());
}

Ok(())
}
Loading