Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions FULL_HELP_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1877,6 +1877,7 @@ Create a new transaction
- `revoke-sponsorship` — Revoke sponsorship of a ledger entry or signer
- `set-options` — Set account options like flags, signers, and home domain
- `set-trustline-flags` — Configure authorization and trustline flags for an asset
- `invoke` — Invoke a smart contract using a given InvokeHostFunctionOp XDR

## `stellar tx new account-merge`

Expand Down Expand Up @@ -2624,6 +2625,36 @@ Configure authorization and trustline flags for an asset
- `--network-passphrase <NETWORK_PASSPHRASE>` — Network passphrase to sign the transaction sent to the rpc server
- `-n`, `--network <NETWORK>` — Name of network to use from config

## `stellar tx new invoke`

Invoke a smart contract using a given InvokeHostFunctionOp XDR

**Usage:** `stellar tx new invoke [OPTIONS] --source-account <SOURCE_ACCOUNT> --xdr <XDR>`

###### **Options:**

- `-s`, `--source-account <SOURCE_ACCOUNT>` [alias: `source`] — Account that where transaction originates from. Alias `source`. Can be an identity (--source alice), a public key (--source GDKW...), a muxed account (--source MDA…), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). If `--build-only` was NOT provided, this key will also be used to sign the final transaction. In that case, trying to sign with public key will fail
- `--sign-with-key <SIGN_WITH_KEY>` — Sign with a local key or key saved in OS secure storage. Can be an identity (--sign-with-key alice), a secret key (--sign-with-key SC36…), or a seed phrase (--sign-with-key "kite urban…"). If using seed phrase, `--hd-path` defaults to the `0` path
- `--hd-path <HD_PATH>` — If using a seed phrase to sign, sets which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0`
- `--sign-with-lab` — Sign with https://lab.stellar.org
- `--sign-with-ledger` — Sign with a ledger wallet
- `--fee <FEE>` — ⚠️ Deprecated, use `--inclusion-fee`. Fee amount for transaction, in stroops. 1 stroop = 0.0000001 xlm
- `--inclusion-fee <INCLUSION_FEE>` — Maximum fee amount for transaction inclusion, in stroops. 1 stroop = 0.0000001 xlm. Defaults to 100 if no arg, env, or config value is provided
- `--build-only` — Build the transaction and only write the base64 xdr to stdout
- `--xdr <XDR>` — Base-64 InvokeContractArgs envelope XDR or file containing XDR to decode

###### **Options (Global):**

- `--global` — ⚠️ Deprecated: global config is always on
- `--config-dir <CONFIG_DIR>` — Location of config directory. By default, it uses `$XDG_CONFIG_HOME/stellar` if set, falling back to `~/.config/stellar` otherwise. Contains configuration files, aliases, and other persistent settings

###### **Options (RPC):**

- `--rpc-url <RPC_URL>` — RPC server endpoint
- `--rpc-header <RPC_HEADERS>` — RPC Header(s) to include in requests to the RPC provider, example: "X-API-Key: abc123". Multiple headers can be added by passing the option multiple times
- `--network-passphrase <NETWORK_PASSPHRASE>` — Network passphrase to sign the transaction sent to the rpc server
- `-n`, `--network <NETWORK>` — Name of network to use from config

## `stellar tx operation`

Manipulate the operations in a transaction, including adding new operations
Expand Down
28 changes: 25 additions & 3 deletions cmd/soroban-cli/src/commands/contract/arg_parsing.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::commands::contract::arg_parsing::Error::HelpMessage;
use crate::commands::contract::arg_parsing::Error::{CannotParseXDR, HelpMessage};
use crate::commands::contract::deploy::wasm::CONSTRUCTOR_FUNCTION_NAME;
use crate::commands::txn_result::TxnResult;
use crate::config::{self, sc_address, UnresolvedScAddress};
Expand All @@ -16,8 +16,12 @@ use std::convert::TryInto;
use std::env;
use std::ffi::OsString;
use std::fmt::Debug;
use std::path::PathBuf;
use stellar_xdr::curr::ContractId;
use std::fs::File;
use std::io::{Cursor, Read};
use std::path::{Path, PathBuf};
use stellar_xdr::curr::{
ContractId, InvokeHostFunctionOp, Limited, Limits, ReadXdr, SkipWhitespace,
};

#[derive(thiserror::Error, Debug)]
pub enum Error {
Expand Down Expand Up @@ -77,6 +81,10 @@ pub enum Error {
HelpMessage(String),
#[error(transparent)]
Signer(#[from] signer::Error),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error("cannot parse XDR: {error}")]
CannotParseXDR { error: xdr::Error },
}

pub type HostFunctionParameters = (String, Spec, InvokeContractArgs, Vec<Signer>);
Expand Down Expand Up @@ -126,6 +134,20 @@ async fn build_host_function_parameters_with_filter(
Ok((function, spec, invoke_args, signers))
}

pub fn invoke_host_function_op_from_input(input: &OsString) -> Result<InvokeHostFunctionOp, Error> {
let read: &mut dyn Read = {
let exist = Path::new(input).try_exists();
if let Ok(true) = exist {
&mut File::open(input)?
} else {
&mut Cursor::new(input.clone().into_encoded_bytes())
}
};

let mut lim = Limited::new(SkipWhitespace::new(read), Limits::none());
InvokeHostFunctionOp::read_xdr_base64_to_end(&mut lim).map_err(|e| CannotParseXDR { error: e })
}

fn build_clap_command(spec: &Spec, filter_constructor: bool) -> Result<clap::Command, Error> {
let mut cmd = clap::Command::new(running_cmd())
.no_binary_name(true)
Expand Down
3 changes: 3 additions & 0 deletions cmd/soroban-cli/src/commands/tx/args.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::commands::contract::arg_parsing;
use crate::{
commands::{global, txn_result::TxnEnvelopeResult},
config::{
Expand Down Expand Up @@ -50,6 +51,8 @@ pub enum Error {
InvalidPoolId(String),
#[error("invalid hex for {name}: {hex}")]
InvalidHex { name: String, hex: String },
#[error(transparent)]
ArgParsing(#[from] arg_parsing::Error),
}

impl Args {
Expand Down
1 change: 1 addition & 0 deletions cmd/soroban-cli/src/commands/tx/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ pub const BEGIN_SPONSORING_FUTURE_RESERVES: &str =
"Begin sponsoring future reserves for another account";
pub const END_SPONSORING_FUTURE_RESERVES: &str = "End sponsoring future reserves";
pub const REVOKE_SPONSORSHIP: &str = "Revoke sponsorship of a ledger entry or signer";
pub const INVOKE: &str = "Invoke a smart contract using a given InvokeHostFunctionOp XDR";
31 changes: 31 additions & 0 deletions cmd/soroban-cli/src/commands/tx/new/invoke.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::commands::contract::arg_parsing::invoke_host_function_op_from_input;
use crate::{commands::tx, xdr};
use clap::Parser;
use std::ffi::OsString;
use stellar_xdr::curr::OperationBody;

#[derive(Parser, Debug, Clone)]
#[group(skip)]
pub struct Cmd {
#[command(flatten)]
pub tx: tx::Args,
#[clap(flatten)]
pub op: Args,
}

#[derive(Debug, clap::Args, Clone)]
#[allow(clippy::struct_excessive_bools, clippy::doc_markdown)]
pub struct Args {
/// Base-64 InvokeContractArgs envelope XDR or file containing XDR to decode.
#[arg(long)]
pub xdr: OsString,
}

impl TryFrom<&Cmd> for xdr::OperationBody {
type Error = tx::args::Error;
fn try_from(cmd: &Cmd) -> Result<Self, Self::Error> {
let parameters = invoke_host_function_op_from_input(&cmd.op.xdr)?;

Ok(OperationBody::InvokeHostFunction(parameters))
}
}
5 changes: 5 additions & 0 deletions cmd/soroban-cli/src/commands/tx/new/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod create_account;
pub mod create_claimable_balance;
pub mod create_passive_sell_offer;
pub mod end_sponsoring_future_reserves;
pub mod invoke;
pub mod liquidity_pool_deposit;
pub mod liquidity_pool_withdraw;
pub mod manage_buy_offer;
Expand Down Expand Up @@ -73,6 +74,8 @@ pub enum Cmd {
SetOptions(set_options::Cmd),
#[command(about = super::help::SET_TRUSTLINE_FLAGS)]
SetTrustlineFlags(set_trustline_flags::Cmd),
#[command(about = super::help::INVOKE)]
Invoke(invoke::Cmd),
}

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -107,6 +110,7 @@ impl TryFrom<&Cmd> for OperationBody {
Cmd::RevokeSponsorship(cmd) => cmd.try_into()?,
Cmd::SetOptions(cmd) => cmd.try_into()?,
Cmd::SetTrustlineFlags(cmd) => cmd.try_into()?,
Cmd::Invoke(cmd) => cmd.try_into()?,
})
}
}
Expand Down Expand Up @@ -139,6 +143,7 @@ impl Cmd {
Cmd::RevokeSponsorship(cmd) => cmd.tx.handle_and_print(op, global_args).await,
Cmd::SetOptions(cmd) => cmd.tx.handle_and_print(op, global_args).await,
Cmd::SetTrustlineFlags(cmd) => cmd.tx.handle_and_print(op, global_args).await,
Cmd::Invoke(cmd) => cmd.tx.handle_and_print(op, global_args).await,
}?;
Ok(())
}
Expand Down
30 changes: 1 addition & 29 deletions cmd/soroban-cli/src/commands/tx/xdr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::fs::File;
use std::io::{stdin, Read};
use std::io::{Cursor, IsTerminal};
use std::path::Path;
use stellar_xdr::curr::Limited;
use stellar_xdr::curr::{Limited, SkipWhitespace};

#[derive(Debug, thiserror::Error)]
pub enum Error {
Expand Down Expand Up @@ -41,34 +41,6 @@ pub fn tx_envelope_from_input(input: &Option<OsString>) -> Result<TransactionEnv
Ok(TransactionEnvelope::read_xdr_base64_to_end(&mut lim)?)
}

// TODO: use SkipWhitespace from rs-stellar-xdr once it's updated to 23.0
pub struct SkipWhitespace<R: Read> {
pub inner: R,
}

impl<R: Read> SkipWhitespace<R> {
pub fn new(inner: R) -> Self {
SkipWhitespace { inner }
}
}

impl<R: Read> Read for SkipWhitespace<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let n = self.inner.read(buf)?;

let mut written = 0;
for read in 0..n {
if !buf[read].is_ascii_whitespace() {
buf[written] = buf[read];
written += 1;
}
}

Ok(written)
}
}
//

pub fn unwrap_envelope_v1(tx_env: TransactionEnvelope) -> Result<Transaction, Error> {
let TransactionEnvelope::Tx(TransactionV1Envelope { tx, .. }) = tx_env else {
return Err(Error::OnlyTransactionV1Supported);
Expand Down
Loading