Skip to content

Commit

Permalink
feat: improve asset parsing to use named keys as issuer
Browse files Browse the repository at this point in the history
Previously the issuer had to be a fully resolved `xdr::AccountId`, now it  can be an `Address`, which then can be resolved. Thus allowing the following: `USDC:circle`
  • Loading branch information
willemneal authored and gitbutler-client committed Nov 30, 2024
1 parent e5f0e5d commit 85937c8
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 40 deletions.
6 changes: 4 additions & 2 deletions cmd/soroban-cli/src/commands/contract/deploy/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Infallible> for Error {
Expand Down Expand Up @@ -85,7 +87,7 @@ impl NetworkRunnable for Cmd {
) -> Result<Self::Result, Error> {
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()?;
Expand All @@ -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,
Expand Down
7 changes: 6 additions & 1 deletion cmd/soroban-cli/src/commands/contract/id/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -30,7 +32,10 @@ impl Cmd {

pub fn contract_address(&self) -> Result<stellar_strkey::Contract, Error> {
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))
}
}
4 changes: 3 additions & 1 deletion cmd/soroban-cli/src/commands/snapshot/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
8 changes: 7 additions & 1 deletion cmd/soroban-cli/src/commands/tx/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
},
fee,
rpc::{self, Client, GetTransactionResponse},
tx::builder::{self, TxExt},
tx::builder::{self, asset, TxExt},
xdr::{self, Limits, WriteXdr},
};

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<xdr::Asset, Error> {
Ok(asset.resolve(&self.config.locator)?)
}
}
12 changes: 7 additions & 5 deletions cmd/soroban-cli/src/commands/tx/new/change_trust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Self, Self::Error> {
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,
})
}))
}
}
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/tx/new/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()?,
Expand Down
15 changes: 11 additions & 4 deletions cmd/soroban-cli/src/commands/tx/new/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,18 @@ pub struct Cmd {

impl TryFrom<&Cmd> for xdr::OperationBody {
type Error = tx::args::Error;
fn try_from(cmd: &Cmd) -> Result<Self, Self::Error> {
fn try_from(
Cmd {
tx,
destination,
asset,
amount,
}: &Cmd,
) -> Result<Self, Self::Error> {
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(),
}))
}
}
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/tx/new/set_trustline_flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down
50 changes: 28 additions & 22 deletions cmd/soroban-cli/src/tx/builder/asset.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,56 @@
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 {
type Err = Error;

fn from_str(value: &str) -> Result<Self, Self::Err> {
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<Asset> 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<xdr::Asset, Error> {
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,
})
}
}
4 changes: 2 additions & 2 deletions cmd/soroban-cli/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,13 @@ pub fn is_hex_string(s: &str) -> bool {
}

pub fn contract_id_hash_from_asset(
asset: impl Into<Asset>,
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())
Expand Down

0 comments on commit 85937c8

Please sign in to comment.