Skip to main content

stellar_baselib/
muxed_account.rs

1use crate::xdr;
2use crate::{
3    account::{Account, AccountBehavior},
4    utils::decode_encode_muxed_account::{
5        decode_address_to_muxed_account, encode_muxed_account, encode_muxed_account_to_address,
6        extract_base_address,
7    },
8};
9use std::{cell::RefCell, rc::Rc};
10use stellar_strkey::ed25519::PublicKey;
11
12pub struct MuxedAccount {
13    account: Rc<RefCell<Account>>,
14    muxed_xdr: xdr::MuxedAccount,
15    m_address: String,
16    id: String,
17}
18
19pub trait MuxedAccountBehavior {
20    fn new(
21        base_account: Rc<RefCell<Account>>,
22        id: &str,
23    ) -> Result<Self, Box<dyn std::error::Error>>
24    where
25        Self: Sized;
26    fn from_address(
27        m_address: &str,
28        sequence_num: &str,
29    ) -> Result<Self, Box<dyn std::error::Error>>
30    where
31        Self: Sized;
32    fn set_id(&mut self, id: &str) -> Result<(), Box<dyn std::error::Error>>;
33    fn base_account(&self) -> Rc<RefCell<Account>>;
34    fn account_id(&self) -> &str;
35    fn id(&self) -> &str;
36    fn sequence_number(&self) -> String;
37    fn increment_sequence_number(&mut self);
38    fn to_xdr_object(&self) -> &xdr::MuxedAccount;
39    fn equals(&self, other_muxed_account: &MuxedAccount) -> bool;
40}
41
42impl MuxedAccountBehavior for MuxedAccount {
43    fn new(
44        base_account: Rc<RefCell<Account>>,
45        id: &str,
46    ) -> Result<Self, Box<dyn std::error::Error>> {
47        let account_id = base_account.borrow().account_id().to_owned();
48
49        let key = PublicKey::from_string(&account_id);
50
51        if key.is_err() {
52            return Err("accountId is invalid".into());
53        }
54
55        let muxed_xdr = encode_muxed_account(&account_id, id);
56        let m_address = encode_muxed_account_to_address(&muxed_xdr);
57
58        Ok(Self {
59            account: base_account,
60            id: id.to_string(),
61            muxed_xdr,
62            m_address,
63        })
64    }
65
66    fn from_address(
67        m_address: &str,
68        sequence_num: &str,
69    ) -> Result<Self, Box<dyn std::error::Error>> {
70        let muxed_account = decode_address_to_muxed_account(m_address);
71        let g_address = extract_base_address(m_address)?;
72        let id = muxed_account.id;
73        let mut account = Account::new(&g_address, sequence_num).unwrap();
74        let account_rc = Rc::new(RefCell::new(account));
75
76        let muxed_xdr = encode_muxed_account(&g_address, &id.to_string());
77        let m_address = encode_muxed_account_to_address(&muxed_xdr);
78        Ok(Self {
79            account: account_rc,
80            id: id.to_string(),
81            muxed_xdr,
82            m_address,
83        })
84    }
85
86    fn set_id(&mut self, id: &str) -> Result<(), Box<dyn std::error::Error>> {
87        if !id.chars().all(|c| c.is_ascii_digit()) {
88            return Err("id should be a string representing a number (uint64)".into());
89        }
90
91        let val = match &self.muxed_xdr {
92            xdr::MuxedAccount::MuxedEd25519(x) => x,
93            _ => return Err("Bad XDR".into()),
94        };
95
96        let muxed_xdr = xdr::MuxedAccount::MuxedEd25519(xdr::MuxedAccountMed25519 {
97            id: id.parse::<u64>().unwrap(),
98            ed25519: val.ed25519.clone(),
99        });
100        self.muxed_xdr = muxed_xdr;
101
102        self.m_address = encode_muxed_account_to_address(&self.muxed_xdr); // Replace with your actual encoding function
103        self.id = id.to_string();
104
105        Ok(())
106    }
107
108    fn base_account(&self) -> Rc<RefCell<Account>> {
109        self.account.clone()
110    }
111
112    fn account_id(&self) -> &str {
113        &self.m_address
114    }
115
116    fn id(&self) -> &str {
117        &self.id
118    }
119
120    fn sequence_number(&self) -> String {
121        self.account.borrow().sequence_number()
122    }
123
124    fn increment_sequence_number(&mut self) {
125        self.account.borrow_mut().increment_sequence_number();
126    }
127
128    fn to_xdr_object(&self) -> &xdr::MuxedAccount {
129        &self.muxed_xdr
130    }
131
132    fn equals(&self, other_muxed_account: &MuxedAccount) -> bool {
133        self.account.borrow().account_id() == other_muxed_account.account.borrow().account_id()
134    }
135}
136
137#[cfg(test)]
138mod tests {
139
140    use super::*;
141    use crate::{
142        keypair::Keypair,
143        utils::decode_encode_muxed_account::{
144            decode_address_to_muxed_account, encode_muxed_account, encode_muxed_account_to_address,
145            extract_base_address,
146        },
147    };
148    use stellar_strkey::{ed25519, Strkey};
149
150    #[test]
151    fn test_generate_addresses() {
152        let pubkey = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ";
153        let mpubkey_zero = "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ";
154        let mpubkey_id = "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAABUTGI4";
155
156        let mut base_account = Account::new(pubkey, "1").unwrap();
157        let base_account_rc = Rc::new(RefCell::new(base_account));
158
159        let mut mux =
160            MuxedAccount::new(base_account_rc.clone(), "0").expect("Error creating MuxedAccount");
161
162        assert_eq!(mux.base_account().borrow().account_id(), pubkey);
163        assert_eq!(
164            mux.account_id(),
165            "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ"
166        );
167        assert_eq!(mux.id(), "0");
168
169        mux.set_id("420").expect("Error setting MuxedAccount ID");
170        assert_eq!(mux.id(), "420");
171        assert_eq!(mux.account_id(), mpubkey_id);
172
173        let mux_xdr = mux.to_xdr_object().discriminant();
174        assert_eq!(mux_xdr, xdr::CryptoKeyType::MuxedEd25519);
175
176        let mux_xdr = mux.to_xdr_object();
177
178        let inner_mux = match mux_xdr {
179            xdr::MuxedAccount::MuxedEd25519(x) => x,
180            _ => panic!("Bad XDR"),
181        };
182
183        // mux.account.
184        let key = PublicKey::from_string(pubkey);
185
186        let vv = key.clone().unwrap().0;
187
188        assert_eq!(inner_mux.ed25519, xdr::Uint256::from(vv));
189
190        assert_eq!(
191            inner_mux.id,
192            xdr::Uint64::from("420".parse::<u64>().unwrap())
193        );
194
195        let encoded_address = encode_muxed_account_to_address(mux_xdr); // Implement this function
196        assert_eq!(encoded_address, mux.account_id());
197    }
198
199    #[test]
200    fn test_sequence_numbers() {
201        let pubkey = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ";
202        let base_account = Account::new(pubkey, "12345").unwrap();
203        let base_account_rc = Rc::new(RefCell::new(base_account));
204
205        let mut mux1 = MuxedAccount::new(base_account_rc.clone(), "1").unwrap();
206        let mut mux2 = MuxedAccount::new(base_account_rc.clone(), "2").unwrap();
207
208        assert_eq!(base_account_rc.borrow().sequence_number(), "12345");
209        assert_eq!(mux1.sequence_number(), "12345");
210        assert_eq!(mux2.sequence_number(), "12345");
211
212        mux1.increment_sequence_number();
213
214        // println!("Checking value {:?}",base_account.sequence_number());
215        assert_eq!(base_account_rc.borrow().sequence_number(), "12346");
216        assert_eq!(mux1.sequence_number(), "12346");
217        assert_eq!(mux2.sequence_number(), "12346");
218
219        mux2.increment_sequence_number();
220
221        assert_eq!(base_account_rc.borrow().sequence_number(), "12347");
222        assert_eq!(mux1.sequence_number(), "12347");
223        assert_eq!(mux2.sequence_number(), "12347");
224
225        base_account_rc.borrow_mut().increment_sequence_number();
226
227        assert_eq!(base_account_rc.borrow().sequence_number(), "12348");
228        assert_eq!(mux1.sequence_number(), "12348");
229        assert_eq!(mux2.sequence_number(), "12348");
230    }
231
232    #[test]
233    fn test_virtual_accounts_creation() {
234        let pubkey = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ";
235        let mpubkey_zero = "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ";
236        let mpubkey_id = "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAABUTGI4";
237
238        let base_account = Account::new(pubkey, "12345").unwrap();
239        let base_account_rc = Rc::new(RefCell::new(base_account));
240
241        let mux1 = MuxedAccount::new(base_account_rc.clone(), "1").unwrap();
242
243        let base_account_mux1 = mux1.base_account();
244        let mut mux2 = MuxedAccount::new(base_account_mux1.clone(), "420").unwrap();
245
246        assert_eq!(mux2.id(), "420");
247        assert_eq!(mux2.account_id(), mpubkey_id);
248        assert_eq!(mux2.sequence_number(), "12345");
249
250        let base_account_mux2 = mux2.base_account();
251        let mux3 = MuxedAccount::new(base_account_mux2.clone(), "3").unwrap();
252
253        mux2.increment_sequence_number();
254
255        assert_eq!(mux1.sequence_number(), "12346");
256        assert_eq!(mux2.sequence_number(), "12346");
257        assert_eq!(mux3.sequence_number(), "12346");
258    }
259
260    #[test]
261    fn test_parse_m_addresses() {
262        let pubkey = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ";
263        let mpubkey_zero = "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ";
264        let mpubkey_id = "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAABUTGI4";
265        let mux1 = MuxedAccount::from_address(mpubkey_zero, "123").unwrap();
266
267        assert_eq!(mux1.id(), "0");
268        assert_eq!(mux1.account_id(), mpubkey_zero);
269        assert_eq!(mux1.base_account().borrow().account_id(), pubkey);
270        assert_eq!(mux1.sequence_number(), "123");
271    }
272}