From abfbd7d2f79ee37a4bacb643717f307999414312 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Tue, 24 Oct 2023 14:44:07 -0700 Subject: [PATCH] Add strkey str conversions for ScAddress --- Makefile | 2 +- src/curr/generated.rs | 3 +- src/curr/str.rs | 38 ++++++++++++++++++++++-- tests/str.rs | 68 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 104 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 2f32508a..c0bb103d 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CARGO_HACK_ARGS=--feature-powerset --exclude-features default --group-features b CARGO_DOC_ARGS?=--open XDRGEN_VERSION=64612a24 -XDRGEN_TYPES_CUSTOM_STR_IMPL=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId +XDRGEN_TYPES_CUSTOM_STR_IMPL=PublicKey,AccountId,MuxedAccount,MuxedAccountMed25519,SignerKey,SignerKeyEd25519SignedPayload,NodeId,ScAddress all: build test diff --git a/src/curr/generated.rs b/src/curr/generated.rs index 13915e95..1870b4bd 100644 --- a/src/curr/generated.rs +++ b/src/curr/generated.rs @@ -8004,8 +8004,7 @@ impl WriteXdr for ScAddressType { #[cfg_attr(feature = "arbitrary", derive(Arbitrary))] #[cfg_attr( all(feature = "serde", feature = "alloc"), - derive(serde::Serialize, serde::Deserialize), - serde(rename_all = "snake_case") + derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr) )] #[allow(clippy::large_enum_variant)] pub enum ScAddress { diff --git a/src/curr/str.rs b/src/curr/str.rs index 55c4a5be..5333323e 100644 --- a/src/curr/str.rs +++ b/src/curr/str.rs @@ -16,8 +16,8 @@ #![cfg(feature = "std")] use super::{ - AccountId, Error, MuxedAccount, MuxedAccountMed25519, NodeId, PublicKey, SignerKey, - SignerKeyEd25519SignedPayload, Uint256, + AccountId, Error, Hash, MuxedAccount, MuxedAccountMed25519, NodeId, PublicKey, ScAddress, + SignerKey, SignerKeyEd25519SignedPayload, Uint256, }; impl From for Error { @@ -220,3 +220,37 @@ impl core::fmt::Display for SignerKey { Ok(()) } } + +impl core::str::FromStr for ScAddress { + type Err = Error; + fn from_str(s: &str) -> core::result::Result { + let strkey = stellar_strkey::Strkey::from_str(s)?; + match strkey { + stellar_strkey::Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(k)) => Ok( + ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256(k)))), + ), + stellar_strkey::Strkey::Contract(stellar_strkey::Contract(h)) => { + Ok(ScAddress::Contract(Hash(h))) + } + stellar_strkey::Strkey::MuxedAccountEd25519(_) + | stellar_strkey::Strkey::PrivateKeyEd25519(_) + | stellar_strkey::Strkey::PreAuthTx(_) + | stellar_strkey::Strkey::HashX(_) + | stellar_strkey::Strkey::SignedPayloadEd25519(_) => Err(Error::Invalid), + } + } +} + +impl core::fmt::Display for ScAddress { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ScAddress::Account(a) => a.fmt(f)?, + ScAddress::Contract(Hash(h)) => { + let k = stellar_strkey::Contract(*h); + let s = k.to_string(); + f.write_str(&s)?; + } + } + Ok(()) + } +} diff --git a/tests/str.rs b/tests/str.rs index d23efd92..57e129f8 100644 --- a/tests/str.rs +++ b/tests/str.rs @@ -4,8 +4,8 @@ use stellar_xdr::curr as stellar_xdr; use stellar_xdr::{ - AccountId, MuxedAccount, MuxedAccountMed25519, NodeId, PublicKey, SignerKey, - SignerKeyEd25519SignedPayload, Uint256, + AccountId, Error, Hash, MuxedAccount, MuxedAccountMed25519, NodeId, PublicKey, ScAddress, + SignerKey, SignerKeyEd25519SignedPayload, Uint256, }; use std::str::FromStr; @@ -334,3 +334,67 @@ fn signer_key_from_str_with_signed_payload_ed25519() { )), ); } + +#[test] +fn sc_address_to_string_with_account() { + let s = ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519(Uint256([ + 0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99, 0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, + 0x51, 0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2, 0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, + 0xe8, 0x9a, + ])))) + .to_string(); + assert_eq!( + s, + "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ" + ); +} + +#[test] +fn sc_address_from_str_with_account() { + let v = ScAddress::from_str("GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"); + assert_eq!( + v, + Ok(ScAddress::Account(AccountId( + PublicKey::PublicKeyTypeEd25519(Uint256([ + 0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99, 0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, + 0x05, 0x51, 0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2, 0xfb, 0x0d, 0x7a, 0x03, + 0xfc, 0x7f, 0xe8, 0x9a, + ])) + ))), + ); +} + +#[test] +fn sc_address_to_string_with_contract() { + let s = ScAddress::Contract(Hash([ + 0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99, 0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, + 0x51, 0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2, 0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, + 0xe8, 0x9a, + ])) + .to_string(); + assert_eq!( + s, + "CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA" + ); +} + +#[test] +fn sc_address_from_str_with_contract() { + let v = ScAddress::from_str("CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA"); + assert_eq!( + v, + Ok(ScAddress::Contract(Hash([ + 0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99, 0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, + 0x05, 0x51, 0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2, 0xfb, 0x0d, 0x7a, 0x03, + 0xfc, 0x7f, 0xe8, 0x9a, + ]))), + ); +} + +#[test] +fn sc_address_from_str_with_invalid() { + let v = ScAddress::from_str( + "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAAAJLK", + ); + assert_eq!(v, Err(Error::Invalid)); +}