1#![cfg(feature = "alloc")]
32
33use super::{
34 AccountId, AssetCode, AssetCode12, AssetCode4, ClaimableBalanceId, ContractId, Error, Hash,
35 Int128Parts, Int256Parts, MuxedAccount, MuxedAccountMed25519, MuxedEd25519Account, NodeId,
36 PoolId, PublicKey, ScAddress, SignerKey, SignerKeyEd25519SignedPayload, UInt128Parts,
37 UInt256Parts, Uint256,
38};
39use crate::num128::{
40 i128_str_from_pieces, i128_str_into_pieces, u128_str_from_pieces, u128_str_into_pieces,
41};
42use crate::num256::{
43 i256_str_from_pieces, i256_str_into_pieces, u256_str_from_pieces, u256_str_into_pieces,
44};
45
46impl From<stellar_strkey::DecodeError> for Error {
47 fn from(_: stellar_strkey::DecodeError) -> Self {
48 Error::Invalid
49 }
50}
51
52impl core::fmt::Display for PublicKey {
53 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54 match self {
55 PublicKey::PublicKeyTypeEd25519(Uint256(k)) => {
56 let k = stellar_strkey::ed25519::PublicKey::from_payload(k)
57 .map_err(|_| core::fmt::Error)?;
58 let s = k.to_string();
59 f.write_str(&s)?;
60 }
61 }
62 Ok(())
63 }
64}
65
66impl core::str::FromStr for PublicKey {
67 type Err = Error;
68 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
69 let stellar_strkey::ed25519::PublicKey(k) =
70 stellar_strkey::ed25519::PublicKey::from_str(s)?;
71 Ok(PublicKey::PublicKeyTypeEd25519(Uint256(k)))
72 }
73}
74
75impl core::fmt::Display for AccountId {
76 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77 self.0.fmt(f)
78 }
79}
80
81impl core::str::FromStr for AccountId {
82 type Err = Error;
83 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
84 Ok(AccountId(PublicKey::from_str(s)?))
85 }
86}
87
88impl core::fmt::Display for ContractId {
89 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
90 let k = stellar_strkey::Contract(self.0 .0);
91 let s = k.to_string();
92 f.write_str(&s)?;
93 Ok(())
94 }
95}
96
97impl core::str::FromStr for ContractId {
98 type Err = Error;
99 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
100 let stellar_strkey::Contract(h) = stellar_strkey::Contract::from_str(s)?;
101 Ok(ContractId(Hash(h)))
102 }
103}
104
105impl core::fmt::Display for PoolId {
106 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107 let PoolId(Hash(p_id)) = self.clone();
108 let key = stellar_strkey::Strkey::LiquidityPool(stellar_strkey::LiquidityPool(p_id));
109 key.fmt(f)
110 }
111}
112
113impl core::str::FromStr for PoolId {
114 type Err = Error;
115 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
116 let pool_key = stellar_strkey::LiquidityPool::from_str(s)?;
117 Ok(PoolId(Hash(pool_key.0)))
118 }
119}
120
121impl core::fmt::Display for MuxedAccountMed25519 {
122 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123 let MuxedAccountMed25519 {
124 ed25519: Uint256(ed25519),
125 id,
126 } = self;
127 let k = stellar_strkey::ed25519::MuxedAccount {
128 ed25519: *ed25519,
129 id: *id,
130 };
131 let s = k.to_string();
132 f.write_str(&s)?;
133 Ok(())
134 }
135}
136
137impl core::str::FromStr for MuxedAccountMed25519 {
138 type Err = Error;
139 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
140 let stellar_strkey::ed25519::MuxedAccount { ed25519, id } =
141 stellar_strkey::ed25519::MuxedAccount::from_str(s)?;
142 Ok(MuxedAccountMed25519 {
143 ed25519: Uint256(ed25519),
144 id,
145 })
146 }
147}
148
149impl core::str::FromStr for MuxedAccount {
150 type Err = Error;
151 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
152 let strkey = stellar_strkey::Strkey::from_str(s)?;
153 match strkey {
154 stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => {
155 Ok(MuxedAccount::Ed25519(Uint256(k)))
156 }
157 stellar_strkey::Strkey::MuxedAccountEd25519(
158 stellar_strkey::ed25519::MuxedAccount { ed25519, id },
159 ) => Ok(MuxedAccount::MuxedEd25519(MuxedAccountMed25519 {
160 ed25519: Uint256(ed25519),
161 id,
162 })),
163 stellar_strkey::Strkey::PreAuthTx(_)
164 | stellar_strkey::Strkey::HashX(_)
165 | stellar_strkey::Strkey::SignedPayloadEd25519(_)
166 | stellar_strkey::Strkey::Contract(_)
167 | stellar_strkey::Strkey::LiquidityPool(_)
168 | stellar_strkey::Strkey::ClaimableBalance(_)
169 | stellar_strkey::Strkey::MuxedContract(_) => Err(Error::Invalid),
170 }
171 }
172}
173
174impl core::fmt::Display for MuxedAccount {
175 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
176 match self {
177 MuxedAccount::Ed25519(Uint256(k)) => {
178 let k = stellar_strkey::ed25519::PublicKey(*k);
179 let s = k.to_string();
180 f.write_str(&s)?;
181 }
182 MuxedAccount::MuxedEd25519(m) => m.fmt(f)?,
183 }
184 Ok(())
185 }
186}
187
188impl core::fmt::Display for NodeId {
189 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
190 self.0.fmt(f)
191 }
192}
193
194impl core::str::FromStr for NodeId {
195 type Err = Error;
196 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
197 Ok(NodeId(PublicKey::from_str(s)?))
198 }
199}
200
201impl core::fmt::Display for SignerKeyEd25519SignedPayload {
208 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
209 let SignerKeyEd25519SignedPayload {
210 ed25519: Uint256(ed25519),
211 payload,
212 } = self;
213 let Ok(k) = stellar_strkey::ed25519::SignedPayload::new(*ed25519, payload.as_ref()) else {
216 let g = stellar_strkey::ed25519::PublicKey(*ed25519);
217 return write!(f, "<INVALID:{g}:EMPTY_PAYLOAD>");
218 };
219 let s = k.to_string();
220 f.write_str(&s)?;
221 Ok(())
222 }
223}
224
225impl core::str::FromStr for SignerKeyEd25519SignedPayload {
226 type Err = Error;
227 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
228 let sp = stellar_strkey::ed25519::SignedPayload::from_str(s)?;
229 Ok(SignerKeyEd25519SignedPayload {
230 ed25519: Uint256(*sp.ed25519()),
231 payload: sp.payload().try_into()?,
232 })
233 }
234}
235
236impl core::str::FromStr for SignerKey {
237 type Err = Error;
238 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
239 let strkey = stellar_strkey::Strkey::from_str(s)?;
240 match strkey {
241 stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => {
242 Ok(SignerKey::Ed25519(Uint256(k)))
243 }
244 stellar_strkey::Strkey::PreAuthTx(stellar_strkey::PreAuthTx(h)) => {
245 Ok(SignerKey::PreAuthTx(Uint256(h)))
246 }
247 stellar_strkey::Strkey::HashX(stellar_strkey::HashX(h)) => {
248 Ok(SignerKey::HashX(Uint256(h)))
249 }
250 stellar_strkey::Strkey::SignedPayloadEd25519(sp) => Ok(
251 SignerKey::Ed25519SignedPayload(SignerKeyEd25519SignedPayload {
252 ed25519: Uint256(*sp.ed25519()),
253 payload: sp.payload().try_into()?,
254 }),
255 ),
256 stellar_strkey::Strkey::Contract(_)
257 | stellar_strkey::Strkey::MuxedAccountEd25519(_)
258 | stellar_strkey::Strkey::LiquidityPool(_)
259 | stellar_strkey::Strkey::ClaimableBalance(_)
260 | stellar_strkey::Strkey::MuxedContract(_) => Err(Error::Invalid),
261 }
262 }
263}
264
265impl core::fmt::Display for SignerKey {
271 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
272 match self {
273 SignerKey::Ed25519(Uint256(k)) => {
274 let k = stellar_strkey::ed25519::PublicKey(*k);
275 let s = k.to_string();
276 f.write_str(&s)?;
277 }
278 SignerKey::PreAuthTx(Uint256(h)) => {
279 let k = stellar_strkey::PreAuthTx(*h);
280 let s = k.to_string();
281 f.write_str(&s)?;
282 }
283 SignerKey::HashX(Uint256(h)) => {
284 let k = stellar_strkey::HashX(*h);
285 let s = k.to_string();
286 f.write_str(&s)?;
287 }
288 SignerKey::Ed25519SignedPayload(p) => p.fmt(f)?,
289 }
290 Ok(())
291 }
292}
293
294impl core::str::FromStr for MuxedEd25519Account {
295 type Err = Error;
296 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
297 let strkey = stellar_strkey::Strkey::from_str(s)?;
298 match strkey {
299 stellar_strkey::Strkey::MuxedAccountEd25519(muxed_ed25519) => Ok(MuxedEd25519Account {
300 id: muxed_ed25519.id,
301 ed25519: Uint256(muxed_ed25519.ed25519),
302 }),
303 _ => Err(Error::Invalid),
304 }
305 }
306}
307
308impl core::fmt::Display for MuxedEd25519Account {
309 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
310 let k =
311 stellar_strkey::Strkey::MuxedAccountEd25519(stellar_strkey::ed25519::MuxedAccount {
312 ed25519: self.ed25519.0,
313 id: self.id,
314 });
315 let s = k.to_string();
316 f.write_str(&s)
317 }
318}
319
320impl core::str::FromStr for crate::MuxedContract {
321 type Err = Error;
322 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
323 let strkey = stellar_strkey::Strkey::from_str(s)?;
324 match strkey {
325 stellar_strkey::Strkey::MuxedContract(muxed_contract) => Ok(crate::MuxedContract {
326 id: muxed_contract.id,
327 contract_id: ContractId(Hash(muxed_contract.contract_id)),
328 }),
329 _ => Err(Error::Invalid),
330 }
331 }
332}
333
334impl core::fmt::Display for crate::MuxedContract {
335 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
336 let k = stellar_strkey::MuxedContract {
337 contract_id: self.contract_id.0 .0,
338 id: self.id,
339 };
340 let s = k.to_string();
341 f.write_str(&s)
342 }
343}
344
345impl core::str::FromStr for ScAddress {
346 type Err = Error;
347 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
348 let strkey = stellar_strkey::Strkey::from_str(s)?;
349 match strkey {
350 stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => Ok(
351 ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(k)))),
352 ),
353 stellar_strkey::Strkey::Contract(stellar_strkey::Contract(h)) => {
354 Ok(ScAddress::Contract(ContractId(Hash(h))))
355 }
356 stellar_strkey::Strkey::MuxedAccountEd25519(muxed_ed25519) => {
357 Ok(ScAddress::MuxedAccount(MuxedEd25519Account {
358 id: muxed_ed25519.id,
359 ed25519: Uint256(muxed_ed25519.ed25519),
360 }))
361 }
362 stellar_strkey::Strkey::LiquidityPool(liquidity_pool) => {
363 Ok(ScAddress::LiquidityPool(PoolId(Hash(liquidity_pool.0))))
364 }
365 stellar_strkey::Strkey::ClaimableBalance(stellar_strkey::ClaimableBalance::V0(
366 claimable_balance,
367 )) => Ok(ScAddress::ClaimableBalance(
368 ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(claimable_balance)),
369 )),
370 stellar_strkey::Strkey::MuxedContract(stellar_strkey::MuxedContract {
371 contract_id,
372 id,
373 }) => Ok(ScAddress::MuxedContract(crate::MuxedContract {
374 id,
375 contract_id: ContractId(Hash(contract_id)),
376 })),
377 stellar_strkey::Strkey::PreAuthTx(_)
378 | stellar_strkey::Strkey::HashX(_)
379 | stellar_strkey::Strkey::SignedPayloadEd25519(_) => Err(Error::Invalid),
380 }
381 }
382}
383
384impl core::fmt::Display for ScAddress {
385 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
386 match self {
387 ScAddress::Account(a) => a.fmt(f),
388 ScAddress::Contract(ContractId(Hash(h))) => {
389 let k = stellar_strkey::Contract(*h);
390 let s = k.to_string();
391 f.write_str(&s)
392 }
393 ScAddress::MuxedAccount(muxed_ed25519_account) => {
394 let k = stellar_strkey::Strkey::MuxedAccountEd25519(
395 stellar_strkey::ed25519::MuxedAccount {
396 ed25519: muxed_ed25519_account.ed25519.0,
397 id: muxed_ed25519_account.id,
398 },
399 );
400 let s = k.to_string();
401 f.write_str(&s)
402 }
403 ScAddress::ClaimableBalance(claimable_balance_id) => claimable_balance_id.fmt(f),
404 ScAddress::LiquidityPool(pool_id) => pool_id.fmt(f),
405 ScAddress::MuxedContract(muxed_contract) => muxed_contract.fmt(f),
406 }
407 }
408}
409
410impl core::str::FromStr for AssetCode4 {
411 type Err = Error;
412 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
413 let mut code = AssetCode4([0u8; 4]);
414 escape_bytes::unescape_into(&mut code.0, s.as_bytes()).map_err(|_| Error::Invalid)?;
415 Ok(code)
416 }
417}
418
419impl core::fmt::Display for AssetCode4 {
420 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
421 if let Some(last_idx) = self.0.iter().rposition(|c| *c != 0) {
422 for b in escape_bytes::Escape::new(&self.0[..=last_idx]) {
423 write!(f, "{}", b as char)?;
424 }
425 }
426 Ok(())
427 }
428}
429
430impl core::str::FromStr for AssetCode12 {
431 type Err = Error;
432 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
437 const MIN_LENGTH: usize = 5;
442 let mut code = AssetCode12([0u8; 12]);
443 let n =
444 escape_bytes::unescape_into(&mut code.0, s.as_bytes()).map_err(|_| Error::Invalid)?;
445 if n < MIN_LENGTH {
446 return Err(Error::Invalid);
447 }
448 Ok(code)
449 }
450}
451
452impl core::fmt::Display for AssetCode12 {
453 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
454 const MIN_LENGTH: usize = 5;
460 let len = MIN_LENGTH
461 + self
462 .0
463 .iter()
464 .skip(MIN_LENGTH)
465 .rposition(|c| *c != 0)
466 .map_or(0, |last_idx| last_idx + 1);
467 for b in escape_bytes::Escape::new(&self.0[..len]) {
468 write!(f, "{}", b as char)?;
469 }
470 Ok(())
471 }
472}
473
474impl core::str::FromStr for AssetCode {
475 type Err = Error;
476 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
477 let mut code = [0u8; 12];
478 let n = escape_bytes::unescape_into(&mut code, s.as_bytes()).map_err(|_| Error::Invalid)?;
479 if n <= 4 {
480 Ok(AssetCode::CreditAlphanum4(AssetCode4([
481 code[0], code[1], code[2], code[3],
482 ])))
483 } else if n <= 12 {
484 Ok(AssetCode::CreditAlphanum12(AssetCode12(code)))
485 } else {
486 Err(Error::Invalid)
487 }
488 }
489}
490
491impl core::fmt::Display for AssetCode {
492 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
493 match self {
494 AssetCode::CreditAlphanum4(c) => c.fmt(f),
495 AssetCode::CreditAlphanum12(c) => c.fmt(f),
496 }
497 }
498}
499
500impl core::str::FromStr for ClaimableBalanceId {
501 type Err = Error;
502 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
503 let stellar_strkey::ClaimableBalance::V0(cb_id) =
504 stellar_strkey::ClaimableBalance::from_str(s)?;
505 Ok(ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(cb_id)))
506 }
507}
508
509impl core::fmt::Display for ClaimableBalanceId {
510 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
511 let ClaimableBalanceId::ClaimableBalanceIdTypeV0(Hash(cb_id)) = self.clone();
512 let key =
513 stellar_strkey::Strkey::ClaimableBalance(stellar_strkey::ClaimableBalance::V0(cb_id));
514 key.fmt(f)
515 }
516}
517
518impl core::fmt::Display for UInt128Parts {
519 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
520 let v = u128_str_from_pieces(self.hi, self.lo);
521 write!(f, "{v}")
522 }
523}
524
525impl core::str::FromStr for UInt128Parts {
526 type Err = Error;
527 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
528 let (hi, lo) = u128_str_into_pieces(s).map_err(|_| Error::Invalid)?;
529 Ok(Self { hi, lo })
530 }
531}
532
533impl core::fmt::Display for Int128Parts {
534 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
535 let v = i128_str_from_pieces(self.hi, self.lo);
536 write!(f, "{v}")
537 }
538}
539
540impl core::str::FromStr for Int128Parts {
541 type Err = Error;
542 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
543 let (hi, lo) = i128_str_into_pieces(s).map_err(|_| Error::Invalid)?;
544 Ok(Self { hi, lo })
545 }
546}
547
548impl core::fmt::Display for UInt256Parts {
549 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
550 let u256 = u256_str_from_pieces(self.hi_hi, self.hi_lo, self.lo_hi, self.lo_lo);
551 write!(f, "{u256}")
552 }
553}
554
555impl core::str::FromStr for UInt256Parts {
556 type Err = Error;
557 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
558 let (hi_hi, hi_lo, lo_hi, lo_lo) = u256_str_into_pieces(s).map_err(|_| Error::Invalid)?;
559 Ok(Self {
560 hi_hi,
561 hi_lo,
562 lo_hi,
563 lo_lo,
564 })
565 }
566}
567
568impl core::fmt::Display for Int256Parts {
569 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
570 let i256 = i256_str_from_pieces(self.hi_hi, self.hi_lo, self.lo_hi, self.lo_lo);
571 write!(f, "{i256}")
572 }
573}
574
575impl core::str::FromStr for Int256Parts {
576 type Err = Error;
577 fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
578 let (hi_hi, hi_lo, lo_hi, lo_lo) = i256_str_into_pieces(s).map_err(|_| Error::Invalid)?;
579 Ok(Self {
580 hi_hi,
581 hi_lo,
582 lo_hi,
583 lo_lo,
584 })
585 }
586}