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

multitoken transfer and query PR#359 for eth-bridge-integration #428

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1465,6 +1465,7 @@ pub mod args {
const SOURCE: Arg<WalletAddress> = arg("source");
const SOURCE_OPT: ArgOpt<WalletAddress> = SOURCE.opt();
const STORAGE_KEY: Arg<storage::Key> = arg("storage-key");
const SUB_PREFIX: ArgOpt<String> = arg_opt("sub-prefix");
const TARGET: Arg<WalletAddress> = arg("target");
const TO_STDOUT: ArgFlag = flag("stdout");
const TOKEN_OPT: ArgOpt<WalletAddress> = TOKEN.opt();
Expand Down Expand Up @@ -1610,6 +1611,8 @@ pub mod args {
pub target: WalletAddress,
/// Transferred token address
pub token: WalletAddress,
/// Transferred token address
pub sub_prefix: Option<String>,
/// Transferred token amount
pub amount: token::Amount,
}
Expand All @@ -1620,12 +1623,14 @@ pub mod args {
let source = SOURCE.parse(matches);
let target = TARGET.parse(matches);
let token = TOKEN.parse(matches);
let sub_prefix = SUB_PREFIX.parse(matches);
let amount = AMOUNT.parse(matches);
Self {
tx,
source,
target,
token,
sub_prefix,
amount,
}
}
Expand All @@ -1638,6 +1643,7 @@ pub mod args {
))
.arg(TARGET.def().about("The target account address."))
.arg(TOKEN.def().about("The transfer token."))
.arg(SUB_PREFIX.def().about("The token's sub prefix."))
.arg(AMOUNT.def().about("The amount to transfer in decimal."))
}
}
Expand Down Expand Up @@ -2185,17 +2191,21 @@ pub mod args {
pub owner: Option<WalletAddress>,
/// Address of a token
pub token: Option<WalletAddress>,
/// Sub prefix of an account
pub sub_prefix: Option<String>,
}

impl Args for QueryBalance {
fn parse(matches: &ArgMatches) -> Self {
let query = Query::parse(matches);
let owner = OWNER.parse(matches);
let token = TOKEN_OPT.parse(matches);
let sub_prefix = SUB_PREFIX.parse(matches);
Self {
query,
owner,
token,
sub_prefix,
}
}

Expand All @@ -2211,6 +2221,11 @@ pub mod args {
.def()
.about("The token's address whose balance to query."),
)
.arg(
SUB_PREFIX.def().about(
"The token's sub prefix whose balance to query.",
),
)
}
}

Expand Down
151 changes: 90 additions & 61 deletions apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use namada::types::governance::{
OfflineProposal, OfflineVote, ProposalVote, TallyResult,
};
use namada::types::key::*;
use namada::types::storage::{Epoch, PrefixValue};
use namada::types::storage::{Epoch, Key, KeySeg, PrefixValue};
use namada::types::token::{balance_key, Amount};
use namada::types::{address, storage, token};
use tendermint::abci::Code;
Expand Down Expand Up @@ -101,89 +101,125 @@ pub async fn query_balance(ctx: Context, args: args::QueryBalance) {
(Some(token), Some(owner)) => {
let token = ctx.get(&token);
let owner = ctx.get(&owner);
let key = token::balance_key(&token, &owner);
let key = match &args.sub_prefix {
Some(sub_prefix) => {
let sub_prefix = Key::parse(sub_prefix).unwrap();
let prefix =
token::multitoken_balance_prefix(&token, &sub_prefix);
token::multitoken_balance_key(&prefix, &owner)
}
None => token::balance_key(&token, &owner),
};
let currency_code = tokens
.get(&token)
.map(|c| Cow::Borrowed(*c))
.unwrap_or_else(|| Cow::Owned(token.to_string()));
match query_storage_value::<token::Amount>(&client, &key).await {
Some(balance) => {
println!("{}: {}", currency_code, balance);
}
Some(balance) => match &args.sub_prefix {
Some(sub_prefix) => {
println!(
"{} with {}: {}",
currency_code, sub_prefix, balance
);
}
None => println!("{}: {}", currency_code, balance),
},
None => {
println!("No {} balance found for {}", currency_code, owner)
}
}
}
(None, Some(owner)) => {
let owner = ctx.get(&owner);
let mut found_any = false;
for (token, currency_code) in tokens {
let key = token::balance_key(&token, &owner);
if let Some(balance) =
query_storage_value::<token::Amount>(&client, &key).await
{
println!("{}: {}", currency_code, balance);
found_any = true;
for (token, _) in tokens {
let prefix = token.to_db_key().into();
let balances = query_storage_prefix::<token::Amount>(
client.clone(),
prefix,
)
.await;
if let Some(balances) = balances {
print_balances(balances, &token, Some(&owner));
}
}
if !found_any {
println!("No balance found for {}", owner);
}
}
(Some(token), None) => {
let token = ctx.get(&token);
let key = token::balance_prefix(&token);
let prefix = token.to_db_key().into();
let balances =
query_storage_prefix::<token::Amount>(client, key).await;
match balances {
Some(balances) => {
let currency_code = tokens
.get(&token)
.map(|c| Cow::Borrowed(*c))
.unwrap_or_else(|| Cow::Owned(token.to_string()));
let stdout = io::stdout();
let mut w = stdout.lock();
writeln!(w, "Token {}:", currency_code).unwrap();
for (key, balance) in balances {
let owner =
token::is_any_token_balance_key(&key).unwrap();
writeln!(w, " {}, owned by {}", balance, owner)
.unwrap();
}
}
None => {
println!("No balances for token {}", token.encode())
}
query_storage_prefix::<token::Amount>(client, prefix).await;
if let Some(balances) = balances {
print_balances(balances, &token, None);
}
}
(None, None) => {
let stdout = io::stdout();
let mut w = stdout.lock();
for (token, currency_code) in tokens {
for (token, _) in tokens {
let key = token::balance_prefix(&token);
let balances =
query_storage_prefix::<token::Amount>(client.clone(), key)
.await;
match balances {
Some(balances) => {
writeln!(w, "Token {}:", currency_code).unwrap();
for (key, balance) in balances {
let owner =
token::is_any_token_balance_key(&key).unwrap();
writeln!(w, " {}, owned by {}", balance, owner)
.unwrap();
}
}
None => {
println!("No balances for token {}", token.encode())
}
if let Some(balances) = balances {
print_balances(balances, &token, None);
}
}
}
}
}

fn print_balances(
balances: impl Iterator<Item = (storage::Key, token::Amount)>,
token: &Address,
target: Option<&Address>,
) {
let stdout = io::stdout();
let mut w = stdout.lock();

// Token
let tokens = address::tokens();
let currency_code = tokens
.get(token)
.map(|c| Cow::Borrowed(*c))
.unwrap_or_else(|| Cow::Owned(token.to_string()));
writeln!(w, "Token {}", currency_code).unwrap();

let print_num = balances
.filter_map(
|(key, balance)| match token::is_any_multitoken_balance_key(&key) {
Some((sub_prefix, owner)) => Some((
owner.clone(),
format!(
"with {}: {}, owned by {}",
sub_prefix, balance, owner
),
)),
None => token::is_any_token_balance_key(&key).map(|owner| {
(
owner.clone(),
format!(": {}, owned by {}", balance, owner),
)
}),
},
)
.filter_map(|(o, s)| match target {
Some(t) if o == *t => Some(s),
Some(_) => None,
None => Some(s),
})
.map(|s| {
writeln!(w, "{}", s).unwrap();
})
.count();

if print_num == 0 {
match target {
Some(t) => writeln!(w, "No balances owned by {}", t).unwrap(),
None => {
writeln!(w, "No balances for token {}", currency_code).unwrap()
}
}
}
}

/// Query Proposals
pub async fn query_proposal(_ctx: Context, args: args::QueryProposal) {
async fn print_proposal(
Expand Down Expand Up @@ -1332,14 +1368,7 @@ where
Ok(values) => {
let decode = |PrefixValue { key, value }: PrefixValue| {
match T::try_from_slice(&value[..]) {
Err(err) => {
eprintln!(
"Skipping a value for key {}. Error in \
decoding: {}",
key, err
);
None
}
Err(_) => None,
Ok(value) => Some((key, value)),
}
};
Expand Down
15 changes: 13 additions & 2 deletions apps/src/lib/client/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use namada::types::governance::{
};
use namada::types::key::*;
use namada::types::nft::{self, Nft, NftToken};
use namada::types::storage::Epoch;
use namada::types::storage::{Epoch, Key};
use namada::types::token::Amount;
use namada::types::transaction::governance::{
InitProposalData, VoteProposalData,
Expand Down Expand Up @@ -415,7 +415,17 @@ pub async fn submit_transfer(ctx: Context, args: args::TxTransfer) {
}
}
// Check source balance
let balance_key = token::balance_key(&token, &source);
let (sub_prefix, balance_key) = match args.sub_prefix {
Some(sub_prefix) => {
let sub_prefix = Key::parse(sub_prefix).unwrap();
let prefix = token::multitoken_balance_prefix(&token, &sub_prefix);
(
Some(sub_prefix),
token::multitoken_balance_key(&prefix, &source),
)
}
None => (None, token::balance_key(&token, &source)),
};
let client = HttpClient::new(args.tx.ledger_address.clone()).unwrap();
match rpc::query_storage_value::<token::Amount>(&client, &balance_key).await
{
Expand Down Expand Up @@ -447,6 +457,7 @@ pub async fn submit_transfer(ctx: Context, args: args::TxTransfer) {
source,
target,
token,
sub_prefix,
amount: args.amount,
};
tracing::debug!("Transfer data {:?}", transfer);
Expand Down
4 changes: 4 additions & 0 deletions shared/src/types/intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,14 @@ mod tests {
source: bertha_addr.clone(),
target: albert_addr.clone(),
token: Address::from_str(BTC).unwrap(),
sub_prefix: None,
amount: token::Amount::from(100),
},
token::Transfer {
source: albert_addr,
target: bertha_addr,
token: Address::from_str(XAN).unwrap(),
sub_prefix: None,
amount: token::Amount::from(1),
},
]
Expand Down Expand Up @@ -424,12 +426,14 @@ mod tests {
source: bertha_addr.clone(),
target: albert_addr.clone(),
token: Address::from_str(BTC).unwrap(),
sub_prefix: None,
amount: token::Amount::from(100),
},
token::Transfer {
source: albert_addr,
target: bertha_addr,
token: Address::from_str(XAN).unwrap(),
sub_prefix: None,
amount: token::Amount::from(1),
},
]
Expand Down
Loading