use std::path::PathBuf;
use clap::{arg, command};
use serde::{Deserialize, Serialize};
use soroban_rpc::Client;
use crate::{
signer,
xdr::{Transaction, TransactionEnvelope},
Pwd,
};
use self::{network::Network, secret::Secret};
pub mod alias;
pub mod data;
pub mod locator;
pub mod network;
pub mod secret;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Network(#[from] network::Error),
#[error(transparent)]
Secret(#[from] secret::Error),
#[error(transparent)]
Config(#[from] locator::Error),
#[error(transparent)]
Rpc(#[from] soroban_rpc::Error),
#[error(transparent)]
Signer(#[from] signer::Error),
}
#[derive(Debug, clap::Args, Clone, Default)]
#[group(skip)]
pub struct Args {
#[command(flatten)]
pub network: network::Args,
#[arg(long, visible_alias = "source", env = "STELLAR_ACCOUNT")]
pub source_account: String,
#[arg(long)]
pub hd_path: Option<usize>,
#[command(flatten)]
pub locator: locator::Args,
}
impl Args {
pub fn key_pair(&self) -> Result<ed25519_dalek::SigningKey, Error> {
let key = self.account(&self.source_account)?;
Ok(key.key_pair(self.hd_path)?)
}
pub async fn sign_with_local_key(&self, tx: Transaction) -> Result<TransactionEnvelope, Error> {
self.sign(tx).await
}
#[allow(clippy::unused_async)]
pub async fn sign(&self, tx: Transaction) -> Result<TransactionEnvelope, Error> {
let key = self.key_pair()?;
let Network {
network_passphrase, ..
} = &self.get_network()?;
Ok(signer::sign_tx(&key, &tx, network_passphrase)?)
}
pub async fn sign_soroban_authorizations(
&self,
tx: &Transaction,
signers: &[ed25519_dalek::SigningKey],
) -> Result<Option<Transaction>, Error> {
let network = self.get_network()?;
let source_key = self.key_pair()?;
let client = Client::new(&network.rpc_url)?;
let latest_ledger = client.get_latest_ledger().await?.sequence;
let seq_num = latest_ledger + 60; Ok(signer::sign_soroban_authorizations(
tx,
&source_key,
signers,
seq_num,
&network.network_passphrase,
)?)
}
pub fn account(&self, account_str: &str) -> Result<Secret, Error> {
if let Ok(secret) = self.locator.read_identity(account_str) {
Ok(secret)
} else {
Ok(account_str.parse::<Secret>()?)
}
}
pub fn get_network(&self) -> Result<Network, Error> {
Ok(self.network.get(&self.locator)?)
}
pub fn config_dir(&self) -> Result<PathBuf, Error> {
Ok(self.locator.config_dir()?)
}
}
impl Pwd for Args {
fn set_pwd(&mut self, pwd: &std::path::Path) {
self.locator.set_pwd(pwd);
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct Config {}