Skip to content

Commit

Permalink
Merge pull request #428 from anoma/james/ethbridge/transpose-yuji-mul…
Browse files Browse the repository at this point in the history
…titoken

multitoken transfer and query PR#359 for `eth-bridge-integration`
  • Loading branch information
james-chf authored Sep 5, 2022
2 parents 2561a86 + b0df28b commit df0152c
Show file tree
Hide file tree
Showing 17 changed files with 320 additions and 111 deletions.
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

0 comments on commit df0152c

Please sign in to comment.