substrate_stellar_sdk/xdr/impls/
muxed_account.rs

1use sp_std::vec::Vec;
2
3use crate::{
4    types::{MuxedAccount, MuxedAccountMed25519, Uint64},
5    utils::key_encoding::{
6        decode_stellar_key, encode_stellar_key, ED25519_PUBLIC_KEY_VERSION_BYTE, MED25519_PUBLIC_KEY_BYTE_LENGTH,
7        MED25519_PUBLIC_KEY_VERSION_BYTE,
8    },
9    AccountId, IntoAccountId, PublicKey, StellarSdkError, XdrCodec,
10};
11
12use core::convert::{AsRef, TryInto};
13
14impl MuxedAccount {
15    pub fn from_account_id<T: IntoAccountId>(account_id: T) -> Result<Self, StellarSdkError> {
16        account_id.into_account_id().map(|account_id| {
17            let account_id = match account_id {
18                PublicKey::PublicKeyTypeEd25519(account_id) => account_id,
19            };
20            MuxedAccount::KeyTypeEd25519(account_id)
21        })
22    }
23
24    pub fn from_muxed_account_id<T: IntoAccountId>(
25        account_id: T,
26        sub_account_id: u64,
27    ) -> Result<Self, StellarSdkError> {
28        account_id.into_account_id().map(|account_id| {
29            let account_id = match account_id {
30                PublicKey::PublicKeyTypeEd25519(account_id) => account_id,
31            };
32            MuxedAccount::KeyTypeMuxedEd25519(MuxedAccountMed25519 { id: sub_account_id, ed25519: account_id })
33        })
34    }
35
36    pub fn from_encoding<T: AsRef<[u8]>>(encoded_key: T) -> Result<Self, StellarSdkError> {
37        let encoded_key = encoded_key.as_ref();
38
39        match decode_stellar_key::<_, MED25519_PUBLIC_KEY_BYTE_LENGTH>(encoded_key, MED25519_PUBLIC_KEY_VERSION_BYTE) {
40            Ok(raw_bytes) => Ok(MuxedAccount::KeyTypeMuxedEd25519(MuxedAccountMed25519 {
41                id: Uint64::from_xdr(&raw_bytes[MED25519_PUBLIC_KEY_BYTE_LENGTH - 8..]).unwrap(),
42                ed25519: raw_bytes[..MED25519_PUBLIC_KEY_BYTE_LENGTH - 8].try_into().unwrap(),
43            })),
44            Err(_) => PublicKey::from_encoding(encoded_key)
45                .map(|public_key| MuxedAccount::KeyTypeEd25519(public_key.into_binary())),
46        }
47    }
48
49    /// Return the key encoding as an ASCII string (given as `Vec<u8>`)
50    pub fn to_encoding(&self) -> Vec<u8> {
51        match self {
52            MuxedAccount::KeyTypeEd25519(raw_bytes) => encode_stellar_key(raw_bytes, ED25519_PUBLIC_KEY_VERSION_BYTE),
53            MuxedAccount::KeyTypeMuxedEd25519(MuxedAccountMed25519 { id, ed25519 }) => {
54                let mut raw_bytes = [0u8; MED25519_PUBLIC_KEY_BYTE_LENGTH];
55                raw_bytes[..MED25519_PUBLIC_KEY_BYTE_LENGTH - 8].copy_from_slice(ed25519);
56                raw_bytes[MED25519_PUBLIC_KEY_BYTE_LENGTH - 8..].copy_from_slice(id.to_xdr().as_slice());
57                encode_stellar_key(&raw_bytes, MED25519_PUBLIC_KEY_VERSION_BYTE)
58            },
59            _ => unreachable!("Invalid muxed account type"),
60        }
61    }
62}
63
64// This can be both an account id or a muxed account id.
65// For that reason it would be better to call it AsPossiblyMuxedAccountId
66// but Stellar just calls this a MuxedAccount, too.
67pub trait IntoMuxedAccountId {
68    fn into_muxed_account_id(self) -> Result<MuxedAccount, StellarSdkError>;
69}
70
71impl IntoMuxedAccountId for AccountId {
72    fn into_muxed_account_id(self) -> Result<MuxedAccount, StellarSdkError> {
73        Ok(MuxedAccount::KeyTypeEd25519(self.into_binary()))
74    }
75}
76
77impl IntoMuxedAccountId for MuxedAccount {
78    fn into_muxed_account_id(self) -> Result<MuxedAccount, StellarSdkError> {
79        Ok(self)
80    }
81}
82
83impl<T: AsRef<[u8]>> IntoMuxedAccountId for T {
84    fn into_muxed_account_id(self) -> Result<MuxedAccount, StellarSdkError> {
85        MuxedAccount::from_encoding(self)
86    }
87}