mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-08 00:03:09 +00:00
fix: account subcommand updated
This commit is contained in:
parent
0384efc38f
commit
66ee0c5449
@ -1,21 +1,81 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use base58::ToBase58;
|
||||
use clap::Subcommand;
|
||||
use common::transaction::NSSATransaction;
|
||||
use nssa::Address;
|
||||
use nssa::{Address, program::Program};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
SubcommandReturnValue, WalletCore, cli::WalletSubcommand, helperfunctions::HumanReadableAccount,
|
||||
SubcommandReturnValue, WalletCore,
|
||||
cli::WalletSubcommand,
|
||||
helperfunctions::{AddressPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix},
|
||||
};
|
||||
|
||||
const TOKEN_DEFINITION_TYPE: u8 = 0;
|
||||
const TOKEN_DEFINITION_DATA_SIZE: usize = 23;
|
||||
|
||||
const TOKEN_HOLDING_TYPE: u8 = 1;
|
||||
const TOKEN_HOLDING_DATA_SIZE: usize = 49;
|
||||
|
||||
struct TokenDefinition {
|
||||
#[allow(unused)]
|
||||
account_type: u8,
|
||||
name: [u8; 6],
|
||||
total_supply: u128,
|
||||
}
|
||||
|
||||
struct TokenHolding {
|
||||
#[allow(unused)]
|
||||
account_type: u8,
|
||||
definition_id: Address,
|
||||
balance: u128,
|
||||
}
|
||||
|
||||
impl TokenDefinition {
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
if data.len() != TOKEN_DEFINITION_DATA_SIZE || data[0] != TOKEN_DEFINITION_TYPE {
|
||||
None
|
||||
} else {
|
||||
let account_type = data[0];
|
||||
let name = data[1..7].try_into().unwrap();
|
||||
let total_supply = u128::from_le_bytes(data[7..].try_into().unwrap());
|
||||
|
||||
Some(Self {
|
||||
account_type,
|
||||
name,
|
||||
total_supply,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenHolding {
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE {
|
||||
None
|
||||
} else {
|
||||
let account_type = data[0];
|
||||
let definition_id = Address::new(data[1..33].try_into().unwrap());
|
||||
let balance = u128::from_le_bytes(data[33..].try_into().unwrap());
|
||||
Some(Self {
|
||||
definition_id,
|
||||
balance,
|
||||
account_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Represents generic chain CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum AccountSubcommand {
|
||||
///Get
|
||||
#[command(subcommand)]
|
||||
Get(GetSubcommand),
|
||||
Get {
|
||||
#[arg(long)]
|
||||
raw: bool,
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
///Fetch
|
||||
#[command(subcommand)]
|
||||
Fetch(FetchSubcommand),
|
||||
@ -24,31 +84,6 @@ pub enum AccountSubcommand {
|
||||
New(NewSubcommand),
|
||||
}
|
||||
|
||||
///Represents generic getter CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum GetSubcommand {
|
||||
///Get account `addr` balance
|
||||
PublicAccountBalance {
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
///Get account `addr` nonce
|
||||
PublicAccountNonce {
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
///Get account at address `addr`
|
||||
PublicAccount {
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
///Get private account with `addr` from storage
|
||||
PrivateAccount {
|
||||
#[arg(short, long)]
|
||||
addr: String,
|
||||
},
|
||||
}
|
||||
|
||||
///Represents generic getter CLI subcommand
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum FetchSubcommand {
|
||||
@ -80,49 +115,6 @@ pub enum NewSubcommand {
|
||||
Private {},
|
||||
}
|
||||
|
||||
impl WalletSubcommand for GetSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
GetSubcommand::PublicAccountBalance { addr } => {
|
||||
let addr = Address::from_str(&addr)?;
|
||||
|
||||
let balance = wallet_core.get_account_balance(addr).await?;
|
||||
println!("Accounts {addr} balance is {balance}");
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
GetSubcommand::PublicAccountNonce { addr } => {
|
||||
let addr = Address::from_str(&addr)?;
|
||||
|
||||
let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0];
|
||||
println!("Accounts {addr} nonce is {nonce}");
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
GetSubcommand::PublicAccount { addr } => {
|
||||
let addr: Address = addr.parse()?;
|
||||
let account = wallet_core.get_account_public(addr).await?;
|
||||
let account_hr: HumanReadableAccount = account.clone().into();
|
||||
println!("{}", serde_json::to_string(&account_hr).unwrap());
|
||||
|
||||
Ok(SubcommandReturnValue::Account(account))
|
||||
}
|
||||
GetSubcommand::PrivateAccount { addr } => {
|
||||
let addr: Address = addr.parse()?;
|
||||
if let Some(account) = wallet_core.get_account_private(&addr) {
|
||||
println!("{}", serde_json::to_string(&account).unwrap());
|
||||
} else {
|
||||
println!("Private account not found.");
|
||||
}
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletSubcommand for FetchSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
@ -237,14 +229,107 @@ impl WalletSubcommand for NewSubcommand {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct AuthenticatedTransferAccountView {
|
||||
pub balance: u128,
|
||||
}
|
||||
|
||||
impl From<nssa::Account> for AuthenticatedTransferAccountView {
|
||||
fn from(value: nssa::Account) -> Self {
|
||||
Self {
|
||||
balance: value.balance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TokedDefinitionAccountView {
|
||||
pub account_type: String,
|
||||
pub name: String,
|
||||
pub total_supply: u128,
|
||||
}
|
||||
|
||||
impl From<TokenDefinition> for TokedDefinitionAccountView {
|
||||
fn from(value: TokenDefinition) -> Self {
|
||||
Self {
|
||||
account_type: "Token definition".to_string(),
|
||||
name: hex::encode(value.name),
|
||||
total_supply: value.total_supply,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TokedHoldingAccountView {
|
||||
pub account_type: String,
|
||||
pub definition_id: String,
|
||||
pub balance: u128,
|
||||
}
|
||||
|
||||
impl From<TokenHolding> for TokedHoldingAccountView {
|
||||
fn from(value: TokenHolding) -> Self {
|
||||
Self {
|
||||
account_type: "Token holding".to_string(),
|
||||
definition_id: value.definition_id.to_string(),
|
||||
balance: value.balance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletSubcommand for AccountSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
AccountSubcommand::Get(get_subcommand) => {
|
||||
get_subcommand.handle_subcommand(wallet_core).await
|
||||
AccountSubcommand::Get { raw, addr } => {
|
||||
let (addr, addr_kind) = parse_addr_with_privacy_prefix(&addr)?;
|
||||
|
||||
let account = match addr_kind {
|
||||
AddressPrivacyKind::Public => wallet_core.get_account_public(addr).await?,
|
||||
AddressPrivacyKind::Private => wallet_core
|
||||
.get_account_private(&addr)
|
||||
.ok_or(anyhow::anyhow!("Private account not found in storage"))?,
|
||||
};
|
||||
|
||||
if raw {
|
||||
let account_hr: HumanReadableAccount = account.clone().into();
|
||||
println!("{}", serde_json::to_string(&account_hr).unwrap());
|
||||
|
||||
return Ok(SubcommandReturnValue::Empty);
|
||||
}
|
||||
|
||||
let auth_tr_prog_id = Program::authenticated_transfer_program().id();
|
||||
let token_prog_id = Program::token().id();
|
||||
|
||||
let acc_view = match &account.program_owner {
|
||||
_ if &account.program_owner == &auth_tr_prog_id => {
|
||||
let acc_view: AuthenticatedTransferAccountView = account.into();
|
||||
|
||||
serde_json::to_string(&acc_view)?
|
||||
}
|
||||
_ if &account.program_owner == &token_prog_id => {
|
||||
if let Some(token_def) = TokenDefinition::parse(&account.data) {
|
||||
let acc_view: TokedDefinitionAccountView = token_def.into();
|
||||
|
||||
serde_json::to_string(&acc_view)?
|
||||
} else if let Some(token_hold) = TokenHolding::parse(&account.data) {
|
||||
let acc_view: TokedHoldingAccountView = token_hold.into();
|
||||
|
||||
serde_json::to_string(&acc_view)?
|
||||
} else {
|
||||
anyhow::bail!("Invalid data for account {addr:#?} with token program");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let account_hr: HumanReadableAccount = account.clone().into();
|
||||
serde_json::to_string(&account_hr).unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
println!("{}", acc_view);
|
||||
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
AccountSubcommand::Fetch(fetch_subcommand) => {
|
||||
fetch_subcommand.handle_subcommand(wallet_core).await
|
||||
|
||||
@ -6,7 +6,7 @@ use tokio::io::AsyncReadExt;
|
||||
|
||||
use anyhow::Result;
|
||||
use key_protocol::key_protocol_core::NSSAUserData;
|
||||
use nssa::Account;
|
||||
use nssa::{Account, Address};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
@ -86,6 +86,30 @@ pub(crate) fn produce_random_nonces(size: usize) -> Vec<Nonce> {
|
||||
result.into_iter().map(Nonce::from_le_bytes).collect()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AddressPrivacyKind {
|
||||
Public,
|
||||
Private,
|
||||
}
|
||||
|
||||
pub(crate) fn parse_addr_with_privacy_prefix(
|
||||
addr_base58: &str,
|
||||
) -> Result<(Address, AddressPrivacyKind)> {
|
||||
if addr_base58.starts_with("Public/") {
|
||||
Ok((
|
||||
addr_base58.strip_prefix("Public/").unwrap().parse()?,
|
||||
AddressPrivacyKind::Public,
|
||||
))
|
||||
} else if addr_base58.starts_with("Private/") {
|
||||
Ok((
|
||||
addr_base58.strip_prefix("Private/").unwrap().parse()?,
|
||||
AddressPrivacyKind::Private,
|
||||
))
|
||||
} else {
|
||||
anyhow::bail!("Unsupported privacy kind, available variants is Public/ and Private/");
|
||||
}
|
||||
}
|
||||
|
||||
/// Human-readable representation of an account.
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct HumanReadableAccount {
|
||||
@ -126,4 +150,20 @@ mod tests {
|
||||
std::env::remove_var(HOME_DIR_ENV_VAR);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_addr_parse_with_privacy() {
|
||||
let addr_base58 = "Public/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
|
||||
let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap();
|
||||
|
||||
assert_eq!(addr_kind, AddressPrivacyKind::Public);
|
||||
|
||||
let addr_base58 = "Private/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
|
||||
let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap();
|
||||
|
||||
assert_eq!(addr_kind, AddressPrivacyKind::Private);
|
||||
|
||||
let addr_base58 = "asdsada/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
|
||||
assert!(parse_addr_with_privacy_prefix(addr_base58).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user