switchboard_common/
function_result.rs

1use crate::*;
2use base64::{engine::general_purpose::STANDARD as b64, Engine as _};
3use hex::FromHex;
4use serde::{Deserialize, Serialize};
5use sha3::{Digest, Keccak256};
6use std::str::FromStr;
7
8////////////////////////////////////////////////////////////////////////////
9/// EVM
10////////////////////////////////////////////////////////////////////////////
11
12/// Represents an Ethereum Virtual Machine (EVM) transaction.
13#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
14pub struct EvmTransaction {
15    /// The expiration time of the transaction in seconds.
16    pub expiration_time_seconds: u64,
17    /// The maximum amount of gas that can be used for the transaction.
18    pub gas_limit: String,
19    /// The value of the transaction in wei.
20    pub value: String,
21    /// The address of the recipient of the transaction.
22    pub to: Vec<u8>,
23    /// The address of the sender of the transaction.
24    pub from: Vec<u8>,
25    /// The data payload of the transaction.
26    pub data: Vec<u8>,
27}
28
29#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
30pub struct EvmFunctionResultV0 {
31    // NOTE: tx.len() == signatures.len() must be true
32    pub txs: Vec<EvmTransaction>,
33    pub signatures: Vec<Vec<u8>>,
34
35    // NOTE: call_ids.len() == checksums.len() must be true - must also be mapped to txs
36    // these params should be default if not used (i.e. empty)
37    pub call_ids: Vec<Vec<u8>>,
38    pub checksums: Vec<Vec<u8>>,
39}
40
41#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
42pub struct EvmFunctionResultV1 {
43    // id of the executed function
44    pub function_id: String,
45
46    // delegated signer address of the executed function
47    pub signer: String,
48
49    pub txs: Vec<EvmTransaction>,
50
51    pub signatures: Vec<String>,
52
53    // -- ids resolved by the function output --
54    pub resolved_ids: Vec<String>,
55
56    // -- checksums of the params used in the function call --
57    pub checksums: Vec<String>,
58
59    // -- error codes assigned to each request id --
60    pub error_codes: Vec<u8>,
61}
62
63impl EvmFunctionResultV1 {
64    /// Appends all fields of the structure to a Vec<u8> and hashes it using Keccak256.
65    pub fn hash(&self) -> Vec<u8> {
66        let mut buffer = Vec::new();
67
68        buffer.extend(self.function_id.as_bytes());
69
70        buffer.extend(self.signer.as_bytes());
71
72        for tx in &self.txs {
73            buffer.extend(&tx.expiration_time_seconds.to_le_bytes());
74            buffer.extend(tx.gas_limit.as_bytes());
75            buffer.extend(tx.value.as_bytes());
76            buffer.extend(&tx.to);
77            buffer.extend(&tx.from);
78            buffer.extend(&tx.data);
79        }
80
81        for signature in &self.signatures {
82            buffer.extend(signature.as_bytes());
83        }
84
85        for resolved_id in &self.resolved_ids {
86            buffer.extend(resolved_id.as_bytes());
87        }
88
89        for checksum in &self.checksums {
90            buffer.extend(checksum.as_bytes());
91        }
92
93        buffer.extend(&self.error_codes);
94
95        let mut hasher = Keccak256::new();
96        hasher.update(buffer);
97        hasher.finalize().to_vec()
98    }
99}
100
101/// Enum representing the result of an EVM function call.
102#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
103#[serde(tag = "version")]
104pub enum EvmFunctionResult {
105    V0(EvmFunctionResultV0),
106    V1(EvmFunctionResultV1),
107}
108impl Default for EvmFunctionResult {
109    fn default() -> Self {
110        Self::V0(EvmFunctionResultV0::default())
111    }
112}
113#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
114pub struct LegacyEvmFunctionResult {
115    // NOTE: tx.len() == signatures.len() must be true
116    pub txs: Vec<EvmTransaction>,
117    pub signatures: Vec<Vec<u8>>,
118
119    // NOTE: call_ids.len() == checksums.len() must be true - must also be mapped to txs
120    // these params should be default if not used (i.e. empty)
121    pub call_ids: Vec<Vec<u8>>,
122    pub checksums: Vec<Vec<u8>>,
123}
124impl From<LegacyEvmFunctionResult> for EvmFunctionResult {
125    fn from(item: LegacyEvmFunctionResult) -> EvmFunctionResult {
126        EvmFunctionResult::V0(EvmFunctionResultV0 {
127            txs: item.txs,
128            signatures: item.signatures,
129            call_ids: item.call_ids,
130            checksums: item.checksums,
131        })
132    }
133}
134////////////////////////////////////////////////////////////////////////////
135/// Solana
136////////////////////////////////////////////////////////////////////////////
137
138/// Represents the result of a Solana function call.
139// @TODO: This should be a Solana transaction, not a serialized transaction.
140#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
141pub struct SolanaFunctionResultV0 {
142    /// The serialized, partially-signed transaction.
143    pub serialized_tx: Vec<u8>,
144}
145
146#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
147pub enum SolanaFunctionRequestType {
148    Routine(Vec<u8>),
149    Request(Vec<u8>),
150    // keep at the end so we can deprecate
151    Function(Vec<u8>),
152}
153impl Default for SolanaFunctionRequestType {
154    fn default() -> Self {
155        Self::Function(vec![])
156    }
157}
158impl SolanaFunctionRequestType {
159    pub fn is_routine(&self) -> bool {
160        matches!(self, SolanaFunctionRequestType::Routine(_))
161    }
162
163    pub fn is_request(&self) -> bool {
164        matches!(self, SolanaFunctionRequestType::Request(_))
165    }
166}
167
168/// Represents the result of a Solana function call.
169#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
170pub struct SolanaFunctionResultV1 {
171    pub fn_key: Vec<u8>,
172    /// The serialized, partially-signed transaction.
173    pub serialized_tx: Vec<u8>,
174    /// The request pubkey
175    pub request_type: SolanaFunctionRequestType,
176    /// A sha-256 hash of the parameters used in the request call.
177    pub request_hash: Vec<u8>,
178}
179
180#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
181#[serde(tag = "version")]
182pub enum SolanaFunctionResult {
183    V0(SolanaFunctionResultV0),
184    V1(SolanaFunctionResultV1),
185}
186impl Default for SolanaFunctionResult {
187    fn default() -> Self {
188        Self::V1(SolanaFunctionResultV1::default())
189    }
190}
191impl SolanaFunctionResult {
192    pub fn serialized_tx(&self) -> Vec<u8> {
193        match self {
194            SolanaFunctionResult::V0(SolanaFunctionResultV0 { serialized_tx }) => {
195                serialized_tx.clone()
196            }
197            SolanaFunctionResult::V1(SolanaFunctionResultV1 { serialized_tx, .. }) => {
198                serialized_tx.clone()
199            }
200        }
201    }
202}
203
204////////////////////////////////////////////////////////////////////////////
205/// Starknet Result Info
206////////////////////////////////////////////////////////////////////////////
207
208#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
209pub enum StarknetFunctionRequestType {
210    Routine(Vec<u8>),
211    Request(Vec<u8>),
212}
213impl Default for StarknetFunctionRequestType {
214    fn default() -> Self {
215        Self::Routine(vec![])
216    }
217}
218impl StarknetFunctionRequestType {
219    pub fn is_routine(&self) -> bool {
220        matches!(self, StarknetFunctionRequestType::Routine(_))
221    }
222
223    pub fn is_request(&self) -> bool {
224        matches!(self, StarknetFunctionRequestType::Request(_))
225    }
226}
227
228#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
229pub struct StarknetCall {
230    pub to: Vec<u8>,
231    pub selector: Vec<u8>,
232    pub calldata: Vec<Vec<u8>>,
233}
234
235#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
236pub struct StarknetFunctionResultV0 {
237    pub function_id: Vec<u8>,
238    pub function_request_id: Vec<u8>,
239    pub txs: Vec<StarknetCall>,
240    pub request_type: StarknetFunctionRequestType,
241}
242
243#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
244#[serde(tag = "version")]
245pub enum StarknetFunctionResult {
246    V0(StarknetFunctionResultV0),
247}
248impl Default for StarknetFunctionResult {
249    fn default() -> Self {
250        Self::V0(StarknetFunctionResultV0::default())
251    }
252}
253
254////////////////////////////////////////////////////////////////////////////
255/// Function result info
256////////////////////////////////////////////////////////////////////////////
257
258#[derive(Default, PartialEq, Clone, Debug, Serialize, Deserialize)]
259#[serde(tag = "chain")]
260pub enum ChainResultInfo {
261    #[default]
262    None,
263    Solana(SolanaFunctionResult),
264    Evm(EvmFunctionResult),
265    Starknet(StarknetFunctionResult),
266}
267
268/// The schema of the output data that will be sent to the quote verification sidecar.
269#[derive(Clone, PartialEq, Default, Debug, Serialize, Deserialize)]
270pub struct FunctionResultV0 {
271    /// Buffer containing the quote signing the output
272    pub quote: Vec<u8>,
273    /// key of the executed function
274    pub fn_key: Vec<u8>,
275    /// The oracle's signer used to sign off on the execution
276    pub signer: Vec<u8>,
277    /// If the call was a funciton request, the address of the request account.
278    pub fn_request_key: Vec<u8>,
279    /// A sha-256 hash of the parameters used in this request call.
280    pub fn_request_hash: Vec<u8>,
281    /// Chain specific info
282    pub chain_result_info: ChainResultInfo,
283    /// On function failure, users should emit with error code to avoid
284    /// aggressive backoffs
285    #[serde(default)]
286    pub error_code: u8,
287}
288
289/// The schema of the output data that will be sent to the quote verification sidecar.
290#[derive(Clone, PartialEq, Default, Debug, Serialize, Deserialize)]
291pub struct FunctionResultV1 {
292    /// Buffer containing the quote signing the output
293    pub quote: Vec<u8>,
294    /// The enclave generated signer's pubkey. This is used to verify the quote
295    pub signer: Vec<u8>,
296    /// The signature of the chain_result_info signed by the enclave generated signer.
297    pub signature: Vec<u8>,
298    /// Chain specific info
299    pub chain_result_info: ChainResultInfo,
300    /// On function failure, users should emit with error code to avoid aggressive backoffs
301    #[serde(default)]
302    pub error_code: u8,
303}
304
305#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
306#[serde(tag = "version")]
307pub enum FunctionResult {
308    V0(FunctionResultV0),
309    V1(FunctionResultV1),
310}
311impl Default for FunctionResult {
312    fn default() -> Self {
313        Self::V1(FunctionResultV1::default())
314    }
315}
316
317pub static FUNCTION_RESULT_PREFIX: &str = "FN_OUT: ";
318
319impl FunctionResult {
320    pub fn is_solana(&self) -> bool {
321        match self {
322            FunctionResult::V0(FunctionResultV0 {
323                chain_result_info, ..
324            }) => matches!(chain_result_info, ChainResultInfo::Solana(_)),
325            FunctionResult::V1(FunctionResultV1 {
326                chain_result_info, ..
327            }) => matches!(chain_result_info, ChainResultInfo::Solana(_)),
328        }
329    }
330
331    pub fn is_evm(&self) -> bool {
332        match self {
333            FunctionResult::V0(FunctionResultV0 {
334                chain_result_info, ..
335            }) => matches!(chain_result_info, ChainResultInfo::Evm(_)),
336            FunctionResult::V1(FunctionResultV1 {
337                chain_result_info, ..
338            }) => matches!(chain_result_info, ChainResultInfo::Evm(_)),
339        }
340    }
341
342    pub fn is_starknet(&self) -> bool {
343        match self {
344            FunctionResult::V0(FunctionResultV0 {
345                chain_result_info, ..
346            }) => matches!(chain_result_info, ChainResultInfo::Starknet(_)),
347            FunctionResult::V1(FunctionResultV1 {
348                chain_result_info, ..
349            }) => matches!(chain_result_info, ChainResultInfo::Starknet(_)),
350        }
351    }
352
353    pub fn error_code(&self) -> u8 {
354        match self {
355            FunctionResult::V0(FunctionResultV0 { error_code, .. }) => *error_code,
356            FunctionResult::V1(FunctionResultV1 { error_code, .. }) => *error_code,
357        }
358    }
359
360    pub fn set_error_code(&mut self, error_code: u8) {
361        match self {
362            FunctionResult::V0(v) => {
363                v.error_code = error_code;
364            }
365            FunctionResult::V1(v) => {
366                v.error_code = error_code;
367            }
368        }
369    }
370
371    pub fn is_err(&self) -> bool {
372        self.error_code() != 0
373    }
374
375    pub fn version(&self) -> u32 {
376        match self {
377            FunctionResult::V0(_) => 0,
378            FunctionResult::V1(_) => 1,
379        }
380    }
381
382    pub fn fn_key(&self) -> Result<Vec<u8>, SbError> {
383        let fn_key = match self {
384            FunctionResult::V0(FunctionResultV0 { fn_key, .. }) => fn_key.clone(),
385            FunctionResult::V1(FunctionResultV1 {
386                chain_result_info, ..
387            }) => match chain_result_info {
388                ChainResultInfo::Solana(sol) => match sol {
389                    SolanaFunctionResult::V0(_) => vec![],
390                    SolanaFunctionResult::V1(v) => v.fn_key.clone(),
391                },
392                ChainResultInfo::Evm(evm) => match evm {
393                    EvmFunctionResult::V0(_v) => vec![],
394                    EvmFunctionResult::V1(v) => v.function_id.as_str().as_bytes().to_vec(),
395                },
396                ChainResultInfo::Starknet(starknet) => match starknet {
397                    StarknetFunctionResult::V0(v) => v.function_id.clone(),
398                },
399                _ => vec![],
400            },
401        };
402
403        if fn_key.is_empty() {
404            Err("Failed to get fn_key from FunctionResult".into())
405        } else {
406            Ok(fn_key)
407        }
408    }
409
410    pub fn chain_result_info(&self) -> Result<ChainResultInfo, SbError> {
411        let chain_result_info = match self {
412            FunctionResult::V0(v) => v.chain_result_info.clone(),
413            FunctionResult::V1(v) => v.chain_result_info.clone(),
414        };
415
416        Ok(chain_result_info)
417    }
418
419    pub fn quote_bytes(&self) -> &[u8] {
420        match self {
421            FunctionResult::V0(FunctionResultV0 { quote, .. }) => quote,
422            FunctionResult::V1(FunctionResultV1 { quote, .. }) => quote,
423        }
424    }
425
426    cfg_client! {
427        pub fn quote(&self) -> Result<sgx_quote::Quote, SbError> {
428            sgx_quote::Quote::parse(&self.quote_bytes()).map_err(|_| SbError::QuoteParseError)
429        }
430    }
431
432    pub fn signer(&self) -> &[u8] {
433        match self {
434            FunctionResult::V0(FunctionResultV0 { signer, .. }) => signer,
435            FunctionResult::V1(FunctionResultV1 { signer, .. }) => signer,
436        }
437    }
438
439    pub fn to_string(&self) -> Result<String, SbError> {
440        serde_json::to_string(&self).map_err(|e| SbError::CustomError {
441            message: "Failed to convert FunctionResult to string".to_string(),
442            source: std::sync::Arc::new(e),
443        })
444    }
445
446    pub fn hex_encode(&self) -> String {
447        hex::encode(self.to_string().unwrap_or_default())
448    }
449
450    pub fn emit_hex(&self) {
451        println!(
452            "{}{}",
453            FUNCTION_RESULT_PREFIX,
454            hex::encode(self.to_string().unwrap())
455        );
456    }
457
458    pub fn emit_base64(&self) {
459        println!(
460            "{}{}",
461            FUNCTION_RESULT_PREFIX,
462            b64.encode(self.to_string().unwrap().as_bytes())
463        );
464    }
465
466    pub fn emit(&self) {
467        self.emit_hex()
468    }
469
470    pub fn decode(s: &str) -> std::result::Result<Self, SbError> {
471        Self::from_str(s)
472    }
473}
474impl From<LegacyFunctionResult> for FunctionResult {
475    fn from(item: LegacyFunctionResult) -> FunctionResult {
476        FunctionResult::V0(FunctionResultV0 {
477            quote: item.quote,
478            fn_key: item.fn_key,
479            signer: item.signer,
480            fn_request_key: item.fn_request_key,
481            fn_request_hash: item.fn_request_hash,
482            chain_result_info: item.chain_result_info.into(),
483            error_code: item.error_code,
484        })
485    }
486}
487impl FromHex for FunctionResult {
488    type Error = SbError;
489
490    // Does not account for FN_OUT prefix
491    fn from_hex<T: AsRef<[u8]>>(hex: T) -> std::result::Result<Self, Self::Error> {
492        let bytes = hex::decode(hex)?;
493
494        bytes.try_into()
495    }
496}
497impl FromStr for FunctionResult {
498    type Err = SbError;
499
500    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
501        // Strip the FN_OUT prefix if its in the string
502        let s = s.strip_prefix(FUNCTION_RESULT_PREFIX).unwrap_or(s);
503
504        // Try to hex decode the string, fallback to utf-8
505        let bytes = match hex::decode(s) {
506            Ok(b) => b,
507            // TODO: handle base64 decoding
508            Err(_) => s.as_bytes().to_vec(),
509        };
510
511        bytes.try_into()
512    }
513}
514
515impl TryFrom<Vec<u8>> for FunctionResult {
516    type Error = SbError;
517
518    fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
519        // First try to deserialize into the correct type
520        let error_msg = match serde_json::from_slice::<FunctionResult>(&bytes) {
521            Ok(deserialized) => {
522                return Ok(deserialized);
523            }
524            Err(e) => {
525                format!("Failed to decode FunctionResult: {:?}", e)
526            }
527        };
528
529        // Fallback to using the LegacyFunctionResult if it cant be deserialized
530        match serde_json::from_slice::<LegacyFunctionResult>(&bytes) {
531            Ok(deserialized) => {
532                return Ok(deserialized.into());
533            }
534            Err(e) => {
535                log::info!("Failed to decode LegacyFunctionResult: {:?}", e);
536            }
537        }
538
539        println!("{}", String::from_utf8(bytes).unwrap_or_default());
540
541        Err(SbError::CustomMessage(format!(
542            "Failed to decode FunctionResult {:?}",
543            error_msg
544        )))
545    }
546}
547
548/// The schema of the output data that will be sent to the quote verification sidecar.
549/// This implementation has been deprecated in favor of `FunctionResult`.
550#[derive(Clone, PartialEq, Default, Debug, Serialize, Deserialize)]
551pub struct LegacyFunctionResult {
552    /// version of the output format
553    pub version: u32,
554    /// Buffer containing the quote signing the output
555    pub quote: Vec<u8>,
556    /// key of the executed function
557    pub fn_key: Vec<u8>,
558    /// The oracle's signer used to sign off on the execution
559    pub signer: Vec<u8>,
560    /// If the call was a funciton request, the address of the request account.
561    pub fn_request_key: Vec<u8>,
562    /// A sha-256 hash of the parameters used in this request call.
563    pub fn_request_hash: Vec<u8>,
564    /// Chain specific info
565    pub chain_result_info: LegacyChainResultInfo,
566    /// On function failure, users should emit with error code to avoid
567    /// aggressive backoffs
568    #[serde(default)]
569    pub error_code: u8,
570}
571
572#[derive(Default, PartialEq, Clone, Debug, Serialize, Deserialize)]
573pub enum LegacyChainResultInfo {
574    #[default]
575    None,
576    Solana(LegacySolanaFunctionResult),
577    Evm(LegacyEvmFunctionResult),
578}
579impl From<LegacyChainResultInfo> for ChainResultInfo {
580    fn from(item: LegacyChainResultInfo) -> ChainResultInfo {
581        match item {
582            LegacyChainResultInfo::Solana(sol) => ChainResultInfo::Solana(sol.into()),
583            LegacyChainResultInfo::Evm(evm) => ChainResultInfo::Evm(evm.into()),
584            _ => ChainResultInfo::None,
585        }
586    }
587}
588
589#[derive(Default, PartialEq, Clone, Debug, Serialize, Deserialize)]
590pub struct LegacySolanaFunctionResult {
591    pub serialized_tx: Vec<u8>,
592}
593impl From<LegacySolanaFunctionResult> for SolanaFunctionResult {
594    fn from(item: LegacySolanaFunctionResult) -> SolanaFunctionResult {
595        SolanaFunctionResult::V0(SolanaFunctionResultV0 {
596            serialized_tx: item.serialized_tx,
597        })
598    }
599}
600
601#[cfg(test)]
602mod tests {
603    use super::*;
604    use pretty_assertions::assert_eq;
605    use rand::Rng;
606
607    // FunctionResult { version: 0, quote: [], fn_key: [], signer: [], fn_request_key: [], fn_request_hash: [], chain_result_info: None, error_code: 0 }
608    pub const EMPTY_ENCODED_FN_RESULT: &str =
609        "7b2276657273696f6e223a302c2271756f7465223a5b5d2c22666e5f6b6579223a5b5d2c227369676e6572223a5b5d2c22666e5f726571756573745f6b6579223a5b5d2c22666e5f726571756573745f68617368223a5b5d2c22636861696e5f726573756c745f696e666f223a224e6f6e65222c226572726f725f636f6465223a307d";
610
611    // FunctionResult { version: 0, quote: [], fn_key: [], signer: [], fn_request_key: [], fn_request_hash: [], chain_result_info: Solana(SOLFunctionResult { serialized_tx: [1, 2, 3] }), error_code: 0 }
612    // pub const SOL_ENCODED_FN_RESULT: &str =
613    //     "7b2276657273696f6e223a302c2271756f7465223a5b5d2c22666e5f6b6579223a5b5d2c227369676e6572223a5b5d2c22666e5f726571756573745f6b6579223a5b5d2c22666e5f726571756573745f68617368223a5b5d2c22636861696e5f726573756c745f696e666f223a7b22536f6c616e61223a7b2273657269616c697a65645f7478223a5b312c322c335d7d7d2c226572726f725f636f6465223a307d";
614
615    pub const TEST_CASE_1: &str =
616        "FN_OUT: 7b2276657273696f6e223a312c2271756f7465223a5b332c302c322c302c302c302c302c302c392c302c31342c302c3134372c3135342c3131342c35312c3234372c3135362c37362c3136392c3134382c31302c31332c3137392c3134392c3132372c362c372c3138362c3131382c3133362c36392c342c3133382c3137362c35342c36362c3133372c3132392c3132342c32372c3138392c36362c3132322c302c302c302c302c31322c31322c31362c31352c3235352c3235352c312c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c352c302c302c302c302c302c302c302c3233312c302c302c302c302c302c302c302c32332c3235352c3135322c3234302c372c3134302c3232392c3130352c3133312c3138372c36322c3136302c31372c3230302c3137372c3135362c3233382c3231332c3234322c3135362c3135332c39342c352c37372c39312c3231382c3138332c3134362c3138312c3230362c3137332c3130382c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c3233312c3234312c3231392c3231342c3136322c3232352c32312c34362c3232372c3138372c3139342c37332c3233362c36332c39362c39362c3230392c3230332c3235312c33302c3231372c35332c36332c3232352c3231332c34302c37352c3133372c3137332c39302c3231362c3131332c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c3136382c3232362c39332c3137332c3230392c31302c37392c39302c34332c3138342c3230362c36342c33302c3230342c36352c3135382c3135332c33322c32322c33382c3234362c3235302c3231372c39312c36322c3133332c3136352c3132392c3233332c39332c3139362c34332c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c3230322c31362c302c302c3130382c32312c3136312c3234312c3233342c3233362c3130372c3235302c3134372c32332c3132332c3133382c3230342c3139332c3139392c3130312c3136372c3134322c3137312c3234372c3139302c3138372c3135302c322c3133302c3130332c3134392c3230332c3234312c38322c34392c392c3232362c3233392c35332c3132312c33312c37312c3233382c3232362c35332c3130362c33302c31392c3136342c32312c3132312c3230302c3137392c3138372c3137392c3130312c32342c3136342c3138342c3231342c3232352c3138392c3130342c3131352c3232392c3234352c3233342c38392c3231352c3134332c3137392c39332c3132382c39392c37382c3230382c3137382c3139362c3130382c3137352c36362c32342c3234302c3132362c3130382c3138372c382c3232332c3137372c3230362c3131322c31342c3234332c3133372c3234372c3130312c3136362c3139332c34382c36382c38352c3233352c3136322c3231342c32342c3235342c3232392c3135342c3233322c3130332c362c3234332c33312c3138322c37312c3132382c3130352c3230302c38372c3233302c3230312c3139362c35362c32302c3230322c3233362c3130322c3134332c382c3234382c39352c31352c31322c31322c31362c31352c3235352c3235352c312c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c32312c302c302c302c302c302c302c302c3233312c302c302c302c302c302c302c302c32352c34322c3136352c31322c3232352c3139322c3230362c3234302c36302c3230372c3133372c3233312c3138312c3137372c3130372c31332c3132312c3132302c3234352c3139342c3137372c3233372c3230372c3131392c37372c3133352c3131322c34362c3132392c38342c3231362c3139312c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c3134302c37392c38372c3131372c3231352c3135302c38302c36322c3135302c31392c3132372c3131392c3139382c3133382c3133302c3135342c302c38362c3137322c3134312c3233372c3131322c32302c31312c382c32372c392c36382c3134342c3139372c3132332c3235352c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c312c302c392c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c3132302c37392c36302c36382c34342c382c3230382c3135392c3230372c33372c36382c3134322c3131392c36332c3233332c3231322c35312c3232332c3235322c3231352c3135332c3139382c3138372c36392c3137342c312c3233312c3230332c3232322c3230342c3132352c3137332c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c3132342c37372c3234372c38342c39382c39322c36342c3133322c3233392c31382c3130352c3131322c32322c34302c3233382c38332c34352c34312c37332c3135302c3134392c3133312c342c37302c3135322c3136322c3232382c3138352c37332c35382c3231342c3135372c3230342c37302c3230332c3233362c33342c3233322c35332c3132392c3234342c31342c3235312c39332c3131362c3132302c39382c3232352c3232342c38372c3132362c3234352c362c34352c34362c3135352c36372c34332c34352c3139302c34392c3130382c35392c3230352c33322c302c302c312c322c332c342c352c362c372c382c392c31302c31312c31322c31332c31342c31352c31362c31372c31382c31392c32302c32312c32322c32332c32342c32352c32362c32372c32382c32392c33302c33312c352c302c39382c31342c302c302c34352c34352c34352c34352c34352c36362c36392c37312c37332c37382c33322c36372c36392c38322c38342c37332c37302c37332c36372c36352c38342c36392c34352c34352c34352c34352c34352c31302c37372c37332c37332c36392c35362c3130362c36372c36372c36362c37342c3130392c3130332c36352c3131392c37332c36362c36352c3130332c37332c38362c36352c37392c39392c36382c38302c36352c35312c3132312c3131352c3130312c38362c38332c39382c3131382c36352c37302c3130302c3131372c3132312c3131312c38352c3132302c37362c3131362c3130352c37342c34382c3130322c37372c36352c3131312c37312c36372c36372c3131332c37312c38332c37372c35322c35372c36362c36352c37372c36372c31302c37372c37322c36352c3132302c37332c3130362c36352c3130332c36362c3130332c37382c38362c36362c36352c37372c37372c37312c38352c3130382c3131372c3130302c37312c38362c3131352c37332c37302c37382c37322c38372c36372c36362c38312c38312c34382c3131352c3130332c38352c37312c3132302c3130342c3130302c37312c39302c3131382c39392c3130392c34382c3130332c38312c34382c36392c3132302c37312c3130362c36352c38392c36362c3130332c37382c38362c36362c36352c3131312c37372c31302c36392c38352c3130382c3131372c3130302c37312c38362c3131352c37332c36392c37382c3131382c39392c3131302c36362c3131382c39392c3130392c37302c34382c39372c38372c35372c3131372c37372c38322c38312c3131392c36392c3130332c38392c36382c38362c38312c38312c37322c36382c36352c3131362c38342c38392c38372c35332c34382c38392c38332c36362c36382c39382c37312c37302c3132312c38392c38342c36392c37362c37372c36352c3130372c37312c36352c34392c38352c36392c31302c36372c36352c3131392c36372c38312c34382c36392c3132302c36372c3132322c36352c37342c36362c3130332c37382c38362c36362c36352c38392c38342c36352c3130382c38362c38342c37372c36362c35322c38382c36382c38342c37332c3132322c37372c36382c3130332c3132312c37382c36382c37332c3132302c37382c38342c3130332c34392c37372c38362c3131312c38382c36382c38342c37372c3131392c37372c36382c3130332c3132312c37382c36382c37332c3132302c37382c38342c3130332c34392c31302c37372c38362c3131312c3131392c39392c36382c36392c3130352c37372c36372c36352c37312c36352c34392c38352c36392c36352c3131392c3131392c39302c38332c38372c35332c34382c39302c38372c3131392c3130332c38352c34382c3130302c38392c37332c37302c36362c36382c38332c3132312c36362c36382c39302c38382c37342c34382c39372c38372c39302c3131322c38392c35302c37302c34382c39302c38342c36392c39372c37372c36362c3130332c37312c36352c34392c38352c36392c31302c36372c3130332c3131392c38322c38332c38372c35332c34382c39302c38372c3131392c3130332c38312c35302c35372c3132312c39392c37312c35372c3132312c38392c38382c38322c3131322c39382c35302c35322c3132302c37302c36382c36352c38332c36362c3130332c37382c38362c36362c36352c39392c37372c36372c34392c37382c3130342c39382c3131302c38322c3130342c37332c36392c37382c3131352c38392c38382c37342c3130342c37372c38312c3131352c3131392c36372c38312c38392c36382c31302c38362c38312c38312c37332c36382c36352c37342c36382c38312c38342c36392c37362c37372c36352c3130372c37312c36352c34392c38352c36392c36362c3130342c37372c36372c38362c38362c37372c3131392c38372c38342c36352c38342c36362c3130332c39392c3131332c3130342c3130372c3130362c37392c38302c38312c37332c36362c36362c3130332c3130332c3131332c3130342c3130372c3130362c37392c38302c38312c37372c36362c36362c3131392c37382c36372c36352c36352c38312c37382c31302c3131392c38392c3130302c34382c39392c3130392c36382c38392c37352c38312c3131312c37322c37302c3130362c37372c35352c3132312c38342c3130332c35352c34372c3130332c35312c3132302c39382c3131342c36352c3131362c37312c3131302c35322c38312c35332c3131302c3130312c35302c3131392c38392c38342c3130312c3130302c38372c38352c38362c3131362c36382c3131362c3130382c38392c35322c37392c3131342c3131342c3130342c35372c35372c3131392c36382c3132302c37322c38332c3132302c35322c38352c31302c36372c38392c3131362c3130382c38382c34382c38392c38392c37322c3130352c37322c3131392c37302c3131372c38372c38312c34332c38392c3130392c34382c3131312c35322c37332c36382c36382c3130362c36372c36372c36352c3131392c3131312c3131392c37322c3131392c38392c36382c38362c38322c34382c3130362c36362c36362c3130332c3131392c37302c3131312c36352c38352c3130382c38372c35372c3130302c3132322c39382c34382c39382c35322c3130312c3130382c36352c38332c39392c3131302c38352c31302c35372c36382c38302c37392c36352c38362c39392c37362c35312c3130382c38312c3131392c39372c3131392c38392c36382c38362c38322c34382c3130322c36362c37312c38312c3131392c38392c3130362c36362c3130332c3131312c37302c35342c3130332c38382c37332c39302c39372c39372c37322c38322c34382c39392c37322c37372c35342c37362c3132312c35372c3130342c39392c37312c3130372c3131372c3130302c37322c37342c34392c39392c35312c38322c3130382c39302c37322c37382c3130382c31302c39392c3131302c39302c3131322c38392c35302c38362c3132322c37362c3130392c3130382c3131372c3130302c37312c38362c3131352c37362c3130392c37382c3131382c39382c38332c35372c3132322c39302c35312c3130332c3131382c38392c35302c38362c3132312c3130302c37312c3130382c3130392c39372c38372c37382c3130342c3130302c37312c3130382c3131382c39382c3130352c35372c35302c37372c3132312c35372c3131392c38392c35302c3131362c3130362c39392c3130392c3131392c34372c38392c35302c36392c35372c31302c39392c37312c3132302c3130342c3130302c37312c39302c3131382c39392c3130392c34382c3130392c39302c38372c35332c3130362c39382c35302c38322c3131322c39382c3130392c39392c35372c39302c37312c38362c3132312c37372c36362c34382c37312c36352c34392c38352c3130302c36382c3130332c38312c38372c36362c36362c38312c37372c3130322c38372c35302c38342c34332c35302c3131372c38342c34382c38312c37342c34382c38342c37312c38342c34392c35312c3132322c39302c38372c31302c3130312c3130372c35362c34382c37392c3130362c36352c37392c36362c3130332c37382c38362c37322c38312c35362c36362c36352c3130322c35362c36392c36362c36352c37372c36372c36362c3131352c36352c3131392c36382c36352c38392c36382c38362c38322c34382c38342c36352c38312c37322c34372c36362c36352c37332c3131392c36352c36382c36372c36372c36352c3130362c3131352c37312c36372c38332c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c31302c36352c38312c38332c36372c36352c3130352c3131392c3131392c3130332c3130332c37332c3131312c37372c36362c35322c37312c36372c3130352c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c36392c36392c36392c37332c3132302c3131342c37372c38362c3132322c3130312c35302c38392c36382c35352c36372c3132322c36352c34372c37362c3130352c38332c3130362c38342c39302c34382c3131392c3130332c3130332c37302c3130382c36362c3130332c3131312c3131332c31302c3130342c3130372c3130352c37312c34332c36392c34382c36362c36382c38312c36392c36372c37372c37332c37332c36362c38362c38342c36352c38312c36362c3130332c3131352c3131332c3130342c3130372c3130352c37312c34332c36392c34382c36362c36382c38312c36392c36372c36352c38312c37332c36362c36382c36382c36352c38312c36362c3130332c3131352c3131332c3130342c3130372c3130352c37312c34332c36392c34382c36362c36382c38312c36392c36372c36352c3130332c37332c36362c31302c36382c36382c36352c38312c36362c3130332c3131352c3131332c3130342c3130372c3130352c37312c34332c36392c34382c36362c36382c38312c36392c36372c36352c3131392c37332c36362c36352c3132322c36352c38312c36362c3130332c3131352c3131332c3130342c3130372c3130352c37312c34332c36392c34382c36362c36382c38312c36392c36372c36362c36352c37332c36362c36352c3132322c36352c38322c36362c3130332c3131352c3131332c3130342c3130372c3130352c37312c34332c36392c34382c36362c31302c36382c38312c36392c36372c36362c38312c37332c36372c36352c38302c35362c3131392c36392c38312c38392c37362c37352c3131312c39302c37332c3130342c3131382c3130342c37382c36352c38312c34382c36362c36352c3130332c38392c36372c36352c3130332c36382c34372c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c37322c36352c3130332c36392c36362c37372c36362c36352c37312c31302c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c37332c36352c3130332c36392c36352c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c37342c36352c3130332c36392c36352c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c37352c31302c36352c3130332c36392c36352c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c37362c36352c3130332c36392c36352c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c37372c36352c3130332c36392c36352c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c31302c38342c38312c36392c37382c36352c38312c37332c37382c36352c3130332c36392c36352c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c37392c36352c3130332c36392c36352c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c38302c36352c3130332c36392c36352c37372c36362c36352c37312c31302c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c38312c36352c3130332c36392c36352c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c38322c36352c3130332c36392c37382c37372c36362c35362c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37332c38332c31302c36362c36362c36352c37372c36382c36352c37372c36382c34372c34372c35362c36362c36352c36352c36352c36352c36352c36352c36352c36352c36352c36352c36352c36352c37372c36362c36352c37312c36372c3130352c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c37372c36392c36352c3130332c36352c36352c37372c36362c38312c37312c36372c3130352c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c31302c36352c38312c38312c36392c36362c3130332c36362c3130332c39372c3130332c36352c36352c36352c36382c36352c38302c36362c3130332c3131312c3131332c3130342c3130372c3130352c37312c34332c36392c34382c36362c36382c38312c36392c37302c36372c3130332c36392c36362c37372c36362c35322c37312c36372c3130352c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c38392c36392c36392c37332c38322c39382c3130302c3130362c3131372c3130342c31302c35332c3131302c3130322c39392c3130392c3130372c36382c38332c36352c34372c39302c3130312c3131382c3130372c39392c3131392c38322c36352c38392c37352c37352c3131312c39302c37332c3130342c3131382c3130342c37382c36352c38312c34382c36362c36362c3132322c36352c35302c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c39392c36362c36352c38312c37322c34372c37372c36362c36352c37312c31302c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c39392c36372c36352c38312c36392c36352c37372c36362c36352c37312c36372c3132312c3131332c37312c38332c37332c39382c35322c38342c38312c36392c37382c36352c38312c39392c36382c36352c38312c36392c36352c37372c36352c3131312c37312c36372c36372c3131332c37312c38332c37372c35322c35372c36362c36352c37372c36372c36352c34382c39392c36352c31302c37372c36392c38312c36372c37332c37322c38302c36352c37372c37342c38352c3131362c37332c35322c35332c37352c3131352c37392c3130362c37382c36392c38322c38312c38322c3130362c3131342c39392c35342c38352c35342c3131312c3131322c35322c38362c3131312c3130302c35362c3131332c39382c38352c35302c3131342c37382c38382c3131322c38352c39302c38372c36352c3130352c36352c3131382c37362c3132322c3130342c3131322c39382c37342c3130342c34392c3130382c38312c3131302c3131322c31302c3130382c3131382c39382c3130372c38372c37392c34372c38372c3131382c3132312c35342c39382c37372c39392c35312c3130362c38322c3131352c39372c3131332c34382c3130342c38362c3131312c34382c38302c37392c36392c3130392c3130332c36312c36312c31302c34352c34352c34352c34352c34352c36392c37382c36382c33322c36372c36392c38322c38342c37332c37302c37332c36372c36352c38342c36392c34352c34352c34352c34352c34352c31302c34352c34352c34352c34352c34352c36362c36392c37312c37332c37382c33322c36372c36392c38322c38342c37332c37302c37332c36372c36352c38342c36392c34352c34352c34352c34352c34352c31302c37372c37332c37332c36372c3130382c3130362c36372c36372c36352c3130362c35302c3130332c36352c3131392c37332c36362c36352c3130332c37332c38362c36352c37342c38362c3131382c38382c39392c35302c35372c37312c34332c37322c3131322c38312c36392c3131302c37342c34392c38302c38312c3132322c3132322c3130332c37302c38382c36372c35372c35332c38352c37372c36352c3131312c37312c36372c36372c3131332c37312c38332c37372c35322c35372c36362c36352c37372c36372c31302c37372c37312c3130332c3132302c37312c3130362c36352c38392c36362c3130332c37382c38362c36362c36352c37372c37372c36392c38352c3130382c3131372c3130302c37312c38362c3131352c37332c37302c37382c37322c38372c36372c36362c38332c39382c35302c35372c34382c37332c36392c37382c36362c37372c38322c3131312c3131392c37312c36352c38392c36382c38362c38312c38312c37352c36382c36362c37302c37342c39382c3131302c38322c3130382c39382c36372c36362c36382c31302c39382c35312c37342c3131392c39382c35312c37342c3130342c3130302c37312c3130382c3131382c39382c3130362c36392c38352c37372c36362c37332c37312c36352c34392c38352c36392c36362c3131392c3131392c37362c38352c35302c37302c3131372c3130302c37312c36392c3130332c38312c35302c3132302c3130342c39392c3130392c36392c3132302c36372c3132322c36352c37342c36362c3130332c37382c38362c36362c36352c3130332c37372c36352c3130372c37382c36362c37372c38312c3131352c3131392c31302c36372c38312c38392c36382c38362c38312c38312c37312c36392c3131392c37342c38362c38352c3132322c36352c3130312c37302c3131392c34382c3132302c37392c36382c36352c34392c37372c3130362c36392c3132302c37372c36382c38352c3131392c37372c38342c36362c39372c37302c3131392c34382c3132322c37372c3132322c36352c34392c37372c3130362c36392c3132302c37372c36382c38352c3131392c37372c38342c36362c39372c37372c37322c36352c3132302c37332c3130362c36352c3130332c31302c36362c3130332c37382c38362c36362c36352c37372c37372c37312c38352c3130382c3131372c3130302c37312c38362c3131352c37332c37302c37382c37322c38372c36372c36362c38312c38312c34382c3131352c3130332c38352c37312c3132302c3130342c3130302c37312c39302c3131382c39392c3130392c34382c3130332c38312c34382c36392c3132302c37312c3130362c36352c38392c36362c3130332c37382c38362c36362c36352c3131312c37372c36392c38352c3130382c3131372c3130302c37312c38362c3131352c31302c37332c36392c37382c3131382c39392c3131302c36362c3131382c39392c3130392c37302c34382c39372c38372c35372c3131372c37372c38322c38312c3131392c36392c3130332c38392c36382c38362c38312c38312c37322c36382c36352c3131362c38342c38392c38372c35332c34382c38392c38332c36362c36382c39382c37312c37302c3132312c38392c38342c36392c37362c37372c36352c3130372c37312c36352c34392c38352c36392c36372c36352c3131392c36372c38312c34382c36392c3132302c31302c36372c3132322c36352c37342c36362c3130332c37382c38362c36362c36352c38392c38342c36352c3130382c38362c38342c37372c37302c3130372c3131392c36392c3131392c38392c37322c37352c3131312c39302c37332c3132322c3130362c34382c36372c36352c38312c38392c37332c37352c3131312c39302c37332c3132322c3130362c34382c36382c36352c38312c39392c36382c38312c3130332c36352c36392c37382c38332c36362c34372c35352c3131362c35302c34392c3130382c38382c38332c37392c31302c35302c36372c3131372c3132322c3131322c3132302c3131392c35352c35322c3130312c37342c36362c35352c35302c36392c3132312c36382c37312c3130332c38372c35332c3131342c38382c36372c3131362c3132302c35302c3131362c38362c38342c37362c3131332c35342c3130342c37352c3130372c35342c3132322c34332c38352c3130352c38322c39302c36372c3131302c3131332c38322c35352c3131322c3131352c37392c3131382c3130332c3131332c37302c3130312c38332c3132302c3130382c3130392c38342c3130382c37342c3130382c31302c3130312c38342c3130392c3130352c35302c38372c38392c3132322c35312c3131332c37392c36362c3131372c3132322c36372c36362c3131372c36382c36352c3130322c36362c3130332c37382c38362c37322c38332c37372c36392c37312c36382c36352c38372c3130332c36362c38312c3130352c39302c38312c3132322c38372c38372c3131322c34382c34382c3130352c3130322c37392c36382c3131362c37342c38362c38332c3131382c34392c36352c39382c37392c38332c39392c37312c3131342c36382c36362c38332c31302c36362c3130332c37382c38362c37322c38322c35362c36392c38332c3132322c36362c37342c37372c36392c3130312c3130332c38322c39372c36362c36382c3130342c3130372c37302c3131312c3130302c37322c38322c3131392c39392c3132322c3131312c3131382c37362c35302c37382c3130382c39392c3131302c38322c3131322c39302c3130392c3130382c3130362c38392c38382c38322c3130382c39392c3132312c35332c34382c39392c3131302c38362c3132322c3130302c37312c38362c3130372c39392c35302c38362c3132312c31302c3130302c3130392c3130382c3130362c39302c38382c37372c3131372c39372c38372c35332c34382c39302c38372c3131392c3131372c38392c35302c35372c3131362c37362c34382c3130382c3131372c3130302c37312c38362c3131352c38352c34382c3130302c38392c38352c3130392c35372c3131382c3130302c36392c37382c36362c37362c3130392c38322c3130382c39392c3130362c36352c3130302c36362c3130332c37382c38362c37322c38312c35322c36392c37302c3130332c38312c38352c3130382c38372c35372c3130302c31302c3132322c39382c34382c39382c35322c3130312c3130382c36352c38332c39392c3131302c38352c35372c36382c38302c37392c36352c38362c39392c37362c35312c3130382c38312c3131392c36382c3130332c38392c36382c38362c38322c34382c38302c36352c38312c37322c34372c36362c36352c38312c36382c36352c3130332c36392c37312c37372c36362c37332c37312c36352c34392c38352c3130302c36392c3131392c36392c36362c34372c3131392c38312c37332c37372c36352c38392c36362c31302c36352c3130322c35362c36372c36352c38312c36352c3131392c36372c3130332c38392c37332c37352c3131312c39302c37332c3132322c3130362c34382c36392c36352c3131392c37332c36382c38322c3131392c36352c3131392c38322c36352c37332c3130332c38382c3131352c38362c3130372c3130352c34382c3131392c34332c3130352c35342c38362c38392c37312c38372c35312c38352c37302c34372c35302c35302c3131372c39372c38382c3130312c34382c38392c37342c36382c3130362c34392c38352c3130312c31302c3131302c36352c34332c38342c3130362c36382c34392c39372c3130352c35332c39392c36372c37332c36372c38392c39382c34392c38332c36352c3130392c36382c35332c3132302c3130372c3130322c38342c38362c3131322c3131382c3131312c35322c38352c3131312c3132312c3130352c38332c38392c3132302c3131342c36382c38372c37362c3130392c38352c38322c35322c36372c37332c35372c37382c37352c3132312c3130322c38302c37382c34332c31302c34352c34352c34352c34352c34352c36392c37382c36382c33322c36372c36392c38322c38342c37332c37302c37332c36372c36352c38342c36392c34352c34352c34352c34352c34352c31302c34352c34352c34352c34352c34352c36362c36392c37312c37332c37382c33322c36372c36392c38322c38342c37332c37302c37332c36372c36352c38342c36392c34352c34352c34352c34352c34352c31302c37372c37332c37332c36372c3130362c3132322c36372c36372c36352c3130362c38332c3130332c36352c3131392c37332c36362c36352c3130332c37332c38352c37332c3130392c38352c37372c34392c3130382c3131332c3130302c37382c37332c3131302c3132322c3130332c35352c38332c38362c38352c3131342c35372c38312c37312c3132322c3130372c3131302c36362c3131332c3131392c3131392c36372c3130332c38392c37332c37352c3131312c39302c37332c3132322c3130362c34382c36392c36352c3131392c37332c3131392c31302c39372c36382c36392c39372c37372c36362c3130332c37312c36352c34392c38352c36392c36352c3131392c3131392c38322c38332c38372c35332c34382c39302c38372c3131392c3130332c38352c34382c3130302c38392c37332c37302c37342c3131382c39382c35312c38312c3130332c38312c34382c36392c3132302c37312c3130362c36352c38392c36362c3130332c37382c38362c36362c36352c3131312c37372c36392c38352c3130382c3131372c3130302c37312c38362c3131352c37332c36392c37382c3131382c31302c39392c3131302c36362c3131382c39392c3130392c37302c34382c39372c38372c35372c3131372c37372c38322c38312c3131392c36392c3130332c38392c36382c38362c38312c38312c37322c36382c36352c3131362c38342c38392c38372c35332c34382c38392c38332c36362c36382c39382c37312c37302c3132312c38392c38342c36392c37362c37372c36352c3130372c37312c36352c34392c38352c36392c36372c36352c3131392c36372c38312c34382c36392c3132302c36372c3132322c36352c37342c31302c36362c3130332c37382c38362c36362c36352c38392c38342c36352c3130382c38362c38342c37372c36362c35322c38382c36382c38342c36392c35322c37372c36382c38352c3132312c37372c38342c36392c3131392c37382c36382c38352c3132302c37372c37302c3131312c38382c36382c38342c38312c35332c37372c38342c37332c3132322c37372c38342c37332c3132322c37382c38342c3130372c34392c37392c38362c3131312c3131392c39372c36382c36392c39372c37372c36362c3130332c37312c31302c36352c34392c38352c36392c36352c3131392c3131392c38322c38332c38372c35332c34382c39302c38372c3131392c3130332c38352c34382c3130302c38392c37332c37302c37342c3131382c39382c35312c38312c3130332c38312c34382c36392c3132302c37312c3130362c36352c38392c36362c3130332c37382c38362c36362c36352c3131312c37372c36392c38352c3130382c3131372c3130302c37312c38362c3131352c37332c36392c37382c3131382c39392c3131302c36362c3131382c39392c3130392c37302c34382c31302c39372c38372c35372c3131372c37372c38322c38312c3131392c36392c3130332c38392c36382c38362c38312c38312c37322c36382c36352c3131362c38342c38392c38372c35332c34382c38392c38332c36362c36382c39382c37312c37302c3132312c38392c38342c36392c37362c37372c36352c3130372c37312c36352c34392c38352c36392c36372c36352c3131392c36372c38312c34382c36392c3132302c36372c3132322c36352c37342c36362c3130332c37382c38362c36362c36352c38392c38342c31302c36352c3130382c38362c38342c37372c37302c3130372c3131392c36392c3131392c38392c37322c37352c3131312c39302c37332c3132322c3130362c34382c36372c36352c38312c38392c37332c37352c3131312c39302c37332c3132322c3130362c34382c36382c36352c38312c39392c36382c38312c3130332c36352c36392c36372c35342c3131302c36392c3131392c37372c36382c37332c38392c39302c37392c3130362c34372c3130352c38302c38372c3131352c36372c3132322c39372c36392c37352c3130352c35352c31302c34392c37392c3130352c37392c38332c37362c38322c37302c3130342c38372c37312c3130362c39382c3131302c36362c38362c37342c3130322c38362c3131302c3130372c38392c35322c3131372c35312c37332c3130362c3130372c36382c38392c38392c37362c34382c37372c3132302c37392c35322c3130392c3131332c3131352c3132312c38392c3130362c3130382c36362c39372c3130382c38342c38362c38392c3132302c37302c38302c35302c3131352c37342c36362c37352c35332c3132322c3130382c37352c37392c36362c31302c3131372c3132322c36372c36362c3131372c36382c36352c3130322c36362c3130332c37382c38362c37322c38332c37372c36392c37312c36382c36352c38372c3130332c36362c38312c3130352c39302c38312c3132322c38372c38372c3131322c34382c34382c3130352c3130322c37392c36382c3131362c37342c38362c38332c3131382c34392c36352c39382c37392c38332c39392c37312c3131342c36382c36362c38332c36362c3130332c37382c38362c37322c38322c35362c36392c38332c3132322c36362c37342c31302c37372c36392c3130312c3130332c38322c39372c36362c36382c3130342c3130372c37302c3131312c3130302c37322c38322c3131392c39392c3132322c3131312c3131382c37362c35302c37382c3130382c39392c3131302c38322c3131322c39302c3130392c3130382c3130362c38392c38382c38322c3130382c39392c3132312c35332c34382c39392c3131302c38362c3132322c3130302c37312c38362c3130372c39392c35302c38362c3132312c3130302c3130392c3130382c3130362c39302c38382c37372c3131372c39372c38372c35332c34382c31302c39302c38372c3131392c3131372c38392c35302c35372c3131362c37362c34382c3130382c3131372c3130302c37312c38362c3131352c38352c34382c3130302c38392c38352c3130392c35372c3131382c3130302c36392c37382c36362c37362c3130392c38322c3130382c39392c3130362c36352c3130302c36362c3130332c37382c38362c37322c38312c35322c36392c37302c3130332c38312c38352c37332c3130392c38352c37372c34392c3130382c3131332c3130302c37382c37332c3131302c3132322c3130332c35352c38332c38362c31302c38352c3131342c35372c38312c37312c3132322c3130372c3131302c36362c3131332c3131392c3131392c36382c3130332c38392c36382c38362c38322c34382c38302c36352c38312c37322c34372c36362c36352c38312c36382c36352c3130332c36392c37312c37372c36362c37332c37312c36352c34392c38352c3130302c36392c3131392c36392c36362c34372c3131392c38312c37332c37372c36352c38392c36362c36352c3130322c35362c36372c36352c38312c36392c3131392c36372c3130332c38392c37332c31302c37352c3131312c39302c37332c3132322c3130362c34382c36392c36352c3131392c37332c36382c38332c38312c36352c3131392c38322c3130332c37332c3130342c36352c37392c38372c34372c35332c38312c3130372c38322c34332c38332c35372c36372c3130352c38332c36382c39392c37382c3131312c3131312c3131392c37362c3131372c38302c38322c37362c3131352c38372c37312c3130322c34372c38392c3130352c35352c37312c38332c38382c35372c35322c36362c3130332c3131392c38342c3131392c3130332c31302c36352c3130352c36392c36352c35322c37342c34382c3130382c3131342c37322c3131312c37372c3131352c34332c38382c3131312c35332c3131312c34372c3131352c38382c35342c37392c35372c38312c38372c3132302c37322c38322c36352c3131382c39302c38352c37312c37392c3130302c38322c38312c35352c39392c3131382c3131332c38322c38382c39372c3131332c37332c36312c31302c34352c34352c34352c34352c34352c36392c37382c36382c33322c36372c36392c38322c38342c37332c37302c37332c36372c36352c38342c36392c34352c34352c34352c34352c34352c31302c305d2c22666e5f6b6579223a5b3234322c3135342c3235312c3234332c3131382c3232312c39302c3235342c3133352c3230362c3231312c33372c392c3137322c3135392c3233302c3137322c3235352c38332c3232302c32322c39302c39352c3235332c3231332c3234322c34302c33382c33332c39372c3231302c3134355d2c227369676e6572223a5b35302c3130302c342c33332c37372c3134302c3133312c312c3234392c3137392c37312c3139342c3136342c34342c35302c3131392c3133322c32372c3231382c3139362c3132322c36322c3132392c3138372c39332c39302c3230372c37352c36322c3133392c3137362c3231335d2c22666e5f726571756573745f6b6579223a5b5d2c22666e5f726571756573745f68617368223a5b5d2c22636861696e5f726573756c745f696e666f223a7b22536f6c616e61223a7b2273657269616c697a65645f7478223a5b332c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c302c3134342c38372c3133312c3138392c3130392c38352c3133372c3234322c3136372c3234332c3234312c3134322c382c3130372c34392c3232332c3138382c31302c3135362c3131312c3139362c3136332c39312c36392c3131332c31342c3137392c3231312c3137342c3133322c332c3234372c3136352c35302c3139332c3231332c3230332c3234372c31372c3232352c3233352c3234362c33392c3132312c3234332c34362c3233362c37372c36332c382c3232322c3136342c3133372c3234302c3232332c34392c38322c302c3230392c3233302c38332c36352c3138312c362c332c322c372c31342c31392c3136352c33392c3131392c3135392c31392c37382c3136322c32302c36332c3133312c35332c37352c3132322c39352c35302c3230312c36392c3230392c3133342c3138302c37322c3235322c32322c35302c3132302c39372c3136312c3139322c3234372c3132322c3234382c33362c3137372c3130342c39392c37332c3139362c3134382c3138372c3231312c35302c3136352c3139392c3137302c35312c3135352c3135372c39322c3136312c3232332c39382c36332c3137312c3235342c31362c34332c38312c39322c3138362c38392c31382c3130322c3230332c35302c3130302c342c33332c37372c3134302c3133312c312c3234392c3137392c37312c3139342c3136342c34342c35302c3131392c3133322c32372c3231382c3139362c3132322c36322c3132392c3138372c39332c39302c3230372c37352c36322c3133392c3137362c3231332c36382c36362c3232312c3139372c3133382c3232382c3134332c35392c3139392c3132392c3231342c39342c3234312c302c31372c3133322c3235332c3231312c3231302c3138382c3132342c3139372c31352c3130392c34382c36332c3136382c3235352c38332c34322c3234382c32302c3131342c3133392c3136382c3133372c3130302c3232392c3232332c3135352c31372c38392c3139302c3131312c35302c3233332c33312c3134312c3233372c3134372c3132302c33322c3232372c3136302c3136372c342c3230302c3233302c37342c3230332c3138332c3235312c35302c35322c3136392c3138342c3138322c3137342c38372c38302c36312c332c3232342c3135322c3233382c34352c32382c31332c3131392c3134392c302c33372c32362c38322c3130302c3139372c37372c32372c3139322c3231362c35322c3132322c3136322c31332c39392c37352c3234322c3135342c3235312c3234332c3131382c3232312c39302c3235342c3133352c3230362c3231312c33372c392c3137322c3135392c3233302c3137322c3235352c38332c3232302c32322c39302c39352c3235332c3231332c3234322c34302c33382c33332c39372c3231302c3134352c362c3232312c3234362c3232352c3231352c3130312c3136312c3134372c3231372c3230332c3232352c37302c3230362c3233352c3132312c3137322c32382c3138302c3133332c3233372c39352c39312c35352c3134352c35382c3134302c3234352c3133332c3132362c3235352c302c3136392c31322c3234362c33372c34302c3135362c3134362c3136312c3133322c3139302c3132302c3230312c31382c3136312c38312c3138392c3231352c38312c32382c3234332c3138392c38312c3233302c3139382c33372c3132372c3138392c3233372c34352c3138302c332c3138382c3139312c36342c3234362c3138342c34342c3230352c36332c3132342c3233312c33392c3135312c3234322c3137342c3139322c33362c3131352c3132332c39312c3139352c39302c3135342c39312c33342c33322c3134372c39312c3131322c3130392c3230362c32382c3133392c3136312c35302c38302c3138372c3234382c31352c38352c32302c3234372c36332c3132322c38392c38342c3138352c3234372c3131332c3234362c36302c35362c3230372c35332c33302c3132302c31332c3130392c36322c31322c38322c36392c3130322c37322c3230332c39302c37352c38312c33312c3232352c37392c3233372c3130342c3138332c33322c3139322c32302c3137372c3132342c3136322c36382c3133382c3139322c3231322c3230342c32372c35312c31382c3137362c36302c3230362c3234362c3135362c3131362c3134372c33382c36392c3136342c3134392c3139362c3139352c3231392c3232312c3134312c32392c35372c3134322c352c3137392c3137352c37352c3138342c3139342c3134332c3235342c3231312c3231332c3235302c3130302c3231342c3135352c3233392c35392c3139382c3138312c36382c32302c3134392c382c3233312c34352c3232332c3230332c35332c31372c3133372c33372c392c3232322c33312c3230342c3136302c3138342c3235352c3133352c3139342c3138352c38322c3136302c3134312c3235302c3235302c3136332c3132332c34382c39352c3235342c3136392c31302c39352c3233312c39332c32322c38302c35382c322c35302c3139312c39322c3234392c3133382c3233362c38312c392c3233362c3135362c3234352c3233322c39332c3135352c3233362c3139352c3234382c36352c36372c3230322c3231342c3235312c37342c3233342c3133372c36312c35332c32332c36332c322c382c31302c362c322c31332c312c392c31302c332c352c31312c372c35372c3231302c3130382c3135342c3133382c3139382c31342c35332c3139312c3135312c3135312c36372c3130312c302c302c302c302c3235352c3235352c3235352c3235352c3235352c3235352c3235352c3132372c302c32332c3235352c3135322c3234302c372c3134302c3232392c3130352c3133312c3138372c36322c3136302c31372c3230302c3137372c3135362c3233382c3231332c3234322c3135362c3135332c39342c352c37372c39312c3231382c3138332c3134362c3138312c3230362c3137332c3130382c31322c332c342c362c322c3135312c322c32302c3231362c3234362c35312c37322c3232362c3230372c3136302c332c302c302c302c312c3135312c3135312c36372c3130312c302c302c302c302c3132382c35382c3231302c35312c34362c33322c302c302c302c302c302c302c302c302c302c302c3132382c3135352c3135322c32322c3233332c302c302c302c302c302c302c302c302c302c302c302c33322c3230352c34382c3136392c33322c35392c302c302c302c302c302c302c302c302c302c302c37342c38312c3232312c3234302c34322c33322c302c302c302c302c302c302c302c302c302c302c3234362c3133382c3130362c3231392c3231352c33312c302c302c302c302c302c302c302c302c302c302c322c3135312c3135312c36372c3130312c302c302c302c302c302c392c37392c3138352c3137312c312c302c302c302c302c302c302c302c302c302c302c39362c33362c3231392c3132322c3130382c392c302c302c302c302c302c302c302c302c302c302c33322c3130392c38332c35332c37342c3234332c312c302c302c302c302c302c302c302c302c302c3138382c36352c34312c3135392c3137312c312c302c302c302c302c302c302c302c302c302c302c34382c39382c3134312c3134322c3137302c312c302c302c302c302c302c302c302c302c302c302c332c3135312c3135312c36372c3130312c302c302c302c302c3232342c34302c3134372c35392c302c302c302c302c302c302c302c302c302c302c302c302c302c3234302c3230362c3130342c3135362c3131302c3137342c302c302c302c302c302c302c302c302c302c302c32382c3232322c3135312c3138362c3230302c38362c372c302c302c302c302c302c302c302c302c38322c38342c3134352c35392c302c302c302c302c302c302c302c302c302c302c302c302c3232302c3233382c3134382c35392c302c302c302c302c302c302c302c302c302c302c302c305d7d7d2c226572726f725f636f6465223a307d";
617
618    #[test]
619    fn test_legacy_decode() {
620        let _ = simple_logger::init_with_level(log::Level::Debug);
621
622        let decoded =
623            FunctionResult::decode(&format!("FN_OUT: {}", EMPTY_ENCODED_FN_RESULT)).unwrap();
624
625        assert_eq!(decoded, FunctionResult::V0(FunctionResultV0::default()));
626    }
627
628    #[test]
629    fn test_legacy_quote() {
630        let _ = simple_logger::init_with_level(log::Level::Debug);
631
632        let mut rng = rand::thread_rng();
633
634        let quote: Vec<u8> = (0..1456).map(|_| rng.gen::<u8>()).collect();
635        let fn_key: Vec<u8> = (0..32).map(|_| rng.gen::<u8>()).collect();
636        let signer: Vec<u8> = (0..32).map(|_| rng.gen::<u8>()).collect();
637
638        let legacy = LegacyFunctionResult {
639            fn_key: fn_key.clone(),
640            version: 1,
641            quote: quote.clone(),
642            signer: signer.clone(),
643            fn_request_key: vec![],
644            fn_request_hash: vec![],
645            chain_result_info: LegacyChainResultInfo::default(),
646            error_code: 1,
647        };
648
649        let function_result: FunctionResult = legacy.into();
650
651        // println!("Quote = {:#?}", quote);
652
653        assert_eq!(quote, function_result.quote_bytes().to_vec());
654        assert_eq!(fn_key, function_result.fn_key().unwrap());
655        assert_eq!(signer, function_result.signer().to_vec());
656    }
657
658    #[test]
659    fn test_decode() {
660        let _ = simple_logger::init_with_level(log::Level::Debug);
661
662        let fr = FunctionResult::default();
663
664        let encoded = format!(
665            "FN_OUT: {}",
666            hex::encode(serde_json::to_string(&fr).unwrap())
667        );
668        // println!("Encoded: {:?}", encoded);
669
670        let decoded = FunctionResult::decode(&encoded).unwrap();
671        // println!("Decoded: {:?}", decoded);
672
673        assert_eq!(decoded, FunctionResult::default());
674    }
675
676    #[test]
677    fn test_case_1() {
678        let _ = simple_logger::init_with_level(log::Level::Debug);
679        let _decoded = FunctionResult::decode(TEST_CASE_1).unwrap();
680        // assert!(decoded_result.is_ok())
681    }
682
683    #[test]
684    fn test_evm_v0_decode() {
685        let _ = simple_logger::init_with_level(log::Level::Debug);
686
687        let evm_result = EvmFunctionResultV0::default();
688        let fr = FunctionResult::V0(FunctionResultV0 {
689            quote: vec![],
690            fn_key: vec![],
691            signer: vec![],
692            fn_request_key: vec![],
693            fn_request_hash: vec![],
694            chain_result_info: ChainResultInfo::Evm(EvmFunctionResult::V0(evm_result)),
695            error_code: 0,
696        });
697
698        let encoded = format!(
699            "FN_OUT: {}",
700            hex::encode(serde_json::to_string(&fr).unwrap())
701        );
702        // println!("Encoded: {:?}", encoded);
703
704        let decoded = FunctionResult::decode(&encoded).unwrap();
705        // println!("Decoded: {:?}", decoded);
706
707        match decoded {
708            FunctionResult::V0(FunctionResultV0 {
709                chain_result_info:
710                    ChainResultInfo::Evm(EvmFunctionResult::V0(decoded_evm_v0_result)),
711                ..
712            }) => {
713                assert_eq!(decoded_evm_v0_result, EvmFunctionResultV0::default());
714            }
715            _ => panic!("Expected EVMFunctionResultV0"),
716        }
717    }
718}