Skip to content

Commit

Permalink
Show decimal rune balances (ordinals#3505)
Browse files Browse the repository at this point in the history
  • Loading branch information
raphjaph committed Apr 11, 2024
1 parent abd9654 commit b2ae17d
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use super::*;

#[derive(Debug, PartialEq, Copy, Clone, Default, DeserializeFromStr, SerializeDisplay)]
pub struct Decimal {
value: u128,
scale: u8,
pub value: u128,
pub scale: u8,
}

impl Decimal {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub mod api;
pub mod arguments;
mod blocktime;
pub mod chain;
mod decimal;
pub mod decimal;
mod deserialize_from_str;
mod fee_rate;
pub mod index;
Expand Down
13 changes: 11 additions & 2 deletions src/subcommand/wallet/balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub struct Output {
pub cardinal: u64,
pub ordinal: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub runes: Option<BTreeMap<SpacedRune, u128>>,
pub runes: Option<BTreeMap<SpacedRune, Decimal>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub runic: Option<u64>,
pub total: u64,
Expand Down Expand Up @@ -37,7 +37,16 @@ pub(crate) fn run(wallet: Wallet) -> SubcommandResult {

if is_runic {
for (spaced_rune, pile) in rune_balances {
*runes.entry(spaced_rune).or_default() += pile.amount;
runes
.entry(spaced_rune)
.and_modify(|decimal: &mut Decimal| {
assert_eq!(decimal.scale, pile.divisibility);
decimal.value += pile.amount;
})
.or_insert(Decimal {
value: pile.amount,
scale: pile.divisibility,
});
}
runic += txout.value;
}
Expand Down
6 changes: 3 additions & 3 deletions src/subcommand/wallet/batch_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl Batch {
terms
.cap
.checked_mul(terms.amount.to_integer(etching.divisibility)?)
.ok_or_else(|| anyhow!("`terms.count` * `terms.amount` over maximum"))
.ok_or_else(|| anyhow!("`terms.cap` * `terms.amount` over maximum"))
})
.transpose()?
.unwrap_or_default();
Expand All @@ -110,8 +110,8 @@ impl Batch {
supply
== premine
.checked_add(mintable)
.ok_or_else(|| anyhow!("`premine` + `terms.count` * `terms.amount` over maximum"))?,
"`supply` not equal to `premine` + `terms.count` * `terms.amount`"
.ok_or_else(|| anyhow!("`premine` + `terms.cap` * `terms.amount` over maximum"))?,
"`supply` not equal to `premine` + `terms.cap` * `terms.amount`"
);

ensure!(supply > 0, "`supply` must be greater than zero");
Expand Down
88 changes: 84 additions & 4 deletions tests/wallet/balance.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::*;
use {super::*, ord::decimal::Decimal};

#[test]
fn wallet_balance() {
Expand Down Expand Up @@ -127,14 +127,21 @@ fn runic_utxos_are_deducted_from_cardinal() {
ordinal: 10000,
runic: Some(10_000),
runes: Some(
vec![(SpacedRune { rune, spacers: 1 }, 1000)]
.into_iter()
.collect()
vec![(
SpacedRune { rune, spacers: 1 },
Decimal {
value: 1000,
scale: 0,
}
)]
.into_iter()
.collect()
),
total: 50 * COIN_VALUE * 8,
}
);
}

#[test]
fn unsynced_wallet_fails_with_unindexed_output() {
let core = mockcore::spawn();
Expand Down Expand Up @@ -176,3 +183,76 @@ fn unsynced_wallet_fails_with_unindexed_output() {
.stderr_regex(r"error: output in wallet but not in ord server: [[:xdigit:]]{64}:\d+.*")
.run_and_extract_stdout();
}

#[test]
fn runic_utxos_are_displayed_with_decimal_amount() {
let core = mockcore::builder().network(Network::Regtest).build();

let ord = TestServer::spawn_with_server_args(&core, &["--regtest", "--index-runes"], &[]);

create_wallet(&core, &ord);

pretty_assert_eq!(
CommandBuilder::new("--regtest --index-runes wallet balance")
.core(&core)
.ord(&ord)
.run_and_deserialize_output::<Balance>(),
Balance {
cardinal: 0,
ordinal: 0,
runic: Some(0),
runes: Some(BTreeMap::new()),
total: 0,
}
);

let rune = Rune(RUNE);

batch(
&core,
&ord,
batch::File {
etching: Some(batch::Etching {
divisibility: 3,
premine: "1.111".parse().unwrap(),
rune: SpacedRune { rune, spacers: 1 },
supply: "2.222".parse().unwrap(),
symbol: '¢',
terms: Some(batch::Terms {
amount: "1.111".parse().unwrap(),
cap: 1,
..default()
}),
}),
inscriptions: vec![batch::Entry {
file: "inscription.jpeg".into(),
..default()
}],
..default()
},
);

pretty_assert_eq!(
CommandBuilder::new("--regtest --index-runes wallet balance")
.core(&core)
.ord(&ord)
.run_and_deserialize_output::<Balance>(),
Balance {
cardinal: 50 * COIN_VALUE * 8 - 20_000,
ordinal: 10000,
runic: Some(10_000),
runes: Some(
vec![(
SpacedRune { rune, spacers: 1 },
Decimal {
value: 1111,
scale: 3,
}
)]
.into_iter()
.collect()
),
total: 50 * COIN_VALUE * 8,
}
);
}
22 changes: 17 additions & 5 deletions tests/wallet/batch_command.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use {super::*, ord::subcommand::wallet::send, pretty_assertions::assert_eq};
use {
super::*, ord::decimal::Decimal, ord::subcommand::wallet::send, pretty_assertions::assert_eq,
};

fn receive(core: &mockcore::Handle, ord: &TestServer) -> Address {
let address = CommandBuilder::new("wallet receive")
Expand Down Expand Up @@ -1505,7 +1507,17 @@ fn batch_can_etch_rune() {
cardinal: 44999980000,
ordinal: 10000,
runic: Some(10000),
runes: Some(vec![(rune, 1000)].into_iter().collect()),
runes: Some(
vec![(
rune,
Decimal {
value: 1000,
scale: 0,
}
)]
.into_iter()
.collect()
),
total: 450 * COIN_VALUE,
}
);
Expand Down Expand Up @@ -1990,7 +2002,7 @@ fn etch_mintable_overflow_error() {
)
.core(&core)
.ord(&ord)
.expected_stderr("error: `terms.count` * `terms.amount` over maximum\n")
.expected_stderr("error: `terms.cap` * `terms.amount` over maximum\n")
.expected_exit_code(1)
.run_and_extract_stdout();
}
Expand Down Expand Up @@ -2039,7 +2051,7 @@ fn etch_mintable_plus_premine_overflow_error() {
)
.core(&core)
.ord(&ord)
.expected_stderr("error: `premine` + `terms.count` * `terms.amount` over maximum\n")
.expected_stderr("error: `premine` + `terms.cap` * `terms.amount` over maximum\n")
.expected_exit_code(1)
.run_and_extract_stdout();
}
Expand Down Expand Up @@ -2088,7 +2100,7 @@ fn incorrect_supply_error() {
)
.core(&core)
.ord(&ord)
.expected_stderr("error: `supply` not equal to `premine` + `terms.count` * `terms.amount`\n")
.expected_stderr("error: `supply` not equal to `premine` + `terms.cap` * `terms.amount`\n")
.expected_exit_code(1)
.run_and_extract_stdout();
}
Expand Down
12 changes: 9 additions & 3 deletions tests/wallet/mint.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use {super::*, ord::subcommand::wallet::mint};
use {super::*, ord::decimal::Decimal, ord::subcommand::wallet::mint};

#[test]
fn minting_rune_and_fails_if_after_end() {
Expand Down Expand Up @@ -209,7 +209,10 @@ fn minting_rune_and_then_sending_works() {

assert_eq!(
*balance.runes.unwrap().first_key_value().unwrap().1,
111_u128
Decimal {
value: 111,
scale: 0,
}
);

let output = CommandBuilder::new(format!(
Expand All @@ -229,7 +232,10 @@ fn minting_rune_and_then_sending_works() {

assert_eq!(
*balance.runes.unwrap().first_key_value().unwrap().1,
132_u128
Decimal {
value: 132,
scale: 0,
}
);

pretty_assert_eq!(
Expand Down

0 comments on commit b2ae17d

Please sign in to comment.