diff --git a/cmd/soroban-cli/src/commands/contract/deploy/asset.rs b/cmd/soroban-cli/src/commands/contract/deploy/asset.rs index 04a0380ed..9adf1e1be 100644 --- a/cmd/soroban-cli/src/commands/contract/deploy/asset.rs +++ b/cmd/soroban-cli/src/commands/contract/deploy/asset.rs @@ -39,6 +39,8 @@ pub enum Error { Network(#[from] network::Error), #[error(transparent)] Builder(#[from] builder::Error), + #[error(transparent)] + Asset(#[from] builder::asset::Error), } impl From for Error { @@ -85,7 +87,7 @@ impl NetworkRunnable for Cmd { ) -> Result { let config = config.unwrap_or(&self.config); // Parse asset - let asset = &self.asset; + let asset = self.asset.resolve(&config.locator)?; let network = config.get_network()?; let client = network.rpc_client()?; @@ -100,7 +102,7 @@ impl NetworkRunnable for Cmd { .await?; let sequence: i64 = account_details.seq_num.into(); let network_passphrase = &network.network_passphrase; - let contract_id = contract_id_hash_from_asset(asset, network_passphrase); + let contract_id = contract_id_hash_from_asset(&asset, network_passphrase); let tx = build_wrap_token_tx( asset, &contract_id, diff --git a/cmd/soroban-cli/src/commands/contract/id/asset.rs b/cmd/soroban-cli/src/commands/contract/id/asset.rs index 921592cf8..ddc03a715 100644 --- a/cmd/soroban-cli/src/commands/contract/id/asset.rs +++ b/cmd/soroban-cli/src/commands/contract/id/asset.rs @@ -21,6 +21,8 @@ pub enum Error { ConfigError(#[from] config::Error), #[error(transparent)] Xdr(#[from] crate::xdr::Error), + #[error(transparent)] + Asset(#[from] builder::asset::Error), } impl Cmd { pub fn run(&self) -> Result<(), Error> { @@ -30,7 +32,10 @@ impl Cmd { pub fn contract_address(&self) -> Result { let network = self.config.get_network()?; - let contract_id = contract_id_hash_from_asset(&self.asset, &network.network_passphrase); + let contract_id = contract_id_hash_from_asset( + &self.asset.resolve(&self.config.locator)?, + &network.network_passphrase, + ); Ok(stellar_strkey::Contract(contract_id.0)) } } diff --git a/cmd/soroban-cli/src/commands/snapshot/create.rs b/cmd/soroban-cli/src/commands/snapshot/create.rs index 6ce48d3f2..9c1736914 100644 --- a/cmd/soroban-cli/src/commands/snapshot/create.rs +++ b/cmd/soroban-cli/src/commands/snapshot/create.rs @@ -322,7 +322,9 @@ impl Cmd { get_name_from_stellar_asset_contract_storage(storage) { let asset: builder::Asset = name.parse()?; - if let Some(issuer) = match asset.into() { + if let Some(issuer) = match asset + .resolve(&global_args.locator)? + { Asset::Native => None, Asset::CreditAlphanum4(a4) => Some(a4.issuer), Asset::CreditAlphanum12(a12) => Some(a12.issuer), diff --git a/cmd/soroban-cli/src/commands/tx/args.rs b/cmd/soroban-cli/src/commands/tx/args.rs index c703ead6b..e789bc2e4 100644 --- a/cmd/soroban-cli/src/commands/tx/args.rs +++ b/cmd/soroban-cli/src/commands/tx/args.rs @@ -7,7 +7,7 @@ use crate::{ }, fee, rpc::{self, Client, GetTransactionResponse}, - tx::builder::{self, TxExt}, + tx::builder::{self, asset, TxExt}, xdr::{self, Limits, WriteXdr}, }; @@ -38,6 +38,8 @@ pub enum Error { Xdr(#[from] xdr::Error), #[error(transparent)] Address(#[from] address::Error), + #[error(transparent)] + Asset(#[from] asset::Error), } impl Args { @@ -120,4 +122,8 @@ impl Args { .resolve_muxed_account(&self.config.locator, self.config.hd_path)? .account_id()) } + + pub fn resolve_asset(&self, asset: &builder::Asset) -> Result { + Ok(asset.resolve(&self.config.locator)?) + } } diff --git a/cmd/soroban-cli/src/commands/tx/new/change_trust.rs b/cmd/soroban-cli/src/commands/tx/new/change_trust.rs index da9acc8cf..ebc367474 100644 --- a/cmd/soroban-cli/src/commands/tx/new/change_trust.rs +++ b/cmd/soroban-cli/src/commands/tx/new/change_trust.rs @@ -14,16 +14,18 @@ pub struct Cmd { pub limit: i64, } -impl From<&Cmd> for xdr::OperationBody { - fn from(cmd: &Cmd) -> Self { - let line = match cmd.line.0.clone() { +impl TryFrom<&Cmd> for xdr::OperationBody { + type Error = tx::args::Error; + fn try_from(cmd: &Cmd) -> Result { + let asset = cmd.tx.resolve_asset(&cmd.line)?; + let line = match asset { xdr::Asset::CreditAlphanum4(asset) => xdr::ChangeTrustAsset::CreditAlphanum4(asset), xdr::Asset::CreditAlphanum12(asset) => xdr::ChangeTrustAsset::CreditAlphanum12(asset), xdr::Asset::Native => xdr::ChangeTrustAsset::Native, }; - xdr::OperationBody::ChangeTrust(xdr::ChangeTrustOp { + Ok(xdr::OperationBody::ChangeTrust(xdr::ChangeTrustOp { line, limit: cmd.limit, - }) + })) } } diff --git a/cmd/soroban-cli/src/commands/tx/new/mod.rs b/cmd/soroban-cli/src/commands/tx/new/mod.rs index 1d5682cc0..cba9a52c7 100644 --- a/cmd/soroban-cli/src/commands/tx/new/mod.rs +++ b/cmd/soroban-cli/src/commands/tx/new/mod.rs @@ -59,7 +59,7 @@ impl TryFrom<&Cmd> for OperationBody { Ok(match cmd { Cmd::AccountMerge(cmd) => cmd.try_into()?, Cmd::BumpSequence(cmd) => cmd.into(), - Cmd::ChangeTrust(cmd) => cmd.into(), + Cmd::ChangeTrust(cmd) => cmd.try_into()?, Cmd::CreateAccount(cmd) => cmd.try_into()?, Cmd::ManageData(cmd) => cmd.into(), Cmd::Payment(cmd) => cmd.try_into()?, diff --git a/cmd/soroban-cli/src/commands/tx/new/payment.rs b/cmd/soroban-cli/src/commands/tx/new/payment.rs index 397bf68a7..dd80185e0 100644 --- a/cmd/soroban-cli/src/commands/tx/new/payment.rs +++ b/cmd/soroban-cli/src/commands/tx/new/payment.rs @@ -20,11 +20,18 @@ pub struct Cmd { impl TryFrom<&Cmd> for xdr::OperationBody { type Error = tx::args::Error; - fn try_from(cmd: &Cmd) -> Result { + fn try_from( + Cmd { + tx, + destination, + asset, + amount, + }: &Cmd, + ) -> Result { Ok(xdr::OperationBody::Payment(xdr::PaymentOp { - destination: cmd.tx.reslove_muxed_address(&cmd.destination)?, - asset: cmd.asset.clone().into(), - amount: cmd.amount.into(), + destination: tx.reslove_muxed_address(destination)?, + asset: tx.resolve_asset(asset)?, + amount: amount.into(), })) } } diff --git a/cmd/soroban-cli/src/commands/tx/new/set_trustline_flags.rs b/cmd/soroban-cli/src/commands/tx/new/set_trustline_flags.rs index 318f3ff1d..1c680a60d 100644 --- a/cmd/soroban-cli/src/commands/tx/new/set_trustline_flags.rs +++ b/cmd/soroban-cli/src/commands/tx/new/set_trustline_flags.rs @@ -63,7 +63,7 @@ impl TryFrom<&Cmd> for xdr::OperationBody { Ok(xdr::OperationBody::SetTrustLineFlags( xdr::SetTrustLineFlagsOp { trustor: cmd.tx.reslove_account_id(&cmd.trustor)?, - asset: cmd.asset.clone().into(), + asset: cmd.tx.resolve_asset(&cmd.asset)?, clear_flags, set_flags, }, diff --git a/cmd/soroban-cli/src/tx/builder/asset.rs b/cmd/soroban-cli/src/tx/builder/asset.rs index bba39804e..c67e4b42e 100644 --- a/cmd/soroban-cli/src/tx/builder/asset.rs +++ b/cmd/soroban-cli/src/tx/builder/asset.rs @@ -1,17 +1,24 @@ use std::str::FromStr; -use crate::xdr::{self, AlphaNum12, AlphaNum4, AssetCode}; +use crate::{ + config::{address, locator}, + xdr::{self, AlphaNum12, AlphaNum4, AssetCode}, +}; #[derive(Clone, Debug)] -pub struct Asset(pub xdr::Asset); +pub enum Asset { + Asset(AssetCode, address::Address), + Native, +} #[derive(thiserror::Error, Debug)] pub enum Error { #[error("cannot parse asset: {0}, expected format: 'native' or 'code:issuer'")] CannotParseAsset(String), - #[error(transparent)] Xdr(#[from] xdr::Error), + #[error(transparent)] + Address(#[from] address::Error), } impl FromStr for Asset { @@ -19,32 +26,31 @@ impl FromStr for Asset { fn from_str(value: &str) -> Result { if value == "native" { - return Ok(Asset(xdr::Asset::Native)); + return Ok(Asset::Native); } let mut iter = value.splitn(2, ':'); let (Some(code), Some(issuer), None) = (iter.next(), iter.next(), iter.next()) else { return Err(Error::CannotParseAsset(value.to_string())); }; - let issuer = issuer.parse()?; - Ok(Asset(match code.parse()? { - AssetCode::CreditAlphanum4(asset_code) => { - xdr::Asset::CreditAlphanum4(AlphaNum4 { asset_code, issuer }) - } - AssetCode::CreditAlphanum12(asset_code) => { - xdr::Asset::CreditAlphanum12(AlphaNum12 { asset_code, issuer }) - } - })) + Ok(Asset::Asset(code.parse()?, issuer.parse()?)) } } -impl From for xdr::Asset { - fn from(builder: Asset) -> Self { - builder.0 - } -} - -impl From<&Asset> for xdr::Asset { - fn from(builder: &Asset) -> Self { - builder.clone().into() +impl Asset { + pub fn resolve(&self, locator: &locator::Args) -> Result { + Ok(match self { + Asset::Asset(code, issuer) => { + let issuer = issuer.resolve_muxed_account(locator, None)?.account_id(); + match code.clone() { + AssetCode::CreditAlphanum4(asset_code) => { + xdr::Asset::CreditAlphanum4(AlphaNum4 { asset_code, issuer }) + } + AssetCode::CreditAlphanum12(asset_code) => { + xdr::Asset::CreditAlphanum12(AlphaNum12 { asset_code, issuer }) + } + } + } + Asset::Native => xdr::Asset::Native, + }) } } diff --git a/cmd/soroban-cli/src/utils.rs b/cmd/soroban-cli/src/utils.rs index 0c4207a4e..3efe619ef 100644 --- a/cmd/soroban-cli/src/utils.rs +++ b/cmd/soroban-cli/src/utils.rs @@ -125,13 +125,13 @@ pub fn is_hex_string(s: &str) -> bool { } pub fn contract_id_hash_from_asset( - asset: impl Into, + asset: &Asset, network_passphrase: &str, ) -> stellar_strkey::Contract { let network_id = Hash(Sha256::digest(network_passphrase.as_bytes()).into()); let preimage = HashIdPreimage::ContractId(HashIdPreimageContractId { network_id, - contract_id_preimage: ContractIdPreimage::Asset(asset.into()), + contract_id_preimage: ContractIdPreimage::Asset(asset.clone()), }); let preimage_xdr = preimage .to_xdr(Limits::none())