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); 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 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); 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 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}