1use core::{cmp::Ordering, convert::Infallible, fmt::Debug};
2
3use super::{
4 env::internal::{AddressObject, Env as _, MuxedAddressObject, Tag},
5 ConversionError, Env, TryFromVal, TryIntoVal, Val,
6};
7use crate::{env::internal, unwrap::UnwrapInfallible, Address};
8
9#[cfg(not(target_family = "wasm"))]
10use crate::env::internal::xdr::{ScAddress, ScVal};
11
12#[derive(Clone)]
13enum AddressObjectWrapper {
14 Address(AddressObject),
15 MuxedAddress(MuxedAddressObject),
16}
17
18#[derive(Clone)]
43pub struct MuxedAddress {
44 env: Env,
45 obj: AddressObjectWrapper,
46}
47
48impl Debug for MuxedAddress {
49 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
50 #[cfg(target_family = "wasm")]
51 match &self.obj {
52 AddressObjectWrapper::Address(_) => write!(f, "Address(..)"),
53 AddressObjectWrapper::MuxedAddress(_) => write!(f, "MuxedAddress(..)"),
54 }
55 #[cfg(not(target_family = "wasm"))]
56 {
57 use crate::env::internal::xdr;
58 use stellar_strkey::Strkey;
59 match &self.obj {
60 AddressObjectWrapper::Address(address_object) => {
61 Address::try_from_val(self.env(), address_object)
62 .map_err(|_| core::fmt::Error)?
63 .fmt(f)
64 }
65 AddressObjectWrapper::MuxedAddress(muxed_address_object) => {
66 let sc_val = ScVal::try_from_val(self.env(), &muxed_address_object.to_val())
67 .map_err(|_| core::fmt::Error)?;
68 if let ScVal::Address(addr) = sc_val {
69 match addr {
70 xdr::ScAddress::MuxedAccount(muxed_account) => {
71 let strkey = Strkey::MuxedAccountEd25519(
72 stellar_strkey::ed25519::MuxedAccount {
73 ed25519: muxed_account.ed25519.0,
74 id: muxed_account.id,
75 },
76 );
77 write!(f, "MuxedAccount({})", strkey.to_string())
78 }
79 _ => Err(core::fmt::Error),
80 }
81 } else {
82 Err(core::fmt::Error)
83 }
84 }
85 }
86 }
87 }
88}
89
90impl Eq for MuxedAddress {}
91
92impl PartialEq for MuxedAddress {
93 fn eq(&self, other: &Self) -> bool {
94 self.partial_cmp(other) == Some(Ordering::Equal)
95 }
96}
97
98impl PartialOrd for MuxedAddress {
99 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
100 Some(Ord::cmp(self, other))
101 }
102}
103
104impl Ord for MuxedAddress {
105 fn cmp(&self, other: &Self) -> Ordering {
106 let v = self
107 .env
108 .obj_cmp(self.to_val(), other.to_val())
109 .unwrap_infallible();
110 v.cmp(&0)
111 }
112}
113
114impl TryFromVal<Env, MuxedAddressObject> for MuxedAddress {
115 type Error = Infallible;
116
117 fn try_from_val(env: &Env, val: &MuxedAddressObject) -> Result<Self, Self::Error> {
118 Ok(unsafe { MuxedAddress::unchecked_new(env.clone(), *val) })
119 }
120}
121
122impl TryFromVal<Env, AddressObject> for MuxedAddress {
123 type Error = Infallible;
124
125 fn try_from_val(env: &Env, val: &AddressObject) -> Result<Self, Self::Error> {
126 Ok(unsafe { MuxedAddress::unchecked_new_from_address(env.clone(), *val) })
127 }
128}
129
130impl TryFromVal<Env, Val> for MuxedAddress {
131 type Error = ConversionError;
132
133 fn try_from_val(env: &Env, val: &Val) -> Result<Self, Self::Error> {
134 if val.get_tag() == Tag::AddressObject {
135 Ok(AddressObject::try_from_val(env, val)?
136 .try_into_val(env)
137 .unwrap_infallible())
138 } else {
139 Ok(MuxedAddressObject::try_from_val(env, val)?
140 .try_into_val(env)
141 .unwrap_infallible())
142 }
143 }
144}
145
146impl TryFromVal<Env, MuxedAddress> for Val {
147 type Error = ConversionError;
148
149 fn try_from_val(_env: &Env, v: &MuxedAddress) -> Result<Self, Self::Error> {
150 Ok(v.to_val())
151 }
152}
153
154impl TryFromVal<Env, &MuxedAddress> for Val {
155 type Error = ConversionError;
156
157 fn try_from_val(_env: &Env, v: &&MuxedAddress) -> Result<Self, Self::Error> {
158 Ok(v.to_val())
159 }
160}
161
162impl From<&MuxedAddress> for MuxedAddress {
163 fn from(address: &MuxedAddress) -> Self {
164 address.clone()
165 }
166}
167
168impl From<Address> for MuxedAddress {
169 fn from(address: Address) -> Self {
170 (&address).into()
171 }
172}
173
174impl From<&Address> for MuxedAddress {
175 fn from(address: &Address) -> Self {
176 address
177 .as_object()
178 .try_into_val(address.env())
179 .unwrap_infallible()
180 }
181}
182
183impl MuxedAddress {
184 pub fn address(&self) -> Address {
189 match &self.obj {
190 AddressObjectWrapper::Address(address_object) => {
191 Address::try_from_val(&self.env, address_object).unwrap_infallible()
192 }
193 AddressObjectWrapper::MuxedAddress(muxed_address_object) => Address::try_from_val(
194 &self.env,
195 &internal::Env::get_address_from_muxed_address(&self.env, *muxed_address_object)
196 .unwrap_infallible(),
197 )
198 .unwrap_infallible(),
199 }
200 }
201
202 pub fn id(&self) -> Option<u64> {
210 match &self.obj {
211 AddressObjectWrapper::Address(_) => None,
212 AddressObjectWrapper::MuxedAddress(muxed_address_object) => Some(
213 u64::try_from_val(
214 &self.env,
215 &internal::Env::get_id_from_muxed_address(&self.env, *muxed_address_object)
216 .unwrap_infallible(),
217 )
218 .unwrap(),
219 ),
220 }
221 }
222
223 #[inline(always)]
224 pub(crate) unsafe fn unchecked_new_from_address(env: Env, obj: AddressObject) -> Self {
225 Self {
226 env,
227 obj: AddressObjectWrapper::Address(obj),
228 }
229 }
230
231 #[inline(always)]
232 pub(crate) unsafe fn unchecked_new(env: Env, obj: MuxedAddressObject) -> Self {
233 Self {
234 env,
235 obj: AddressObjectWrapper::MuxedAddress(obj),
236 }
237 }
238
239 #[inline(always)]
240 pub fn env(&self) -> &Env {
241 &self.env
242 }
243
244 pub fn as_val(&self) -> &Val {
245 match &self.obj {
246 AddressObjectWrapper::Address(o) => o.as_val(),
247 AddressObjectWrapper::MuxedAddress(o) => o.as_val(),
248 }
249 }
250
251 pub fn to_val(&self) -> Val {
252 match self.obj {
253 AddressObjectWrapper::Address(o) => o.to_val(),
254 AddressObjectWrapper::MuxedAddress(o) => o.to_val(),
255 }
256 }
257}
258
259#[cfg(not(target_family = "wasm"))]
260impl TryFromVal<Env, ScVal> for MuxedAddress {
261 type Error = ConversionError;
262 fn try_from_val(env: &Env, val: &ScVal) -> Result<Self, Self::Error> {
263 let v = Val::try_from_val(env, val)?;
264 match val {
265 ScVal::Address(sc_address) => match sc_address {
266 ScAddress::Account(_) | ScAddress::Contract(_) => {
267 Ok(AddressObject::try_from_val(env, &v)?
268 .try_into_val(env)
269 .unwrap_infallible())
270 }
271 ScAddress::MuxedAccount(_) => Ok(MuxedAddressObject::try_from_val(env, &v)?
272 .try_into_val(env)
273 .unwrap_infallible()),
274 ScAddress::ClaimableBalance(_) | ScAddress::LiquidityPool(_) => {
275 panic!("unsupported ScAddress type")
276 }
277 },
278 _ => panic!("incorrect scval type"),
279 }
280 }
281}
282
283#[cfg(not(target_family = "wasm"))]
284impl TryFromVal<Env, ScAddress> for MuxedAddress {
285 type Error = ConversionError;
286 fn try_from_val(env: &Env, val: &ScAddress) -> Result<Self, Self::Error> {
287 ScVal::Address(val.clone()).try_into_val(env)
288 }
289}
290
291#[cfg(any(test, feature = "testutils"))]
292#[cfg_attr(feature = "docs", doc(cfg(feature = "testutils")))]
293impl crate::testutils::MuxedAddress for MuxedAddress {
294 fn generate(env: &Env) -> crate::MuxedAddress {
295 let sc_val = ScVal::Address(crate::env::internal::xdr::ScAddress::MuxedAccount(
296 crate::env::internal::xdr::MuxedEd25519Account {
297 ed25519: crate::env::internal::xdr::Uint256(
298 env.with_generator(|mut g| g.address()),
299 ),
300 id: env.with_generator(|mut g| g.mux_id()),
301 },
302 ));
303 sc_val.try_into_val(env).unwrap()
304 }
305
306 fn new<T: Into<MuxedAddress>>(address: T, id: u64) -> crate::MuxedAddress {
307 let address: MuxedAddress = address.into();
308 let sc_val = ScVal::try_from_val(&address.env, address.as_val()).unwrap();
309 let account_id = match sc_val {
310 ScVal::Address(address) => match address {
311 ScAddress::MuxedAccount(muxed_account) => muxed_account.ed25519,
312 ScAddress::Account(crate::env::internal::xdr::AccountId(
313 crate::env::internal::xdr::PublicKey::PublicKeyTypeEd25519(account_id),
314 )) => account_id,
315 ScAddress::Contract(_) => panic!("contract addresses can not be multiplexed"),
316 ScAddress::ClaimableBalance(_) | ScAddress::LiquidityPool(_) => unreachable!(),
317 },
318 _ => unreachable!(),
319 };
320 let result_sc_val = ScVal::Address(ScAddress::MuxedAccount(
321 crate::env::internal::xdr::MuxedEd25519Account {
322 id,
323 ed25519: account_id,
324 },
325 ));
326 result_sc_val.try_into_val(&address.env).unwrap()
327 }
328}