Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: tx sign --sign-with-lab #1604

Merged
merged 58 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
bf88e36
feat: `tx sign` and new traits for signing
willemneal Sep 10, 2024
df58864
refactor(tx): test
willemneal Sep 10, 2024
58630c3
Merge remote-tracking branch 'origin/main' into feat/tx_sign
willemneal Sep 12, 2024
a0cc592
fix: simplify sign_with
willemneal Sep 12, 2024
329d81e
Fix typo
elizabethengelman Aug 20, 2024
442a6bf
Start to add sign with lab functionality
elizabethengelman Aug 22, 2024
d06b66c
Open Lab on sign_with_lab
elizabethengelman Aug 29, 2024
00f8ba8
Properly encode the url query string
elizabethengelman Aug 29, 2024
a4c5c45
Actually use the tx env passed in
elizabethengelman Aug 29, 2024
c8c7bce
Add lab_url arg
elizabethengelman Aug 30, 2024
75580eb
Handle unwraps
elizabethengelman Aug 30, 2024
daab977
Refactor/cleanup
elizabethengelman Aug 30, 2024
9fead2e
Small fix to default lab url
elizabethengelman Sep 3, 2024
52101d0
Update generated docs
elizabethengelman Sep 3, 2024
8959025
Update default sign with lab url
elizabethengelman Sep 4, 2024
c66425d
Address PR feedback
elizabethengelman Sep 11, 2024
c705666
Apply suggestions from code review
willemneal Sep 16, 2024
5379176
Cleanup
elizabethengelman Sep 17, 2024
d23986c
Merge branch 'feat/tx_sign' into feat/sign_with_lab
elizabethengelman Sep 17, 2024
00aaedc
fix: address PR review
willemneal Sep 17, 2024
8745dc5
Merge remote-tracking branch 'origin/main' into feat/tx_sign
willemneal Sep 17, 2024
ada184f
Merge remote-tracking branch 'origin/main' into feat/tx_sign
willemneal Sep 18, 2024
00d989a
fix: remove unneeded arg
willemneal Sep 18, 2024
0a378c5
Merge branch 'feat/tx_sign' into feat/sign_with_lab
elizabethengelman Sep 19, 2024
bc6d3bc
Cleanup after merge
elizabethengelman Sep 19, 2024
c36f788
rename Transaction trait to SignTx and collapse traits
leighmcculloch Sep 23, 2024
1470057
rename account to key
leighmcculloch Sep 23, 2024
70837be
update docs
leighmcculloch Sep 23, 2024
bf7f88d
flatten layer of one liner
leighmcculloch Sep 23, 2024
c2a7cc2
undo move transaction_hash, remove trait
leighmcculloch Sep 23, 2024
df299e8
undo change
leighmcculloch Sep 23, 2024
9beed05
rename Stellar error to Signer
leighmcculloch Sep 23, 2024
d3e22cc
move StellarSigner and eliminate trait
leighmcculloch Sep 23, 2024
ded7eba
handle instead of panic on error
leighmcculloch Sep 23, 2024
015435b
move types into signer and replace existing signing logic
leighmcculloch Sep 23, 2024
baf7036
address clippy
leighmcculloch Sep 23, 2024
f3fbff7
lab.stellar.org
leighmcculloch Sep 23, 2024
d56fa09
clippy
leighmcculloch Sep 23, 2024
d79933f
Merge remote-tracking branch 'origin/feat/tx_sign' into feat/sign_wit…
willemneal Sep 23, 2024
9edbfb6
fix: hard code lab url and use printer for output
willemneal Sep 23, 2024
25102a0
remove unnecessary trim
leighmcculloch Sep 24, 2024
02245e7
fix e2e test run and tweak
leighmcculloch Sep 24, 2024
376c464
remove deadcode
leighmcculloch Sep 24, 2024
1db4b5a
remove sign with lab
leighmcculloch Sep 24, 2024
d2300cb
Merge branch 'feat/tx_sign' into feat/sign_with_lab
leighmcculloch Sep 24, 2024
4322f6e
Merge branch 'main' into feat/sign_with_lab
leighmcculloch Sep 24, 2024
faa9b5b
fix
leighmcculloch Sep 24, 2024
b8e44a3
fix: use globeln for printing url
willemneal Sep 24, 2024
0b51621
Merge branch 'main' into feat/sign_with_lab
willemneal Sep 24, 2024
94f0526
fix: test
willemneal Sep 24, 2024
5b0c841
feat: add a new SignerKind::Lab to centralize signing logic
willemneal Sep 24, 2024
d5cbd38
reorder fn params in same order as related fns
leighmcculloch Sep 24, 2024
a6a61aa
remove unnecessary pub, clone, and qualifier
leighmcculloch Sep 25, 2024
ad2152c
space
leighmcculloch Sep 25, 2024
4a3aed8
ref xdr mod
leighmcculloch Sep 25, 2024
a86af7e
clippy warning
leighmcculloch Sep 25, 2024
2bb71f7
Merge branch 'main' into feat/sign_with_lab
leighmcculloch Sep 25, 2024
acc019d
Pass print instead of quiet
leighmcculloch Sep 25, 2024
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
32 changes: 32 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ termcolor = "1.1.3"
termcolor_output = "1.0.1"
ed25519-dalek = ">= 2.1.1"

# networking
# networking
http = "1.0.0"
jsonrpsee-http-client = "0.20.1"
jsonrpsee-core = "0.20.1"
Expand Down
1 change: 1 addition & 0 deletions FULL_HELP_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1338,6 +1338,7 @@ Sign a transaction envelope appending the signature to the envelope

* `--sign-with-key <SIGN_WITH_KEY>` — Sign with a local key. 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>
* `--rpc-url <RPC_URL>` — RPC server endpoint
* `--network-passphrase <NETWORK_PASSPHRASE>` — Network passphrase to sign the transaction sent to the rpc server
* `--network <NETWORK>` — Name of network to use from config
Expand Down
3 changes: 1 addition & 2 deletions cmd/crates/soroban-test/tests/it/integration/tx.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use soroban_rpc::GetTransactionResponse;
use soroban_sdk::xdr::{Limits, ReadXdr, TransactionEnvelope, WriteXdr};
use soroban_test::{AssertExt, TestEnv};

use crate::integration::util::{deploy_contract, deploy_hello, DeployKind, HELLO_WORLD};
use crate::integration::util::{deploy_contract, DeployKind, HELLO_WORLD};

#[tokio::test]
async fn simulate() {
Expand Down
2 changes: 2 additions & 0 deletions cmd/soroban-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ humantime = "2.1.0"
phf = { version = "0.11.2", features = ["macros"] }
semver = "1.0.0"
glob = "0.3.1"
open = "5.3.0"
url = "2.5.2"

# For hyper-tls
[target.'cfg(unix)'.dependencies]
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/tx/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl Cmd {
pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> {
let tx_env = super::xdr::tx_envelope_from_stdin()?;
let tx_env_signed = self.sign_with.sign_tx_env(
tx_env,
&tx_env,
&self.locator,
&self.network.get(&self.locator)?,
global_args.quiet,
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl Args {
let network = &self.get_network()?;
let signer = Signer {
kind: SignerKind::Local(LocalKey { key }),
printer: Print::new(false),
print: Print::new(false),
};
Ok(signer.sign_tx(tx, network)?)
}
Expand Down
9 changes: 3 additions & 6 deletions cmd/soroban-cli/src/config/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize};
use std::{io::Write, str::FromStr};
use stellar_strkey::ed25519::{PrivateKey, PublicKey};

use crate::print::Print;
use crate::{
print::Print,
signer::{self, LocalKey, Signer, SignerKind},
utils,
};
Expand Down Expand Up @@ -126,17 +126,14 @@ impl Secret {
)?)
}

pub fn signer(&self, index: Option<usize>, quiet: bool) -> Result<Signer, Error> {
pub fn signer(&self, index: Option<usize>, print: Print) -> Result<Signer, Error> {
let kind = match self {
Secret::SecretKey { .. } | Secret::SeedPhrase { .. } => {
let key = self.key_pair(index)?;
SignerKind::Local(LocalKey { key })
}
};
Ok(Signer {
kind,
printer: Print::new(quiet),
})
Ok(Signer { kind, print })
}

pub fn key_pair(&self, index: Option<usize>) -> Result<ed25519_dalek::SigningKey, Error> {
Expand Down
28 changes: 23 additions & 5 deletions cmd/soroban-cli/src/config/sign_with.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use crate::{signer, xdr::TransactionEnvelope};
use crate::{
print::Print,
signer::{self, Signer, SignerKind},
xdr::{self, TransactionEnvelope},
};
use clap::arg;

use super::{
Expand All @@ -23,6 +27,8 @@ pub enum Error {
NoSignWithKey,
#[error(transparent)]
StrKey(#[from] stellar_strkey::DecodeError),
#[error(transparent)]
Xdr(#[from] xdr::Error),
}

#[derive(Debug, clap::Args, Clone, Default)]
Expand All @@ -35,19 +41,31 @@ pub struct Args {
#[arg(long, requires = "sign_with_key")]
/// 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`
pub hd_path: Option<usize>,

/// Sign with <https://lab.stellar.org>
#[arg(long, conflicts_with = "sign_with_key", env = "STELLAR_SIGN_WITH_LAB")]
pub sign_with_lab: bool,
}

impl Args {
pub fn sign_tx_env(
&self,
tx: TransactionEnvelope,
tx: &TransactionEnvelope,
locator: &locator::Args,
network: &Network,
quiet: bool,
) -> Result<TransactionEnvelope, Error> {
let key_or_name = self.sign_with_key.as_deref().ok_or(Error::NoSignWithKey)?;
let secret = locator.key(key_or_name)?;
let signer = secret.signer(self.hd_path, quiet)?;
let print = Print::new(quiet);
let signer = if self.sign_with_lab {
Signer {
kind: SignerKind::Lab,
print,
}
} else {
let key_or_name = self.sign_with_key.as_deref().ok_or(Error::NoSignWithKey)?;
let secret = locator.key(key_or_name)?;
secret.signer(self.hd_path, print)?
};
Ok(signer.sign_tx_env(tx, network)?)
}
}
51 changes: 42 additions & 9 deletions cmd/soroban-cli/src/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ pub enum Error {
Xdr(#[from] xdr::Error),
#[error("Only Transaction envelope V1 type is supported")]
UnsupportedTransactionEnvelopeType,
#[error(transparent)]
Url(#[from] url::ParseError),
#[error(transparent)]
Open(#[from] std::io::Error),
#[error("Returning a signature from Lab is not yet supported; Transaction can be found and submitted in lab")]
ReturningSignatureFromLab,
}

fn requires_auth(txn: &Transaction) -> Option<xdr::Operation> {
Expand Down Expand Up @@ -194,12 +200,13 @@ fn sign_soroban_authorization_entry(

pub struct Signer {
pub kind: SignerKind,
pub printer: Print,
pub print: Print,
}

#[allow(clippy::module_name_repetitions)]
#[allow(clippy::module_name_repetitions, clippy::large_enum_variant)]
pub enum SignerKind {
Local(LocalKey),
Lab,
}

impl Signer {
Expand All @@ -212,26 +219,27 @@ impl Signer {
tx,
signatures: VecM::default(),
});
self.sign_tx_env(tx_env, network)
self.sign_tx_env(&tx_env, network)
}

pub fn sign_tx_env(
&self,
tx_env: TransactionEnvelope,
tx_env: &TransactionEnvelope,
network: &Network,
) -> Result<TransactionEnvelope, Error> {
match tx_env {
match &tx_env {
TransactionEnvelope::Tx(TransactionV1Envelope { tx, signatures }) => {
let tx_hash = transaction_hash(&tx, &network.network_passphrase)?;
self.printer
let tx_hash = transaction_hash(tx, &network.network_passphrase)?;
self.print
.infoln(format!("Signing transaction: {}", hex::encode(tx_hash),));
let decorated_signature = match &self.kind {
SignerKind::Local(key) => key.sign_tx_hash(tx_hash)?,
SignerKind::Lab => Lab::sign_tx_env(tx_env, network, &self.print)?,
};
let mut sigs = signatures.into_vec();
let mut sigs = signatures.clone().into_vec();
sigs.push(decorated_signature);
Ok(TransactionEnvelope::Tx(TransactionV1Envelope {
tx,
tx: tx.clone(),
signatures: sigs.try_into()?,
}))
}
Expand All @@ -251,3 +259,28 @@ impl LocalKey {
Ok(DecoratedSignature { hint, signature })
}
}

pub struct Lab;

impl Lab {
const URL: &str = "https://lab.stellar.org/transaction/cli-sign";

pub fn sign_tx_env(
tx_env: &TransactionEnvelope,
network: &Network,
printer: &Print,
) -> Result<DecoratedSignature, Error> {
let xdr = tx_env.to_xdr_base64(Limits::none())?;

let mut url = url::Url::parse(Self::URL)?;
url.query_pairs_mut()
.append_pair("networkPassphrase", &network.network_passphrase)
.append_pair("xdr", &xdr);
let url = url.to_string();

printer.globeln(format!("Opening lab to sign transaction: {url}"));
open::that(url)?;

Err(Error::ReturningSignatureFromLab)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future it'd be good to add a TODO with a task number in the code

}
}
Loading