soroban_cli/config/
key.rs1use std::{fmt::Display, str::FromStr};
2
3use serde::{Deserialize, Serialize};
4
5use super::secret::{self, Secret};
6use crate::xdr;
7
8#[derive(thiserror::Error, Debug)]
9pub enum Error {
10 #[error("failed to extract secret from public key ")]
11 SecretPublicKey,
12 #[error(transparent)]
13 Secret(#[from] secret::Error),
14 #[error(transparent)]
15 StrKey(#[from] stellar_strkey::DecodeError),
16 #[error("failed to parse key")]
17 Parse,
18}
19
20#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
21pub enum Key {
22 #[serde(rename = "public_key")]
23 PublicKey(Public),
24 #[serde(rename = "muxed_account")]
25 MuxedAccount(MuxedAccount),
26 #[serde(untagged)]
27 Secret(Secret),
28}
29
30impl Key {
31 pub fn muxed_account(&self, hd_path: Option<usize>) -> Result<xdr::MuxedAccount, Error> {
32 let bytes = match self {
33 Key::Secret(secret) => secret.public_key(hd_path)?.0,
34 Key::PublicKey(Public(key)) => key.0,
35 Key::MuxedAccount(MuxedAccount(stellar_strkey::ed25519::MuxedAccount {
36 ed25519,
37 id,
38 })) => {
39 return Ok(xdr::MuxedAccount::MuxedEd25519(xdr::MuxedAccountMed25519 {
40 ed25519: xdr::Uint256(*ed25519),
41 id: *id,
42 }))
43 }
44 };
45 Ok(xdr::MuxedAccount::Ed25519(xdr::Uint256(bytes)))
46 }
47
48 pub fn private_key(
49 &self,
50 hd_path: Option<usize>,
51 ) -> Result<stellar_strkey::ed25519::PrivateKey, Error> {
52 match self {
53 Key::Secret(secret) => Ok(secret.private_key(hd_path)?),
54 _ => Err(Error::SecretPublicKey),
55 }
56 }
57}
58
59impl FromStr for Key {
60 type Err = Error;
61
62 fn from_str(s: &str) -> Result<Self, Self::Err> {
63 if let Ok(secret) = s.parse() {
64 return Ok(Key::Secret(secret));
65 }
66 if let Ok(public_key) = s.parse() {
67 return Ok(Key::PublicKey(public_key));
68 }
69 if let Ok(muxed_account) = s.parse() {
70 return Ok(Key::MuxedAccount(muxed_account));
71 }
72 Err(Error::Parse)
73 }
74}
75
76impl From<stellar_strkey::ed25519::PublicKey> for Key {
77 fn from(value: stellar_strkey::ed25519::PublicKey) -> Self {
78 Key::PublicKey(Public(value))
79 }
80}
81
82impl From<&stellar_strkey::ed25519::PublicKey> for Key {
83 fn from(stellar_strkey::ed25519::PublicKey(key): &stellar_strkey::ed25519::PublicKey) -> Self {
84 stellar_strkey::ed25519::PublicKey(*key).into()
85 }
86}
87
88#[derive(Debug, PartialEq, Eq, serde_with::SerializeDisplay, serde_with::DeserializeFromStr)]
89pub struct Public(pub stellar_strkey::ed25519::PublicKey);
90
91impl FromStr for Public {
92 type Err = stellar_strkey::DecodeError;
93
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 Ok(Public(stellar_strkey::ed25519::PublicKey::from_str(s)?))
96 }
97}
98
99impl Display for Public {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 write!(f, "{}", self.0)
102 }
103}
104
105impl From<&Public> for stellar_strkey::ed25519::MuxedAccount {
106 fn from(Public(stellar_strkey::ed25519::PublicKey(key)): &Public) -> Self {
107 stellar_strkey::ed25519::MuxedAccount {
108 id: 0,
109 ed25519: *key,
110 }
111 }
112}
113
114#[derive(Debug, PartialEq, Eq, serde_with::SerializeDisplay, serde_with::DeserializeFromStr)]
115pub struct MuxedAccount(pub stellar_strkey::ed25519::MuxedAccount);
116
117impl FromStr for MuxedAccount {
118 type Err = stellar_strkey::DecodeError;
119
120 fn from_str(s: &str) -> Result<Self, Self::Err> {
121 Ok(MuxedAccount(
122 stellar_strkey::ed25519::MuxedAccount::from_str(s)?,
123 ))
124 }
125}
126
127impl Display for MuxedAccount {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 write!(f, "{}", self.0)
130 }
131}
132
133impl TryFrom<Key> for Secret {
134 type Error = Error;
135
136 fn try_from(key: Key) -> Result<Secret, Self::Error> {
137 match key {
138 Key::Secret(secret) => Ok(secret),
139 _ => Err(Error::SecretPublicKey),
140 }
141 }
142}
143
144#[cfg(test)]
145mod test {
146 use super::*;
147
148 fn round_trip(key: &Key) {
149 let serialized = toml::to_string(&key).unwrap();
150 println!("{serialized}");
151 let deserialized: Key = toml::from_str(&serialized).unwrap();
152 assert_eq!(key, &deserialized);
153 }
154
155 #[test]
156 fn public_key() {
157 let key = Key::PublicKey(Public(stellar_strkey::ed25519::PublicKey([0; 32])));
158 round_trip(&key);
159 }
160 #[test]
161 fn muxed_key() {
162 let key: stellar_strkey::ed25519::MuxedAccount =
163 "MA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAAAAAAAAAPCICBKU"
164 .parse()
165 .unwrap();
166 let key = Key::MuxedAccount(MuxedAccount(key));
167 round_trip(&key);
168 }
169 #[test]
170 fn secret_key() {
171 let secret_key = stellar_strkey::ed25519::PrivateKey([0; 32]).to_string();
172 let secret = Secret::SecretKey { secret_key };
173 let key = Key::Secret(secret);
174 round_trip(&key);
175 }
176 #[test]
177 fn secret_seed_phrase() {
178 let seed_phrase = "singer swing mango apple singer swing mango apple singer swing mango apple singer swing mango apple".to_string();
179 let secret = Secret::SeedPhrase { seed_phrase };
180 let key = Key::Secret(secret);
181 round_trip(&key);
182 }
183}