soroban_cli/commands/ledger/entry/fetch/
trustline.rs1use std::fmt::Debug;
2
3use super::args::Args;
4use crate::{
5 commands::config::{self, locator},
6 xdr::{
7 AccountId, AlphaNum12, AlphaNum4, AssetCode, LedgerKey, LedgerKeyTrustLine, MuxedAccount,
8 PublicKey, TrustLineAsset, Uint256,
9 },
10};
11use clap::Parser;
12use stellar_strkey::ed25519::PublicKey as Ed25519PublicKey;
13
14#[derive(Parser, Debug, Clone)]
15#[group(skip)]
16pub struct Cmd {
17 #[command(flatten)]
18 pub args: Args,
19
20 #[arg(long)]
22 pub account: String,
23
24 #[arg(long, required = true)]
26 pub asset: Vec<String>,
27
28 #[arg(long)]
30 pub hd_path: Option<usize>,
31}
32
33#[derive(thiserror::Error, Debug)]
34pub enum Error {
35 #[error(transparent)]
36 Config(#[from] config::key::Error),
37 #[error("provided asset is invalid: {0}")]
38 InvalidAsset(String),
39 #[error("provided data name is invalid: {0}")]
40 InvalidDataName(String),
41 #[error("native assets do not have trustlines")]
42 NativeAsset,
43 #[error(transparent)]
44 Locator(#[from] locator::Error),
45 #[error(transparent)]
46 Run(#[from] super::args::Error),
47}
48
49impl Cmd {
50 pub async fn run(&self) -> Result<(), Error> {
51 let mut ledger_keys = vec![];
52 self.insert_asset_keys(&mut ledger_keys)?;
53 Ok(self.args.run(ledger_keys).await?)
54 }
55
56 fn insert_asset_keys(&self, ledger_keys: &mut Vec<LedgerKey>) -> Result<(), Error> {
57 let acc = self.muxed_account(&self.account)?;
58 for asset in &self.asset {
59 let asset = if asset.contains(':') {
60 let mut parts = asset.split(':');
61 let code = parts.next().ok_or(Error::InvalidAsset(asset.clone()))?;
62 let issuer = parts.next().ok_or(Error::InvalidAsset(asset.clone()))?;
63 if parts.next().is_some() {
64 Err(Error::InvalidAsset(asset.clone()))?;
65 }
66 let source_bytes = Ed25519PublicKey::from_string(issuer)
67 .map_err(|_| Error::InvalidAsset(asset.clone()))?
68 .0;
69 let issuer = AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(source_bytes)));
70
71 let asset_code: AssetCode = code
72 .parse()
73 .map_err(|_| Error::InvalidAsset(asset.clone()))?;
74 match asset_code {
75 AssetCode::CreditAlphanum4(asset_code) => {
76 TrustLineAsset::CreditAlphanum4(AlphaNum4 { asset_code, issuer })
77 }
78 AssetCode::CreditAlphanum12(asset_code) => {
79 TrustLineAsset::CreditAlphanum12(AlphaNum12 { asset_code, issuer })
80 }
81 }
82 } else if matches!(asset.as_str(), "XLM" | "xlm" | "native") {
83 Err(Error::NativeAsset)?
84 } else {
85 Err(Error::InvalidAsset(asset.clone()))?
86 };
87
88 let key = LedgerKey::Trustline(LedgerKeyTrustLine {
89 account_id: acc.clone().account_id(),
90 asset,
91 });
92
93 ledger_keys.push(key);
94 }
95 Ok(())
96 }
97
98 fn muxed_account(&self, account: &str) -> Result<MuxedAccount, Error> {
99 Ok(self
100 .args
101 .locator
102 .read_key(account)?
103 .muxed_account(self.hd_path)?)
104 }
105}