stellar_base/operations/
allow_trust.rs1use crate::account::TrustLineFlags;
2use crate::asset::{xdr_code_to_string, CreditAssetType};
3use crate::crypto::{MuxedAccount, PublicKey};
4use crate::error::{Error, Result};
5use crate::operations::Operation;
6use crate::xdr;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct AllowTrustOperation {
10 source_account: Option<MuxedAccount>,
11 trustor: PublicKey,
12 asset: CreditAssetType,
13 authorize: TrustLineFlags,
14}
15
16#[derive(Debug, Default)]
17pub struct AllowTrustOperationBuilder {
18 source_account: Option<MuxedAccount>,
19 trustor: Option<PublicKey>,
20 asset: Option<CreditAssetType>,
21 authorize: Option<TrustLineFlags>,
22}
23
24impl AllowTrustOperation {
25 pub fn source_account(&self) -> &Option<MuxedAccount> {
27 &self.source_account
28 }
29
30 pub fn source_account_mut(&mut self) -> &mut Option<MuxedAccount> {
32 &mut self.source_account
33 }
34
35 pub fn trustor(&self) -> &PublicKey {
37 &self.trustor
38 }
39
40 pub fn trustor_mut(&mut self) -> &mut PublicKey {
42 &mut self.trustor
43 }
44
45 pub fn asset(&self) -> &CreditAssetType {
47 &self.asset
48 }
49
50 pub fn asset_mut(&mut self) -> &mut CreditAssetType {
52 &mut self.asset
53 }
54
55 pub fn authorize_flags(&self) -> &TrustLineFlags {
57 &self.authorize
58 }
59
60 pub fn authorize_flags_mut(&mut self) -> &mut TrustLineFlags {
62 &mut self.authorize
63 }
64
65 pub fn to_xdr_operation_body(&self) -> Result<xdr::OperationBody> {
67 let trustor = self.trustor.to_xdr_account_id()?;
68 let asset = match &self.asset {
69 CreditAssetType::CreditAlphaNum4(code) => {
70 let asset_code = xdr::AssetCode4::try_from(code.as_bytes())
71 .map_err(|_| Error::InvalidAssetCode)?;
72 xdr::AssetCode::CreditAlphanum4(asset_code)
73 }
74 CreditAssetType::CreditAlphaNum12(code) => {
75 let asset_code = xdr::AssetCode12::try_from(code.as_bytes())
76 .map_err(|_| Error::InvalidAssetCode)?;
77 xdr::AssetCode::CreditAlphanum12(asset_code)
78 }
79 };
80 let authorize = self.authorize.bits() as u32;
81
82 let inner = xdr::AllowTrustOp {
83 trustor,
84 asset,
85 authorize,
86 };
87 Ok(xdr::OperationBody::AllowTrust(inner))
88 }
89
90 pub fn from_xdr_operation_body(
92 source_account: Option<MuxedAccount>,
93 x: &xdr::AllowTrustOp,
94 ) -> Result<AllowTrustOperation> {
95 let trustor = PublicKey::from_xdr_account_id(&x.trustor)?;
96 let asset = match &x.asset {
97 xdr::AssetCode::CreditAlphanum4(code) => {
98 let code = xdr_code_to_string(&code.0);
99 CreditAssetType::CreditAlphaNum4(code)
100 }
101 xdr::AssetCode::CreditAlphanum12(code) => {
102 let code = xdr_code_to_string(&code.0);
103 CreditAssetType::CreditAlphaNum12(code)
104 }
105 };
106 let authorize =
107 TrustLineFlags::from_bits(x.authorize).ok_or(Error::InvalidTrustLineFlags)?;
108
109 Ok(AllowTrustOperation {
110 source_account,
111 trustor,
112 asset,
113 authorize,
114 })
115 }
116}
117
118impl AllowTrustOperationBuilder {
119 pub fn new() -> AllowTrustOperationBuilder {
120 Default::default()
121 }
122
123 pub fn with_source_account<S>(mut self, source: S) -> AllowTrustOperationBuilder
124 where
125 S: Into<MuxedAccount>,
126 {
127 self.source_account = Some(source.into());
128 self
129 }
130
131 pub fn with_trustor(mut self, trustor: PublicKey) -> AllowTrustOperationBuilder {
132 self.trustor = Some(trustor);
133 self
134 }
135
136 pub fn with_asset(mut self, asset: CreditAssetType) -> AllowTrustOperationBuilder {
137 self.asset = Some(asset);
138 self
139 }
140
141 pub fn with_authorize_flags(mut self, authorize: TrustLineFlags) -> AllowTrustOperationBuilder {
142 self.authorize = Some(authorize);
143 self
144 }
145
146 pub fn build(self) -> Result<Operation> {
147 let trustor = self
148 .trustor
149 .ok_or_else(|| Error::InvalidOperation("missing allow trust trustor".to_string()))?;
150
151 let asset = self
152 .asset
153 .ok_or_else(|| Error::InvalidOperation("missing allow trust asset".to_string()))?;
154
155 let authorize = self.authorize.ok_or_else(|| {
156 Error::InvalidOperation("missing allow trust authorize flags".to_string())
157 })?;
158
159 Ok(Operation::AllowTrust(AllowTrustOperation {
160 source_account: self.source_account,
161 trustor,
162 asset,
163 authorize,
164 }))
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use crate::account::TrustLineFlags;
171 use crate::asset::CreditAssetType;
172
173 use crate::network::Network;
174 use crate::operations::tests::*;
175 use crate::operations::Operation;
176 use crate::transaction::{Transaction, TransactionEnvelope, MIN_BASE_FEE};
177 use crate::xdr::{XDRDeserialize, XDRSerialize};
178
179 #[test]
180 fn test_allow_trust() {
181 let kp = keypair0();
182 let kp1 = keypair1();
183
184 let op = Operation::new_allow_trust()
185 .with_trustor(kp1.public_key())
186 .with_asset(CreditAssetType::CreditAlphaNum4("ABCD".to_string()))
187 .with_authorize_flags(TrustLineFlags::AUTHORIZED)
188 .build()
189 .unwrap();
190
191 let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
192 .add_operation(op)
193 .into_transaction()
194 .unwrap();
195 tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
196 let envelope = tx.to_envelope();
197 let xdr = envelope.xdr_base64().unwrap();
198 let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAHAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAAUFCQ0QAAAABAAAAAAAAAAHqLnLFAAAAQNhV5kJkZryrHEq8jgx9O76dchfHSkS99FTAcR6D2cjSoy6dbPuGsiPpTbwbMMV+lYTigEmv5vTVV+rWcLfr0Q0=";
199 assert_eq!(expected, xdr);
200 let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
201 assert_eq!(envelope, back);
202 }
203
204 #[test]
205 fn test_allow_trust_with_source_account() {
206 let kp = keypair0();
207 let kp1 = keypair1();
208 let kp2 = keypair2();
209
210 let op = Operation::new_allow_trust()
211 .with_source_account(kp2.public_key())
212 .with_trustor(kp1.public_key())
213 .with_asset(CreditAssetType::CreditAlphaNum4("ABCD".to_string()))
214 .with_authorize_flags(TrustLineFlags::AUTHORIZED)
215 .build()
216 .unwrap();
217 let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
218 .add_operation(op)
219 .into_transaction()
220 .unwrap();
221 tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
222 let envelope = tx.to_envelope();
223 let xdr = envelope.xdr_base64().unwrap();
224 let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAEAAAAAfhHLNNY19eGrAtSgLD3VpaRm2AjNjxIBWQg9zS4VWZgAAAAHAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAAUFCQ0QAAAABAAAAAAAAAAHqLnLFAAAAQOGeHFq7smaQekF9Cu+duxVIGbMiGvT5CccilyMmB7WELOn85XuYIY6qfDKCnjgH47ga1Yve8qnA5hdD2A+iAgA=";
225 assert_eq!(expected, xdr);
226 let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
227 assert_eq!(envelope, back);
228 }
229}