Skip to content

Commit

Permalink
wallet: Use decimal balance type
Browse files Browse the repository at this point in the history
  • Loading branch information
iljakuklic committed Jan 6, 2024
1 parent 1d000bd commit a7ce962
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 50 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions wallet/wallet-cli-lib/src/commands/helper_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,6 @@ pub fn print_coin_amount(chain_config: &ChainConfig, value: Amount) -> String {
value.into_fixedpoint_str(chain_config.coin_decimals())
}

pub fn print_token_amount(token_number_of_decimals: u8, value: Amount) -> String {
value.into_fixedpoint_str(token_number_of_decimals)
}

#[cfg(test)]
mod tests {
use rstest::rstest;
Expand Down
54 changes: 18 additions & 36 deletions wallet/wallet-cli-lib/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

mod helper_types;

use std::{path::PathBuf, str::FromStr, sync::Arc};
use std::{fmt::Write, path::PathBuf, str::FromStr, sync::Arc};

use chainstate::TokenIssuanceError;
use clap::Parser;
Expand All @@ -25,16 +25,14 @@ use common::{
tokens::{Metadata, TokenCreator},
Block, ChainConfig, SignedTransaction, Transaction, UtxoOutPoint,
},
primitives::{Amount, BlockHeight, Id, H256},
primitives::{BlockHeight, Id, H256},
};
use crypto::key::{hdkd::u31::U31, PublicKey};
use mempool::tx_accumulator::PackingStrategy;
use p2p_types::{bannable_address::BannableAddress, ip_or_socket_address::IpOrSocketAddress};
use serialization::{hex::HexEncode, hex_encoded::HexEncoded};
use utils::ensure;
use wallet::{
account::Currency, version::get_version, wallet_events::WalletEventsNoOp, WalletError,
};
use wallet::{version::get_version, wallet_events::WalletEventsNoOp, WalletError};
use wallet_controller::{
read::ReadOnlyController, synced_controller::SyncedController, ControllerConfig,
ControllerError, NodeInterface, NodeRpcClient, PeerId, DEFAULT_ACCOUNT_INDEX,
Expand All @@ -48,9 +46,8 @@ use crate::{

use self::helper_types::{
format_delegation_info, format_pool_info, parse_coin_amount, parse_pool_id, parse_token_amount,
parse_token_id, parse_utxo_outpoint, print_coin_amount, print_token_amount, to_per_thousand,
CliIsFreezable, CliIsUnfreezable, CliStoreSeedPhrase, CliUtxoState, CliUtxoTypes,
CliWithLocked,
parse_token_id, parse_utxo_outpoint, print_coin_amount, to_per_thousand, CliIsFreezable,
CliIsUnfreezable, CliStoreSeedPhrase, CliUtxoState, CliUtxoTypes, CliWithLocked,
};

#[derive(Debug, Parser)]
Expand Down Expand Up @@ -1025,38 +1022,23 @@ impl CommandHandler {
utxo_states,
with_locked,
} => {
let mut balances = self
let (coins, tokens) = self
.get_readonly_controller()?
.get_balance(
.get_decimal_balance(
CliUtxoState::to_wallet_states(utxo_states),
with_locked.to_wallet_type(),
)
.map_err(WalletCliError::Controller)?;
let coin_balance = balances.remove(&Currency::Coin).unwrap_or(Amount::ZERO);
let mut output = String::new();
for (currency, amount) in
std::iter::once((Currency::Coin, coin_balance)).chain(balances.into_iter())
{
let out = match currency {
Currency::Token(token_id) => {
let token_number_of_decimals = self
.controller()?
.get_token_number_of_decimals(token_id)
.await
.map_err(WalletCliError::Controller)?;
format!(
"Token: {} amount: {}",
Address::new(chain_config, &token_id)
.expect("Encoding token id should never fail"),
print_token_amount(token_number_of_decimals, amount)
)
}
Currency::Coin => {
format!("Coins amount: {}", print_coin_amount(chain_config, amount))
}
};
output.push_str(&out);
output.push('\n');
.await
.map_err(WalletCliError::Controller)?
.into_coins_and_tokens();

let mut output = format!("Coins amount: {coins}\n");

for (token_id, amount) in tokens {
let token_id = Address::new(chain_config, &token_id)
.expect("Encoding token id should never fail");
write!(&mut output, "Token: {token_id} amount: {amount}\n")
.expect("Writing to a memory buffer should not fail");
}
output.pop();

Expand Down
3 changes: 2 additions & 1 deletion wallet/wallet-controller/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ wallet-types = { path = "../types" }

async-trait.workspace = true
bip39 = { workspace = true, default-features = false, features = ["std", "zeroize"] }
futures = { workspace = true, default-features = false }
serde.workspace = true
thiserror.workspace = true
tokio = { workspace = true, default-features = false, features = ["io-util", "macros", "net", "rt", "sync"] }
futures = { workspace = true, default-features = false }
zeroize.workspace = true

[dev-dependencies]
Expand Down
22 changes: 15 additions & 7 deletions wallet/wallet-controller/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod mnemonic;
pub mod read;
mod sync;
pub mod synced_controller;
pub mod types;

const NORMAL_DELAY: Duration = Duration::from_secs(1);
const ERROR_DELAY: Duration = Duration::from_secs(10);
Expand Down Expand Up @@ -359,13 +360,7 @@ impl<T: NodeInterface + Clone + Send + Sync + 'static, W: WalletEvents> Controll
&self,
token_id: TokenId,
) -> Result<RPCTokenInfo, ControllerError<T>> {
self.rpc_client
.get_token_info(token_id)
.await
.map_err(ControllerError::NodeCallError)?
.ok_or(ControllerError::WalletError(WalletError::UnknownTokenId(
token_id,
)))
fetch_token_info(&self.rpc_client, token_id).await
}

pub async fn generate_block_by_pool(
Expand Down Expand Up @@ -654,3 +649,16 @@ impl<T: NodeInterface + Clone + Send + Sync + 'static, W: WalletEvents> Controll
}
}
}

pub async fn fetch_token_info<T: NodeInterface>(
rpc_client: &T,
token_id: TokenId,
) -> Result<RPCTokenInfo, ControllerError<T>> {
rpc_client
.get_token_info(token_id)
.await
.map_err(ControllerError::NodeCallError)?
.ok_or(ControllerError::WalletError(WalletError::UnknownTokenId(
token_id,
)))
}
32 changes: 30 additions & 2 deletions wallet/wallet-controller/src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use common::{
ChainConfig, DelegationId, Destination, GenBlock, PoolId, Transaction, TxOutput,
UtxoOutPoint,
},
primitives::{id::WithId, Amount, Id},
primitives::{id::WithId, Amount, DecimalAmount, Id},
};
use crypto::key::hdkd::{child_number::ChildNumber, u31::U31};
use futures::{stream::FuturesUnordered, TryStreamExt};
Expand All @@ -40,7 +40,7 @@ use wallet_types::{
BlockInfo, KeychainUsageState,
};

use crate::ControllerError;
use crate::{types::Balances, ControllerError};

pub struct ReadOnlyController<'a, T> {
wallet: &'a DefaultWallet,
Expand Down Expand Up @@ -83,6 +83,34 @@ impl<'a, T: NodeInterface> ReadOnlyController<'a, T> {
.map_err(ControllerError::WalletError)
}

pub async fn get_decimal_balance(
&self,
utxo_states: UtxoStates,
with_locked: WithLocked,
) -> Result<Balances, ControllerError<T>> {
let mut balances = self.get_balance(utxo_states, with_locked)?;

let coins = balances.remove(&Currency::Coin).unwrap_or(Amount::ZERO);
let coins = DecimalAmount::from_amount_minimal(coins, self.chain_config.coin_decimals());

let mut tokens = BTreeMap::new();
for (currency, amount) in balances {
let token_id = match currency {
Currency::Coin => panic!("Removed just above"),
Currency::Token(token_id) => token_id,
};

let info = super::fetch_token_info(&self.rpc_client, token_id).await?;
let decimals = info.token_number_of_decimals();
tokens.insert(
token_id,
DecimalAmount::from_amount_minimal(amount, decimals),
);
}

Ok(Balances::new(coins, tokens))
}

pub fn get_utxos(
&self,
utxo_types: UtxoTypes,
Expand Down
48 changes: 48 additions & 0 deletions wallet/wallet-controller/src/types/balances.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2024 RBB S.r.l
// opensource@mintlayer.org
// SPDX-License-Identifier: MIT
// Licensed under the MIT License;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://github.com/mintlayer/mintlayer-core/blob/master/LICENSE
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::BTreeMap;

use common::{chain::tokens::TokenId, primitives::DecimalAmount};

/// Balances of coins and tokens
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Balances {
coins: DecimalAmount,
tokens: BTreeMap<TokenId, DecimalAmount>,
}

impl Balances {
pub fn new(coins: DecimalAmount, tokens: BTreeMap<TokenId, DecimalAmount>) -> Self {
Self { coins, tokens }
}

pub fn coins(&self) -> DecimalAmount {
self.coins
}

pub fn tokens(&self) -> &BTreeMap<TokenId, DecimalAmount> {
&self.tokens
}

pub fn token(&self, token_id: &TokenId) -> DecimalAmount {
self.tokens.get(token_id).copied().unwrap_or(DecimalAmount::ZERO)
}

pub fn into_coins_and_tokens(self) -> (DecimalAmount, BTreeMap<TokenId, DecimalAmount>) {
let Self { coins, tokens } = self;
(coins, tokens)
}
}
21 changes: 21 additions & 0 deletions wallet/wallet-controller/src/types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2023 RBB S.r.l
// opensource@mintlayer.org
// SPDX-License-Identifier: MIT
// Licensed under the MIT License;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://github.com/mintlayer/mintlayer-core/blob/master/LICENSE
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Support types for presenting data in user-facing settings
mod balances;

pub use balances::Balances;
pub use common::primitives::DecimalAmount;

0 comments on commit a7ce962

Please sign in to comment.