From 85bb36682821e7cf96d716f81b838a479c2fae99 Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Tue, 18 Oct 2022 15:07:33 +0200 Subject: [PATCH] Wrote code to print out all conversions. --- apps/src/bin/anoma-client/cli.rs | 3 ++ apps/src/lib/cli.rs | 63 ++++++++++++++++++++++++++++- apps/src/lib/client/rpc.rs | 69 +++++++++++++++++++++++++++++++- 3 files changed, 133 insertions(+), 2 deletions(-) diff --git a/apps/src/bin/anoma-client/cli.rs b/apps/src/bin/anoma-client/cli.rs index c817888f50..87e17b10fa 100644 --- a/apps/src/bin/anoma-client/cli.rs +++ b/apps/src/bin/anoma-client/cli.rs @@ -52,6 +52,9 @@ pub async fn main() -> Result<()> { Sub::QueryEpoch(QueryEpoch(args)) => { rpc::query_epoch(args).await; } + Sub::QueryConversions(QueryConversions(args)) => { + rpc::query_conversions(ctx, args).await; + } Sub::QueryTransfers(QueryTransfers(args)) => { rpc::query_transfers(ctx, args).await; } diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 942e894b50..d6ce946da9 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -186,6 +186,7 @@ pub mod cmds { .subcommand(Withdraw::def().display_order(2)) // Queries .subcommand(QueryEpoch::def().display_order(3)) + .subcommand(QueryConversions::def().display_order(3)) .subcommand(QueryTransfers::def().display_order(3)) .subcommand(QueryBalance::def().display_order(3)) .subcommand(QueryBonds::def().display_order(3)) @@ -221,6 +222,7 @@ pub mod cmds { let unbond = Self::parse_with_ctx(matches, Unbond); let withdraw = Self::parse_with_ctx(matches, Withdraw); let query_epoch = Self::parse_with_ctx(matches, QueryEpoch); + let query_conversions = Self::parse_with_ctx(matches, QueryConversions); let query_transfers = Self::parse_with_ctx(matches, QueryTransfers); let query_balance = Self::parse_with_ctx(matches, QueryBalance); let query_bonds = Self::parse_with_ctx(matches, QueryBonds); @@ -250,6 +252,7 @@ pub mod cmds { .or(unbond) .or(withdraw) .or(query_epoch) + .or(query_conversions) .or(query_transfers) .or(query_balance) .or(query_bonds) @@ -312,6 +315,7 @@ pub mod cmds { Unbond(Unbond), Withdraw(Withdraw), QueryEpoch(QueryEpoch), + QueryConversions(QueryConversions), QueryTransfers(QueryTransfers), QueryBalance(QueryBalance), QueryBonds(QueryBonds), @@ -1208,6 +1212,25 @@ pub mod cmds { } } + #[derive(Clone, Debug)] + pub struct QueryConversions(pub args::QueryConversions); + + impl SubCmd for QueryConversions { + const CMD: &'static str = "conversions"; + + fn parse(matches: &ArgMatches) -> Option { + matches.subcommand_matches(Self::CMD).map(|matches| { + QueryConversions(args::QueryConversions::parse(matches)) + }) + } + + fn def() -> App { + App::new(Self::CMD) + .about("Query currently applicable conversions.") + .add_args::() + } + } + #[derive(Clone, Debug)] pub struct QueryTransfers(pub args::QueryTransfers); @@ -1636,7 +1659,7 @@ pub mod args { const FEE_AMOUNT: ArgDefault = arg_default("fee-amount", DefaultFn(|| token::Amount::from(0))); const FEE_TOKEN: ArgDefaultFromCtx = - arg_default_from_ctx("fee-token", DefaultFn(|| "XAN".into())); + arg_default_from_ctx("fee-token", DefaultFn(|| "NAM".into())); const FORCE: ArgFlag = flag("force"); const DONT_PREFETCH_WASM: ArgFlag = flag("dont-prefetch-wasm"); const GAS_LIMIT: ArgDefault = @@ -2422,6 +2445,44 @@ pub mod args { } } + /// Query asset conversions + #[derive(Clone, Debug)] + pub struct QueryConversions { + /// Common query args + pub query: Query, + /// Address of a token + pub token: Option, + /// Epoch of the asset + pub epoch: Option, + } + + impl Args for QueryConversions { + fn parse(matches: &ArgMatches) -> Self { + let query = Query::parse(matches); + let token = TOKEN_OPT.parse(matches); + let epoch = EPOCH.parse(matches); + Self { + query, + epoch, + token, + } + } + + fn def(app: App) -> App { + app.add_args::() + .arg( + EPOCH + .def() + .about("The epoch for which to query conversions."), + ) + .arg( + TOKEN_OPT + .def() + .about("The token address for which to query conversions."), + ) + } + } + /// Query token balance(s) #[derive(Clone, Debug)] pub struct QueryBalance { diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index fcd60f0f26..515b322e14 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -30,6 +30,7 @@ use namada::ledger::pos::{ self, is_validator_slashes_key, BondId, Bonds, PosParams, Slash, Unbonds, }; use namada::ledger::treasury::storage as treasury_storage; +use namada::ledger::storage::ConversionState; use namada::proto::{SignedTxData, Tx}; use namada::types::address::{masp, tokens, Address}; use namada::types::governance::{ @@ -39,7 +40,7 @@ use namada::types::governance::{ use namada::types::key::*; use namada::types::masp::{BalanceOwner, ExtendedViewingKey, PaymentAddress}; use namada::types::storage::{ - BlockHeight, BlockResults, Epoch, PrefixValue, TxIndex, + BlockHeight, BlockResults, Epoch, PrefixValue, TxIndex, KeySeg, Key, }; use namada::types::token::{balance_key, Transfer}; use namada::types::transaction::{ @@ -2019,6 +2020,72 @@ fn process_unbonds_query( (total, withdrawable) } +/// Query for all conversions. +pub async fn query_conversions(ctx: Context, args: args::QueryConversions) { + // The chosen token type of the conversions + let target_token = args + .token + .as_ref() + .map(|x| ctx.get(x)); + // To facilitate human readable token addresses + let tokens = address::tokens(); + let client = HttpClient::new(args.query.ledger_address).unwrap(); + let masp_addr = masp(); + let key_prefix: Key = masp_addr.to_db_key().into(); + let state_key = key_prefix + .push(&(token::CONVERSION_KEY_PREFIX.to_owned())) + .unwrap(); + let conv_state = query_storage_value::(&client, &state_key) + .await.expect("Conversions should be defined"); + // Track whether any non-sentinel conversions are found + let mut conversions_found = false; + for (addr, epoch, conv, _) in conv_state.assets.values() { + let amt: masp_primitives::transaction::components::Amount = conv.clone().into(); + // If the user has specified any targets, then meet them + if matches!(&target_token, Some(target) if target != addr) { continue } + else if matches!(&args.epoch, Some(target) if target != epoch) { continue } + // If we have a sentinel conversion, then skip printing + else if amt == masp_primitives::transaction::components::Amount::zero() { continue } + conversions_found = true; + // Print the asset to which the conversion applies + let addr_enc = addr.encode(); + print!( + "{}[{}]: ", + tokens + .get(&addr) + .cloned() + .unwrap_or(addr_enc.as_str()), + epoch, + ); + // Now print out the components of the allowed conversion + let mut prefix = ""; + for (asset_type, val) in amt.components() { + // Look up the address and epoch of asset to facilitate pretty + // printing + let (addr, epoch, _, _) = &conv_state.assets[asset_type]; + // Now print out this component of the conversion + let addr_enc = addr.encode(); + print!( + "{}{} {}[{}]", + prefix, + val, + tokens + .get(&addr) + .cloned() + .unwrap_or(addr_enc.as_str()), + epoch + ); + // Future iterations need to be prefixed with + + prefix = " + "; + } + // Allowed conversions are always implicit equations + println!(" = 0"); + } + if !conversions_found { + println!("No conversions found satisfying specified criteria."); + } +} + /// Query a conversion. pub async fn query_conversion( client: HttpClient,