-
Notifications
You must be signed in to change notification settings - Fork 129
Expand file tree
/
Copy pathmod.rs
More file actions
226 lines (197 loc) · 6.25 KB
/
mod.rs
File metadata and controls
226 lines (197 loc) · 6.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
use serde::{Deserialize, Serialize};
use std::{
fs::{self, File},
io::Write,
};
use crate::{
print::Print,
signer::{self, Signer},
xdr::{self, SequenceNumber, Transaction, TransactionEnvelope, TransactionV1Envelope, VecM},
Pwd,
};
use network::Network;
pub mod address;
pub mod alias;
pub mod data;
pub mod key;
pub mod locator;
pub mod network;
pub mod sc_address;
pub mod secret;
pub mod sign_with;
pub mod upgrade_check;
use crate::config::locator::cli_config_file;
pub use address::UnresolvedMuxedAccount;
pub use alias::UnresolvedContract;
pub use sc_address::UnresolvedScAddress;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Network(#[from] network::Error),
#[error(transparent)]
Secret(#[from] secret::Error),
#[error(transparent)]
Locator(#[from] locator::Error),
#[error(transparent)]
Rpc(#[from] soroban_rpc::Error),
#[error(transparent)]
Signer(#[from] signer::Error),
#[error(transparent)]
SignWith(#[from] sign_with::Error),
#[error(transparent)]
StellarStrkey(#[from] stellar_strkey::DecodeError),
#[error(transparent)]
Address(#[from] address::Error),
}
#[derive(Debug, clap::Args, Clone, Default)]
#[group(skip)]
pub struct Args {
#[command(flatten)]
pub network: network::Args,
#[arg(long, short = 's', visible_alias = "source", env = "STELLAR_ACCOUNT")]
/// 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` or `--sim-only` flags were NOT provided, this key will also be used to
/// sign the final transaction. In that case, trying to sign with public key will fail.
pub source_account: UnresolvedMuxedAccount,
#[command(flatten)]
pub locator: locator::Args,
#[command(flatten)]
pub sign_with: sign_with::Args,
}
impl Args {
// TODO: Replace PublicKey with MuxedAccount once https://github.com/stellar/rs-stellar-xdr/pull/396 is merged.
pub async fn source_account(&self) -> Result<xdr::MuxedAccount, Error> {
Ok(self
.source_account
.resolve_muxed_account(&self.locator, self.hd_path())
.await?)
}
pub async fn source_signer(&self) -> Result<Signer, Error> {
let print = Print::new(true);
let secret = &self.source_account.resolve_secret(&self.locator)?;
Ok(secret.signer(None, print).await?)
}
pub fn key_pair(&self) -> Result<ed25519_dalek::SigningKey, Error> {
let key = &self.source_account.resolve_secret(&self.locator)?;
Ok(key.key_pair(self.hd_path())?)
}
pub async fn sign(&self, tx: Transaction, quiet: bool) -> Result<TransactionEnvelope, Error> {
let tx_env = TransactionEnvelope::Tx(TransactionV1Envelope {
tx,
signatures: VecM::default(),
});
Ok(self
.sign_with
.sign_tx_env(
&tx_env,
&self.locator,
&self.network.get(&self.locator)?,
quiet,
Some(&self.source_account),
)
.await?)
}
pub async fn sign_soroban_authorizations(
&self,
tx: &Transaction,
signers: &[Signer],
) -> Result<Option<Transaction>, Error> {
let network = self.get_network()?;
let source_signer = self.source_signer().await?;
let client = network.rpc_client()?;
let latest_ledger = client.get_latest_ledger().await?.sequence;
let seq_num = latest_ledger + 60; // ~ 5 min
Ok(signer::sign_soroban_authorizations(
tx,
&source_signer,
signers,
seq_num,
&network.network_passphrase,
)
.await?)
}
pub fn get_network(&self) -> Result<Network, Error> {
Ok(self.network.get(&self.locator)?)
}
pub async fn next_sequence_number(
&self,
account: impl Into<xdr::AccountId>,
) -> Result<SequenceNumber, Error> {
let network = self.get_network()?;
let client = network.rpc_client()?;
Ok((client
.get_account(&account.into().to_string())
.await?
.seq_num
.0
+ 1)
.into())
}
pub fn hd_path(&self) -> Option<usize> {
self.sign_with.hd_path
}
}
impl Pwd for Args {
fn set_pwd(&mut self, pwd: &std::path::Path) {
self.locator.set_pwd(pwd);
}
}
#[derive(Debug, clap::Args, Clone, Default)]
#[group(skip)]
pub struct ArgsLocatorAndNetwork {
#[command(flatten)]
pub network: network::Args,
#[command(flatten)]
pub locator: locator::Args,
}
impl ArgsLocatorAndNetwork {
pub fn get_network(&self) -> Result<Network, Error> {
Ok(self.network.get(&self.locator)?)
}
}
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Config {
pub defaults: Defaults,
}
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Defaults {
pub network: Option<String>,
pub identity: Option<String>,
}
impl Config {
pub fn new() -> Result<Config, locator::Error> {
let path = cli_config_file()?;
if path.exists() {
let data = fs::read_to_string(&path).map_err(|_| locator::Error::FileRead { path })?;
Ok(toml::from_str(&data)?)
} else {
Ok(Config::default())
}
}
#[must_use]
pub fn set_network(mut self, s: &str) -> Self {
self.defaults.network = Some(s.to_string());
self
}
#[must_use]
pub fn set_identity(mut self, s: &str) -> Self {
self.defaults.identity = Some(s.to_string());
self
}
#[must_use]
pub fn unset_identity(mut self) -> Self {
self.defaults.identity = None;
self
}
pub fn save(&self) -> Result<(), locator::Error> {
let toml_string = toml::to_string(&self)?;
let path = cli_config_file()?;
// Depending on the platform, this function may fail if the full directory path does not exist
let mut file = File::create(locator::ensure_directory(path)?)?;
file.write_all(toml_string.as_bytes())?;
Ok(())
}
}