wormhole_sdk/
token.rs

1//! Parsers for Token bridge VAAs.
2//!
3//! Token bridging relies on VAA's that indicate custody/lockup/burn events in order to maintain
4//! token parity between multiple chains. These parsers can be used to read these VAAs. It also
5//! defines the Governance actions that this module supports, namely contract upgrades and chain
6//! registrations.
7
8use bstr::BString;
9use serde::{Deserialize, Serialize};
10use serde_wormhole::RawMessage;
11
12use crate::{Address, Amount, Chain};
13
14/// Represents a non-governance action targeted at the token bridge.
15///
16/// The generic parameter `P` indicates the type of the payload for the `TransferWithPayload`
17/// variant.  This defaults to `Box<RawMessage>` as that provides the most flexibility when
18/// deserializing the payload and avoids leaking lifetime parameters higher up the stack.  However,
19/// users who are serializing to or deserializing from the serde_wormhole data format may want to
20/// use a `&RawMessage` to avoid unnecessary memory allocations.  When the type of the payload is
21/// known and is serialized in the same data format as the rest of the message, that type can be
22/// used as the generic parameter to deserialize the message and the payload together.
23#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub enum Message<P = Box<RawMessage>> {
25    /// The Transfer message contains specifics detailing a token lock up on a sending chain. Chains
26    /// that are attempting to initiate a transfer must lock up tokens in some manner, such as in a
27    /// custody account or via burning, before emitting this message.
28    #[serde(rename = "1")]
29    Transfer {
30        /// The amount being transferred.
31        amount: Amount,
32
33        /// Address of the token. Left-zero-padded if shorter than 32 bytes.
34        token_address: Address,
35
36        /// Chain ID of the token.
37        token_chain: Chain,
38
39        /// Address of the recipient. Left-zero-padded if shorter than 32 bytes.
40        recipient: Address,
41
42        /// Chain ID of the recipient.
43        recipient_chain: Chain,
44
45        /// Amount that the user is willing to pay as the relayer fee.  Must be <= `amount`.
46        fee: Amount,
47    },
48
49    /// Contains information about a token and its origin chain.
50    #[serde(rename = "2")]
51    AssetMeta {
52        /// Address of the token. Left-zero-padded if shorter than 32 bytes.
53        token_address: Address,
54
55        /// Chain ID of the token.
56        token_chain: Chain,
57
58        /// Number of decimals in the token.
59        decimals: u8,
60
61        /// Symbol of the token.
62        #[serde(with = "crate::arraystring")]
63        symbol: BString,
64
65        /// Name of the token.
66        #[serde(with = "crate::arraystring")]
67        name: BString,
68    },
69
70    /// Similar to `Transfer` but also includes an arbitrary payload.
71    ///
72    /// # Examples
73    ///
74    /// Deserialize a `TransferWithPayload` message using the `serde_wormhole` crate:
75    ///
76    /// ```
77    /// # fn example() -> anyhow::Result<()> {
78    /// #     use wormhole_sdk::{Address, Amount, Chain, vaa::Signature, GOVERNANCE_EMITTER};
79    /// #
80    /// #     let data = [
81    /// #         0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb0, 0x72, 0x50, 0x5b, 0x5b, 0x99, 0x9c, 0x1d,
82    /// #         0x08, 0x90, 0x5c, 0x02, 0xe2, 0xb6, 0xb2, 0x83, 0x2e, 0xf7, 0x2c, 0x0b, 0xa6, 0xc8, 0xdb,
83    /// #         0x4f, 0x77, 0xfe, 0x45, 0x7e, 0xf2, 0xb3, 0xd0, 0x53, 0x41, 0x0b, 0x1e, 0x92, 0xa9, 0x19,
84    /// #         0x4d, 0x92, 0x10, 0xdf, 0x24, 0xd9, 0x87, 0xac, 0x83, 0xd7, 0xb6, 0xf0, 0xc2, 0x1c, 0xe9,
85    /// #         0x0f, 0x8b, 0xc1, 0x86, 0x9d, 0xe0, 0x89, 0x8b, 0xda, 0x7e, 0x98, 0x01, 0x00, 0x00, 0x00,
86    /// #         0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87    /// #         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88    /// #         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3c,
89    /// #         0x1b, 0xfa, 0x00, 0x03, 0x99, 0x30, 0x29, 0x01, 0x67, 0xf3, 0x48, 0x6a, 0xf6, 0x4c, 0xdd,
90    /// #         0x07, 0x64, 0xa1, 0x6a, 0xca, 0xcc, 0xc5, 0x64, 0x2a, 0x66, 0x71, 0xaa, 0x87, 0x98, 0x64,
91    /// #         0x0c, 0x25, 0x1f, 0x39, 0x73, 0x25, 0x12, 0x98, 0x15, 0xe5, 0x79, 0xdb, 0xd8, 0x25, 0xfd,
92    /// #         0x72, 0x58, 0x99, 0x97, 0xd1, 0x78, 0xb6, 0x2a, 0x57, 0x47, 0xab, 0xcf, 0x51, 0x62, 0xa5,
93    /// #         0xb7, 0xec, 0x19, 0x4e, 0x03, 0x51, 0x41, 0x18, 0x00, 0x08, 0xa4, 0x7e, 0xa2, 0x49, 0xd4,
94    /// #         0xf0, 0x56, 0x6f, 0xbd, 0x12, 0x77, 0xfe, 0xa8, 0x6e, 0x92, 0x81, 0x3a, 0x35, 0x90, 0x3b,
95    /// #         0x29, 0x73, 0x4d, 0x75, 0x56, 0x0a, 0xfe, 0x70, 0xb0, 0xb9, 0x10, 0x33, 0x00, 0x14, 0x47,
96    /// #         0x3e, 0x51, 0x74, 0x32, 0xbc, 0x3f, 0xb3, 0xf9, 0x82, 0xbb, 0xf3, 0xc9, 0x43, 0x41, 0xcf,
97    /// #         0x74, 0x24, 0xff, 0xa4, 0x02, 0x35, 0xbe, 0xb1, 0x7c, 0x47, 0x16, 0xba, 0xbc, 0xaa, 0xbe,
98    /// #         0x99, 0x54, 0xa2, 0x97, 0xbe, 0x2a, 0xed, 0xae, 0x91, 0x95, 0xb9, 0x6a, 0x8a, 0xba, 0xbd,
99    /// #         0x3a, 0xc1, 0xa4, 0xd1, 0x96, 0x0a, 0xf9, 0xab, 0x92, 0x42, 0x0d, 0x41, 0x33, 0xe5, 0xa8,
100    /// #         0x37, 0x32, 0xd3, 0xc3, 0xb8, 0xf3, 0x93, 0xd7, 0xc0, 0x9e, 0xe8, 0x87, 0xae, 0x16, 0xbf,
101    /// #         0xfa, 0x5e, 0x70, 0xea, 0x36, 0xa2, 0x82, 0x37, 0x1d, 0x46, 0x81, 0x94, 0x10, 0x34, 0xb1,
102    /// #         0xad, 0x0f, 0x4b, 0xc9, 0x17, 0x1e, 0x91, 0x25, 0x11,
103    /// #     ];
104    ///       use serde_wormhole::RawMessage;
105    ///       use wormhole_sdk::{token::Message, Vaa};
106    ///
107    ///       let msg = serde_wormhole::from_slice::<Vaa<Message<&RawMessage>>>(&data)?;
108    ///       match msg.payload {
109    ///           Message::TransferWithPayload { payload, .. } => {
110    ///               // Handle the payload.
111    /// #             assert_eq!(&data[256..], payload.get())
112    ///           }
113    ///           _ => {
114    ///               // Handle other message types.    
115    /// #             panic!("unexpected message type")
116    ///           }
117    ///       }
118    /// #
119    /// #     Ok(())
120    /// # }
121    /// #
122    /// # example().unwrap();
123    /// ```
124    ///
125    /// Deserialize a `TransferWithPayload` message using `serde_json`:
126    ///
127    /// ```
128    /// # fn example() -> anyhow::Result<()> {
129    /// #     use serde_wormhole::RawMessage;
130    /// #     use wormhole_sdk::{Address, Amount, Chain, vaa::Signature, GOVERNANCE_EMITTER};
131    /// #     let tx_payload = [
132    /// #         0x93, 0xd7, 0xc0, 0x9e, 0xe8, 0x87, 0xae, 0x16, 0xbf, 0xfa, 0x5e, 0x70, 0xea, 0x36, 0xa2,
133    /// #         0x82, 0x37, 0x1d, 0x46, 0x81, 0x94, 0x10, 0x34, 0xb1, 0xad, 0x0f, 0x4b, 0xc9,
134    /// #     ];
135    /// #
136    /// #     let vaa = Vaa {
137    /// #         version: 1,
138    /// #         guardian_set_index: 0,
139    /// #         signatures: Vec::new(),
140    /// #         timestamp: 1,
141    /// #         nonce: 1,
142    /// #         emitter_chain: Chain::Solana,
143    /// #         emitter_address: GOVERNANCE_EMITTER,
144    /// #         sequence: 20_716_538,
145    /// #         consistency_level: 0,
146    /// #         payload: Message::TransferWithPayload {
147    /// #             amount: Amount([0xcc; 32]),
148    /// #             token_address: Address([0x22; 32]),
149    /// #             token_chain: Chain::Algorand,
150    /// #             recipient: Address([0x19; 32]),
151    /// #             recipient_chain: Chain::Osmosis,
152    /// #             sender_address: Address([0xfe; 32]),
153    /// #             payload: <Box<RawMessage>>::from(tx_payload.to_vec()),
154    /// #         },
155    /// #     };
156    /// #
157    /// #     let data = serde_json::to_vec(&vaa)?;
158    ///       use anyhow::anyhow;
159    ///       use wormhole_sdk::{token::Message, Vaa};
160    ///
161    ///       let msg = serde_json::from_slice::<Vaa<Message>>(&data)?;
162    /// #     assert_eq!(vaa, msg);
163    ///       match msg.payload {
164    ///           Message::TransferWithPayload { payload, .. } => {
165    ///               // Handle the payload.
166    /// #             assert_eq!(&tx_payload[..], payload.get())
167    ///           }
168    ///           _ => {
169    ///               // Handle other message types.    
170    /// #             panic!("unexpected message type")
171    ///           }
172    ///       }
173    /// #
174    /// #     Ok(())
175    /// # }
176    /// #
177    /// # example().unwrap();
178    /// ```
179    #[serde(rename = "3")]
180    TransferWithPayload {
181        /// The amount being transferred.
182        amount: Amount,
183
184        /// Address of the token. Left-zero-padded if shorter than 32 bytes.
185        token_address: Address,
186
187        /// Chain ID of the token.
188        token_chain: Chain,
189
190        /// Address of the recipient. Left-zero-padded if shorter than 32 bytes.
191        recipient: Address,
192
193        /// Chain ID of the recipient.
194        recipient_chain: Chain,
195
196        /// The identity of the sender sending the payload.
197        sender_address: Address,
198
199        /// The payload to be included with the transfer.
200        payload: P,
201    },
202}
203
204/// Represents a governance action targeted at the token bridge.
205#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
206pub enum Action {
207    /// Registers an emitter address for a particular chain on a different chain.  An emitter
208    /// address must be registered for a chain and must match the emitter address in the VAA before
209    /// the token bridge will accept VAAs from that chain.
210    #[serde(rename = "1")]
211    RegisterChain {
212        chain: Chain,
213        emitter_address: Address,
214    },
215
216    /// Upgrades the token bridge contract to a new address.
217    #[serde(rename = "2")]
218    ContractUpgrade { new_contract: Address },
219}
220
221/// Represents the payload for a governance VAA targeted at the token bridge.
222#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
223pub struct GovernancePacket {
224    /// The chain on which the governance action should be carried out.
225    pub chain: Chain,
226
227    /// The actual governance action to be carried out.
228    pub action: Action,
229}
230
231// MODULE = "TokenBridge"
232pub const MODULE: [u8; 32] = *b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00TokenBridge";
233
234// The wire format for GovernancePackets is wonky and doesn't lend itself well to auto-deriving
235// Serialize / Deserialize so we implement it manually here.
236mod governance_packet_impl {
237    use std::fmt;
238
239    use serde::{
240        de::{Error, MapAccess, SeqAccess, Visitor},
241        ser::SerializeStruct,
242        Deserialize, Deserializer, Serialize, Serializer,
243    };
244
245    use crate::{
246        token::{Action, GovernancePacket, MODULE},
247        Address, Chain,
248    };
249
250    struct Module;
251
252    impl Serialize for Module {
253        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
254        where
255            S: Serializer,
256        {
257            MODULE.serialize(serializer)
258        }
259    }
260
261    impl<'de> Deserialize<'de> for Module {
262        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
263        where
264            D: Deserializer<'de>,
265        {
266            let arr = <[u8; 32]>::deserialize(deserializer)?;
267
268            if arr == MODULE {
269                Ok(Module)
270            } else {
271                Err(Error::custom(
272                    "invalid governance module, expected \"TokenBridge\"",
273                ))
274            }
275        }
276    }
277
278    #[derive(Serialize, Deserialize)]
279    struct ContractUpgrade {
280        new_contract: Address,
281    }
282
283    #[derive(Serialize, Deserialize)]
284    struct RegisterChain {
285        chain: Chain,
286        emitter_address: Address,
287    }
288
289    impl Serialize for GovernancePacket {
290        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
291        where
292            S: Serializer,
293        {
294            let mut seq = serializer.serialize_struct("GovernancePacket", 4)?;
295            seq.serialize_field("module", &Module)?;
296
297            // The wire format encodes the action before the chain and then appends the actual
298            // action payload.
299            match self.action.clone() {
300                Action::RegisterChain {
301                    chain,
302                    emitter_address,
303                } => {
304                    seq.serialize_field("action", &1u8)?;
305                    seq.serialize_field("chain", &self.chain)?;
306                    seq.serialize_field(
307                        "payload",
308                        &RegisterChain {
309                            chain,
310                            emitter_address,
311                        },
312                    )?;
313                }
314                Action::ContractUpgrade { new_contract } => {
315                    seq.serialize_field("action", &2u8)?;
316                    seq.serialize_field("chain", &self.chain)?;
317                    seq.serialize_field("payload", &ContractUpgrade { new_contract })?;
318                }
319            }
320
321            seq.end()
322        }
323    }
324
325    struct GovernancePacketVisitor;
326
327    impl<'de> Visitor<'de> for GovernancePacketVisitor {
328        type Value = GovernancePacket;
329
330        fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
331            f.write_str("struct GovernancePacket")
332        }
333
334        #[inline]
335        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
336        where
337            A: SeqAccess<'de>,
338        {
339            static EXPECTING: &str = "struct GovernancePacket with 4 elements";
340
341            let _: Module = seq
342                .next_element()?
343                .ok_or_else(|| Error::invalid_length(0, &EXPECTING))?;
344            let act: u8 = seq
345                .next_element()?
346                .ok_or_else(|| Error::invalid_length(1, &EXPECTING))?;
347            let chain = seq
348                .next_element()?
349                .ok_or_else(|| Error::invalid_length(2, &EXPECTING))?;
350
351            let action = match act {
352                1 => {
353                    let RegisterChain {
354                        chain,
355                        emitter_address,
356                    } = seq
357                        .next_element()?
358                        .ok_or_else(|| Error::invalid_length(3, &EXPECTING))?;
359
360                    Action::RegisterChain {
361                        chain,
362                        emitter_address,
363                    }
364                }
365                2 => {
366                    let ContractUpgrade { new_contract } = seq
367                        .next_element()?
368                        .ok_or_else(|| Error::invalid_length(3, &EXPECTING))?;
369
370                    Action::ContractUpgrade { new_contract }
371                }
372                v => {
373                    return Err(Error::custom(format_args!(
374                        "invalid value: {v}, expected one of 1, 2"
375                    )))
376                }
377            };
378
379            Ok(GovernancePacket { chain, action })
380        }
381
382        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
383        where
384            A: MapAccess<'de>,
385        {
386            #[derive(Serialize, Deserialize)]
387            #[serde(rename_all = "snake_case")]
388            enum Field {
389                Module,
390                Action,
391                Chain,
392                Payload,
393            }
394
395            let mut module = None;
396            let mut chain = None;
397            let mut action = None;
398            let mut payload = None;
399
400            while let Some(key) = map.next_key::<Field>()? {
401                match key {
402                    Field::Module => {
403                        if module.is_some() {
404                            return Err(Error::duplicate_field("module"));
405                        }
406
407                        module = map.next_value::<Module>().map(Some)?;
408                    }
409                    Field::Action => {
410                        if action.is_some() {
411                            return Err(Error::duplicate_field("action"));
412                        }
413
414                        action = map.next_value::<u8>().map(Some)?;
415                    }
416                    Field::Chain => {
417                        if chain.is_some() {
418                            return Err(Error::duplicate_field("chain"));
419                        }
420
421                        chain = map.next_value().map(Some)?;
422                    }
423                    Field::Payload => {
424                        if payload.is_some() {
425                            return Err(Error::duplicate_field("payload"));
426                        }
427
428                        let a = action.as_ref().copied().ok_or_else(|| {
429                            Error::custom("`action` must be known before deserializing `payload`")
430                        })?;
431
432                        let p = match a {
433                            1 => {
434                                let RegisterChain {
435                                    chain,
436                                    emitter_address,
437                                } = map.next_value()?;
438
439                                Action::RegisterChain {
440                                    chain,
441                                    emitter_address,
442                                }
443                            }
444                            2 => {
445                                let ContractUpgrade { new_contract } = map.next_value()?;
446
447                                Action::ContractUpgrade { new_contract }
448                            }
449                            v => {
450                                return Err(Error::custom(format_args!(
451                                    "invalid action: {v}, expected one of: 1, 2"
452                                )))
453                            }
454                        };
455
456                        payload = Some(p);
457                    }
458                }
459            }
460
461            let _ = module.ok_or_else(|| Error::missing_field("module"))?;
462            let chain = chain.ok_or_else(|| Error::missing_field("chain"))?;
463            let action = payload.ok_or_else(|| Error::missing_field("payload"))?;
464
465            Ok(GovernancePacket { chain, action })
466        }
467    }
468
469    impl<'de> Deserialize<'de> for GovernancePacket {
470        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
471        where
472            D: Deserializer<'de>,
473        {
474            const FIELDS: &[&str] = &["module", "action", "chain", "payload"];
475            deserializer.deserialize_struct("GovernancePacket", FIELDS, GovernancePacketVisitor)
476        }
477    }
478}
479
480#[cfg(test)]
481mod test {
482    use serde_wormhole::RawMessage;
483
484    use crate::{vaa::Signature, Vaa, GOVERNANCE_EMITTER};
485
486    use super::*;
487
488    #[test]
489    pub fn transfer() {
490        let payload = [
491            0x01, 0xfa, 0x22, 0x8b, 0x3d, 0xf3, 0x59, 0x21, 0xa1, 0xc9, 0x39, 0xad, 0x9c, 0x54,
492            0xe1, 0x2f, 0x87, 0xc6, 0x27, 0x25, 0xd1, 0xaf, 0x7c, 0x7b, 0x6a, 0xea, 0xbf, 0x48,
493            0x14, 0xe7, 0x26, 0x56, 0xfa, 0xe8, 0xf2, 0xd2, 0x53, 0xd1, 0x08, 0x52, 0xa2, 0x6f,
494            0x55, 0xae, 0x93, 0xb5, 0x9b, 0x46, 0x91, 0x3d, 0xdf, 0x89, 0x1c, 0xb5, 0x38, 0x75,
495            0x5a, 0x45, 0x47, 0xde, 0x51, 0x12, 0x01, 0x5d, 0xc3, 0x00, 0x15, 0x7a, 0x1f, 0x37,
496            0xe7, 0x14, 0x28, 0xbc, 0x04, 0x75, 0xd9, 0x26, 0x8e, 0x4b, 0x53, 0x06, 0xd3, 0xa1,
497            0x22, 0x40, 0x13, 0xc4, 0x36, 0xbd, 0x1c, 0x23, 0xd7, 0x2a, 0x1c, 0x16, 0x46, 0x43,
498            0x50, 0x00, 0x07, 0x48, 0xc7, 0x7c, 0x80, 0xbd, 0x11, 0xee, 0x41, 0x20, 0xb3, 0x52,
499            0x3b, 0xd0, 0x0a, 0x2f, 0xdd, 0x02, 0xe8, 0xef, 0xfc, 0x7a, 0xfe, 0x3d, 0xd6, 0x73,
500            0x2c, 0x5d, 0xa0, 0x6b, 0x08, 0x98, 0x6c,
501        ];
502        // Need to explicity annotate the type here so that the compiler will use the default type
503        // parameter.
504        let msg: Message = Message::Transfer {
505            amount: Amount([
506                0xfa, 0x22, 0x8b, 0x3d, 0xf3, 0x59, 0x21, 0xa1, 0xc9, 0x39, 0xad, 0x9c, 0x54, 0xe1,
507                0x2f, 0x87, 0xc6, 0x27, 0x25, 0xd1, 0xaf, 0x7c, 0x7b, 0x6a, 0xea, 0xbf, 0x48, 0x14,
508                0xe7, 0x26, 0x56, 0xfa,
509            ]),
510            token_address: Address([
511                0xe8, 0xf2, 0xd2, 0x53, 0xd1, 0x08, 0x52, 0xa2, 0x6f, 0x55, 0xae, 0x93, 0xb5, 0x9b,
512                0x46, 0x91, 0x3d, 0xdf, 0x89, 0x1c, 0xb5, 0x38, 0x75, 0x5a, 0x45, 0x47, 0xde, 0x51,
513                0x12, 0x01, 0x5d, 0xc3,
514            ]),
515            token_chain: Chain::Sui,
516            recipient: Address([
517                0x7a, 0x1f, 0x37, 0xe7, 0x14, 0x28, 0xbc, 0x04, 0x75, 0xd9, 0x26, 0x8e, 0x4b, 0x53,
518                0x06, 0xd3, 0xa1, 0x22, 0x40, 0x13, 0xc4, 0x36, 0xbd, 0x1c, 0x23, 0xd7, 0x2a, 0x1c,
519                0x16, 0x46, 0x43, 0x50,
520            ]),
521            recipient_chain: Chain::Oasis,
522            fee: Amount([
523                0x48, 0xc7, 0x7c, 0x80, 0xbd, 0x11, 0xee, 0x41, 0x20, 0xb3, 0x52, 0x3b, 0xd0, 0x0a,
524                0x2f, 0xdd, 0x02, 0xe8, 0xef, 0xfc, 0x7a, 0xfe, 0x3d, 0xd6, 0x73, 0x2c, 0x5d, 0xa0,
525                0x6b, 0x08, 0x98, 0x6c,
526            ]),
527        };
528
529        assert_eq!(payload.as_ref(), &serde_wormhole::to_vec(&msg).unwrap());
530        assert_eq!(msg, serde_wormhole::from_slice(&payload).unwrap());
531
532        let encoded = serde_json::to_string(&msg).unwrap();
533        assert_eq!(msg, serde_json::from_str(&encoded).unwrap());
534    }
535
536    #[test]
537    pub fn asset_meta() {
538        let payload = [
539            0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
541            0x00, 0xbe, 0xef, 0xfa, 0xce, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
543            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0x45, 0x46, 0x00, 0x00,
544            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
545            0x00, 0x42, 0x65, 0x65, 0x66, 0x20, 0x66, 0x61, 0x63, 0x65, 0x20, 0x54, 0x6f, 0x6b,
546            0x65, 0x6e,
547        ];
548
549        // Need to explicity annotate the type here so that the compiler will use the default type
550        // parameter.
551        let msg: Message = Message::AssetMeta {
552            token_address: Address([
553                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
554                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
555                0xbe, 0xef, 0xfa, 0xce,
556            ]),
557            token_chain: Chain::Ethereum,
558            decimals: 12,
559            symbol: "BEEF".into(),
560            name: "Beef face Token".into(),
561        };
562
563        assert_eq!(payload.as_ref(), &serde_wormhole::to_vec(&msg).unwrap());
564        assert_eq!(msg, serde_wormhole::from_slice(&payload).unwrap());
565
566        let encoded = serde_json::to_string(&msg).unwrap();
567        assert_eq!(msg, serde_json::from_str(&encoded).unwrap());
568    }
569
570    #[test]
571    pub fn transfer_with_payload() {
572        let payload = [
573            0x03, 0x99, 0x30, 0x29, 0x01, 0x67, 0xf3, 0x48, 0x6a, 0xf6, 0x4c, 0xdd, 0x07, 0x64,
574            0xa1, 0x6a, 0xca, 0xcc, 0xc5, 0x64, 0x2a, 0x66, 0x71, 0xaa, 0x87, 0x98, 0x64, 0x0c,
575            0x25, 0x1f, 0x39, 0x73, 0x25, 0x12, 0x98, 0x15, 0xe5, 0x79, 0xdb, 0xd8, 0x25, 0xfd,
576            0x72, 0x58, 0x99, 0x97, 0xd1, 0x78, 0xb6, 0x2a, 0x57, 0x47, 0xab, 0xcf, 0x51, 0x62,
577            0xa5, 0xb7, 0xec, 0x19, 0x4e, 0x03, 0x51, 0x41, 0x18, 0x00, 0x08, 0xa4, 0x7e, 0xa2,
578            0x49, 0xd4, 0xf0, 0x56, 0x6f, 0xbd, 0x12, 0x77, 0xfe, 0xa8, 0x6e, 0x92, 0x81, 0x3a,
579            0x35, 0x90, 0x3b, 0x29, 0x73, 0x4d, 0x75, 0x56, 0x0a, 0xfe, 0x70, 0xb0, 0xb9, 0x10,
580            0x33, 0x00, 0x14, 0x47, 0x3e, 0x51, 0x74, 0x32, 0xbc, 0x3f, 0xb3, 0xf9, 0x82, 0xbb,
581            0xf3, 0xc9, 0x43, 0x41, 0xcf, 0x74, 0x24, 0xff, 0xa4, 0x02, 0x35, 0xbe, 0xb1, 0x7c,
582            0x47, 0x16, 0xba, 0xbc, 0xaa, 0xbe, 0x99, 0x54, 0xa2, 0x97, 0xbe, 0x2a, 0xed, 0xae,
583            0x91, 0x95, 0xb9, 0x6a, 0x8a, 0xba, 0xbd, 0x3a, 0xc1, 0xa4, 0xd1, 0x96, 0x0a, 0xf9,
584            0xab, 0x92, 0x42, 0x0d, 0x41, 0x33, 0xe5, 0xa8, 0x37, 0x32, 0xd3, 0xc3, 0xb8, 0xf3,
585            0x93, 0xd7, 0xc0, 0x9e, 0xe8, 0x87, 0xae, 0x16, 0xbf, 0xfa, 0x5e, 0x70, 0xea, 0x36,
586            0xa2, 0x82, 0x37, 0x1d, 0x46, 0x81, 0x94, 0x10, 0x34, 0xb1, 0xad, 0x0f, 0x4b, 0xc9,
587            0x17, 0x1e, 0x91, 0x25, 0x11,
588        ];
589
590        // No need to annotate the type here as the compiler can infer the generic parameter via the
591        // `TransferWithPayload` variant.
592        let msg = Message::TransferWithPayload {
593            amount: Amount([
594                0x99, 0x30, 0x29, 0x01, 0x67, 0xf3, 0x48, 0x6a, 0xf6, 0x4c, 0xdd, 0x07, 0x64, 0xa1,
595                0x6a, 0xca, 0xcc, 0xc5, 0x64, 0x2a, 0x66, 0x71, 0xaa, 0x87, 0x98, 0x64, 0x0c, 0x25,
596                0x1f, 0x39, 0x73, 0x25,
597            ]),
598            token_address: Address([
599                0x12, 0x98, 0x15, 0xe5, 0x79, 0xdb, 0xd8, 0x25, 0xfd, 0x72, 0x58, 0x99, 0x97, 0xd1,
600                0x78, 0xb6, 0x2a, 0x57, 0x47, 0xab, 0xcf, 0x51, 0x62, 0xa5, 0xb7, 0xec, 0x19, 0x4e,
601                0x03, 0x51, 0x41, 0x18,
602            ]),
603            token_chain: Chain::Algorand,
604            recipient: Address([
605                0xa4, 0x7e, 0xa2, 0x49, 0xd4, 0xf0, 0x56, 0x6f, 0xbd, 0x12, 0x77, 0xfe, 0xa8, 0x6e,
606                0x92, 0x81, 0x3a, 0x35, 0x90, 0x3b, 0x29, 0x73, 0x4d, 0x75, 0x56, 0x0a, 0xfe, 0x70,
607                0xb0, 0xb9, 0x10, 0x33,
608            ]),
609            recipient_chain: Chain::Osmosis,
610            sender_address: Address([
611                0x47, 0x3e, 0x51, 0x74, 0x32, 0xbc, 0x3f, 0xb3, 0xf9, 0x82, 0xbb, 0xf3, 0xc9, 0x43,
612                0x41, 0xcf, 0x74, 0x24, 0xff, 0xa4, 0x02, 0x35, 0xbe, 0xb1, 0x7c, 0x47, 0x16, 0xba,
613                0xbc, 0xaa, 0xbe, 0x99,
614            ]),
615            payload: <Box<RawMessage>>::from(payload[133..].to_vec()),
616        };
617
618        assert_eq!(&payload[..], &serde_wormhole::to_vec(&msg).unwrap());
619        assert_eq!(msg, serde_wormhole::from_slice(&payload).unwrap());
620
621        let encoded = serde_json::to_vec(&msg).unwrap();
622        assert_eq!(msg, serde_json::from_slice(&encoded).unwrap());
623    }
624
625    #[test]
626    fn register_chain() {
627        let buf = [
628            0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xb0, 0x72, 0x50, 0x5b, 0x5b, 0x99, 0x9c,
629            0x1d, 0x08, 0x90, 0x5c, 0x02, 0xe2, 0xb6, 0xb2, 0x83, 0x2e, 0xf7, 0x2c, 0x0b, 0xa6,
630            0xc8, 0xdb, 0x4f, 0x77, 0xfe, 0x45, 0x7e, 0xf2, 0xb3, 0xd0, 0x53, 0x41, 0x0b, 0x1e,
631            0x92, 0xa9, 0x19, 0x4d, 0x92, 0x10, 0xdf, 0x24, 0xd9, 0x87, 0xac, 0x83, 0xd7, 0xb6,
632            0xf0, 0xc2, 0x1c, 0xe9, 0x0f, 0x8b, 0xc1, 0x86, 0x9d, 0xe0, 0x89, 0x8b, 0xda, 0x7e,
633            0x98, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
634            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636            0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3c, 0x1b, 0xfa, 0x00, 0x00, 0x00, 0x00,
637            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638            0x00, 0x00, 0x00, 0x00, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x72, 0x69, 0x64, 0x67,
639            0x65, 0x01, 0x00, 0x00, 0x00, 0x01, 0x3b, 0x26, 0x40, 0x9f, 0x8a, 0xad, 0xed, 0x3f,
640            0x5d, 0xdc, 0xa1, 0x84, 0x69, 0x5a, 0xa6, 0xa0, 0xfa, 0x82, 0x9b, 0x0c, 0x85, 0xca,
641            0xf8, 0x48, 0x56, 0x32, 0x48, 0x96, 0xd2, 0x14, 0xca, 0x98,
642        ];
643
644        let vaa = Vaa {
645            version: 1,
646            guardian_set_index: 0,
647            signatures: vec![Signature {
648                index: 0,
649                signature: [
650                    0xb0, 0x72, 0x50, 0x5b, 0x5b, 0x99, 0x9c, 0x1d, 0x08, 0x90, 0x5c, 0x02, 0xe2,
651                    0xb6, 0xb2, 0x83, 0x2e, 0xf7, 0x2c, 0x0b, 0xa6, 0xc8, 0xdb, 0x4f, 0x77, 0xfe,
652                    0x45, 0x7e, 0xf2, 0xb3, 0xd0, 0x53, 0x41, 0x0b, 0x1e, 0x92, 0xa9, 0x19, 0x4d,
653                    0x92, 0x10, 0xdf, 0x24, 0xd9, 0x87, 0xac, 0x83, 0xd7, 0xb6, 0xf0, 0xc2, 0x1c,
654                    0xe9, 0x0f, 0x8b, 0xc1, 0x86, 0x9d, 0xe0, 0x89, 0x8b, 0xda, 0x7e, 0x98, 0x01,
655                ],
656            }],
657            timestamp: 1,
658            nonce: 1,
659            emitter_chain: Chain::Solana,
660            emitter_address: GOVERNANCE_EMITTER,
661            sequence: 20_716_538,
662            consistency_level: 0,
663            payload: GovernancePacket {
664                chain: Chain::Any,
665                action: Action::RegisterChain {
666                    chain: Chain::Solana,
667                    emitter_address: Address([
668                        0x3b, 0x26, 0x40, 0x9f, 0x8a, 0xad, 0xed, 0x3f, 0x5d, 0xdc, 0xa1, 0x84,
669                        0x69, 0x5a, 0xa6, 0xa0, 0xfa, 0x82, 0x9b, 0x0c, 0x85, 0xca, 0xf8, 0x48,
670                        0x56, 0x32, 0x48, 0x96, 0xd2, 0x14, 0xca, 0x98,
671                    ]),
672                },
673            },
674        };
675
676        assert_eq!(buf.as_ref(), &serde_wormhole::to_vec(&vaa).unwrap());
677        assert_eq!(vaa, serde_wormhole::from_slice(&buf).unwrap());
678
679        let encoded = serde_json::to_string(&vaa).unwrap();
680        assert_eq!(vaa, serde_json::from_str(&encoded).unwrap());
681    }
682
683    #[test]
684    fn contract_upgrade() {
685        let buf = [
686            0x01, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x02, 0x73, 0xaf, 0x3c, 0x2f, 0x55, 0x98, 0x90,
687            0x41, 0xb0, 0x06, 0x8a, 0x4e, 0xae, 0xba, 0x8f, 0x88, 0x25, 0x10, 0x60, 0x21, 0x99,
688            0x6d, 0xe6, 0x14, 0x39, 0x54, 0xc0, 0x6f, 0xc4, 0xcf, 0xad, 0x5c, 0x3f, 0x1a, 0xba,
689            0x6c, 0xa9, 0x51, 0x18, 0x8e, 0x96, 0x2f, 0x11, 0x25, 0x1c, 0x25, 0xca, 0x98, 0x62,
690            0x86, 0x85, 0xe2, 0xfc, 0x2b, 0x65, 0xec, 0x60, 0x94, 0x50, 0xcf, 0xc4, 0xe6, 0x51,
691            0x12, 0x00, 0x03, 0x00, 0xc6, 0x2e, 0xb0, 0xde, 0x7a, 0xb3, 0xd0, 0x28, 0x92, 0x0f,
692            0x18, 0xe1, 0x0d, 0xf7, 0xf2, 0xa0, 0x4d, 0x00, 0xeb, 0x88, 0xb8, 0x94, 0x0a, 0x27,
693            0xbb, 0xce, 0x8c, 0xe6, 0x6c, 0x67, 0x52, 0x68, 0x82, 0xc9, 0x6c, 0xc5, 0x0d, 0xd3,
694            0x81, 0xbd, 0xbf, 0xf3, 0x0b, 0xb6, 0x5b, 0x93, 0x47, 0xca, 0xdf, 0xf0, 0x96, 0x76,
695            0x72, 0x90, 0x43, 0xaf, 0x60, 0xd6, 0x52, 0xa0, 0xb9, 0x06, 0x30, 0x00, 0x04, 0xf0,
696            0x7b, 0x0f, 0xe6, 0xca, 0xb1, 0x8b, 0xe7, 0xae, 0x82, 0x7f, 0xe1, 0x1c, 0xa8, 0x99,
697            0x2f, 0xf0, 0xb5, 0xa2, 0xa3, 0x2d, 0x65, 0xbe, 0x95, 0x82, 0x31, 0xbf, 0x84, 0xcf,
698            0x6b, 0x14, 0xfb, 0x5e, 0xeb, 0x8a, 0x51, 0xad, 0xe1, 0xc7, 0x0a, 0xa5, 0xb8, 0xb8,
699            0xcf, 0x83, 0xaf, 0xe3, 0xc2, 0x2d, 0x34, 0x71, 0x48, 0x1b, 0xda, 0x38, 0x96, 0xea,
700            0x2a, 0x70, 0x46, 0x9f, 0x96, 0x92, 0xb8, 0x00, 0x05, 0x74, 0xd4, 0x96, 0x72, 0x9d,
701            0xde, 0x6e, 0x19, 0x09, 0x59, 0xa1, 0x79, 0x45, 0xe8, 0x7c, 0xd9, 0x5e, 0x23, 0xc1,
702            0x00, 0x47, 0xab, 0x2e, 0xef, 0x5c, 0x7d, 0x0e, 0xc6, 0xf9, 0x12, 0x08, 0xc7, 0x27,
703            0x9d, 0x8a, 0x1b, 0x1f, 0x4a, 0x60, 0x06, 0x9d, 0x25, 0x93, 0x2a, 0x67, 0xd6, 0x55,
704            0xf2, 0xd0, 0xb4, 0x20, 0x59, 0x00, 0x3d, 0xe7, 0x5f, 0xd3, 0xca, 0x79, 0x92, 0xfd,
705            0xd1, 0xb0, 0xd4, 0x01, 0x06, 0x51, 0xf0, 0x6a, 0xb6, 0xfd, 0xfd, 0x42, 0xf3, 0x23,
706            0x84, 0x0a, 0x81, 0x8b, 0x38, 0xcf, 0xd1, 0xc9, 0x9d, 0x22, 0x36, 0x6c, 0x87, 0x79,
707            0x03, 0xb9, 0x8d, 0xf4, 0x0b, 0xda, 0xf2, 0xa2, 0x04, 0x2e, 0xb8, 0xcd, 0x0e, 0x59,
708            0xc4, 0x63, 0x7e, 0x6a, 0x80, 0xa1, 0x99, 0xb1, 0x10, 0x8c, 0xd7, 0x65, 0x9b, 0xa8,
709            0x37, 0x0f, 0x6f, 0x94, 0x76, 0xb4, 0x79, 0x83, 0x98, 0x54, 0xd8, 0xc1, 0xa6, 0x00,
710            0x07, 0x78, 0x4b, 0x37, 0xc6, 0x10, 0x3c, 0x75, 0x2c, 0xd9, 0x7a, 0x58, 0x6b, 0xe8,
711            0xe1, 0xce, 0xff, 0x22, 0xa6, 0xe4, 0x88, 0x43, 0x32, 0x84, 0xff, 0x31, 0xcd, 0x90,
712            0x8b, 0x5c, 0x7d, 0x87, 0xe2, 0x44, 0xda, 0x75, 0x16, 0xd0, 0x7a, 0x0f, 0xa6, 0x92,
713            0x68, 0x4f, 0x82, 0x6e, 0x5e, 0x6c, 0x8b, 0x45, 0x20, 0x04, 0x20, 0x6d, 0x6f, 0xe5,
714            0xba, 0xe4, 0x6a, 0xfb, 0x1c, 0x21, 0x8c, 0xf5, 0x0d, 0x00, 0x09, 0x0b, 0x6c, 0xcc,
715            0xe6, 0x7e, 0xd5, 0x01, 0xcb, 0x20, 0xfb, 0x06, 0xde, 0x76, 0xb9, 0x08, 0x3f, 0x13,
716            0x29, 0xad, 0x78, 0xd3, 0x84, 0x51, 0x7a, 0x94, 0xab, 0x8e, 0x9a, 0xa6, 0x01, 0xbe,
717            0x7a, 0x0f, 0x00, 0xbb, 0x60, 0x3b, 0x36, 0x50, 0x4a, 0x74, 0xdd, 0xc3, 0x67, 0x35,
718            0x9c, 0x8e, 0xa0, 0x7f, 0x5c, 0xcd, 0x50, 0x22, 0x77, 0x2c, 0xc1, 0x57, 0xe0, 0x0f,
719            0x54, 0x15, 0x63, 0x71, 0xe4, 0x01, 0x0b, 0xe1, 0xe6, 0xb7, 0x12, 0xa2, 0x35, 0x3e,
720            0x49, 0x07, 0x92, 0x9c, 0x40, 0x57, 0xd5, 0xba, 0xbe, 0xf8, 0x0d, 0xc0, 0x9f, 0xeb,
721            0xb3, 0xdc, 0x29, 0x34, 0xf4, 0x40, 0x48, 0x79, 0x5e, 0xef, 0x95, 0x4e, 0x99, 0x10,
722            0x6c, 0xb2, 0x9b, 0x1a, 0x8d, 0x93, 0x53, 0x69, 0xda, 0xec, 0xbb, 0x8b, 0xae, 0x45,
723            0x19, 0x2e, 0xfc, 0x3c, 0xed, 0xbc, 0x57, 0x31, 0x5d, 0x67, 0xec, 0x9e, 0xa8, 0x00,
724            0x0a, 0x00, 0x0d, 0xdc, 0xc0, 0x4c, 0xd7, 0x55, 0x6a, 0x94, 0xe8, 0xb4, 0x18, 0xdc,
725            0x3a, 0x8a, 0x00, 0xef, 0xb1, 0x28, 0xd4, 0xf7, 0x6f, 0x71, 0x43, 0x12, 0x47, 0xa9,
726            0x2e, 0x7a, 0x19, 0xa8, 0x33, 0xfc, 0x02, 0x21, 0x5d, 0x1f, 0xd6, 0x9e, 0x0e, 0x59,
727            0x6d, 0xa5, 0x31, 0xea, 0x58, 0x7a, 0xe2, 0xac, 0x2f, 0x36, 0xd2, 0x0f, 0x3b, 0x19,
728            0x33, 0x06, 0x0a, 0xd6, 0xef, 0x3e, 0x9d, 0x7d, 0x84, 0x75, 0xba, 0x01, 0x0e, 0xc7,
729            0x62, 0x16, 0x49, 0x49, 0x06, 0xae, 0xd8, 0xd8, 0x31, 0x0c, 0x31, 0xa5, 0xe4, 0xa5,
730            0x45, 0xea, 0x2a, 0xf8, 0xdb, 0xe3, 0x8e, 0xeb, 0x74, 0xa3, 0xd1, 0x4f, 0x07, 0x34,
731            0xdd, 0x2b, 0x1a, 0x21, 0xb9, 0x85, 0x0e, 0xa2, 0x0e, 0x6c, 0x2c, 0xa4, 0x22, 0x48,
732            0x78, 0x8b, 0xfb, 0x17, 0x43, 0x9d, 0x37, 0xab, 0xda, 0x25, 0xd7, 0x05, 0xb5, 0x68,
733            0xb2, 0x65, 0xb1, 0x13, 0xb9, 0x76, 0xc5, 0x00, 0x10, 0xc6, 0x1f, 0xe6, 0xeb, 0xea,
734            0x61, 0xf2, 0xca, 0xe8, 0x95, 0xc3, 0x34, 0x96, 0x50, 0x70, 0x48, 0x7d, 0x39, 0xab,
735            0x6b, 0xf0, 0x44, 0x28, 0x34, 0x0a, 0xf0, 0xf7, 0x69, 0x9f, 0xdd, 0xd3, 0xc0, 0x1e,
736            0x0c, 0x86, 0xda, 0xea, 0x9e, 0xb4, 0x49, 0x70, 0x12, 0x48, 0xa2, 0x4f, 0xa4, 0xc0,
737            0xff, 0x75, 0xfb, 0x60, 0x0b, 0x2c, 0x01, 0x34, 0xbd, 0x72, 0x17, 0x91, 0xf6, 0x67,
738            0x11, 0x6e, 0x42, 0x00, 0x11, 0x19, 0xb7, 0x9c, 0xaa, 0x25, 0x0e, 0x75, 0xda, 0x14,
739            0x82, 0xc7, 0xf4, 0x12, 0x68, 0x73, 0x08, 0xd1, 0x3e, 0xf7, 0x00, 0xf7, 0x26, 0xb9,
740            0x94, 0x17, 0xbb, 0x75, 0xae, 0x6d, 0xd1, 0x43, 0xfc, 0x61, 0x9f, 0x8c, 0x9c, 0x29,
741            0xc7, 0x3f, 0x99, 0x49, 0xaf, 0xfd, 0x16, 0x29, 0xcc, 0x28, 0x6a, 0x61, 0x91, 0x7e,
742            0xd7, 0x85, 0x37, 0x54, 0xa4, 0x67, 0x02, 0x92, 0x0b, 0x76, 0xcf, 0x90, 0xeb, 0x00,
743            0x12, 0xb0, 0xba, 0xb5, 0xe1, 0xa8, 0xb3, 0x21, 0xe9, 0x2f, 0x9d, 0x3d, 0xf9, 0x24,
744            0x30, 0x18, 0x3e, 0x48, 0x43, 0xe5, 0x7c, 0x6f, 0x8c, 0x15, 0xc2, 0x2d, 0x62, 0xb2,
745            0xf8, 0xe4, 0xb8, 0xcd, 0xc2, 0x75, 0x9f, 0x28, 0x54, 0xb8, 0xd1, 0x22, 0xac, 0xdb,
746            0x4b, 0x4d, 0x89, 0x28, 0xb8, 0x7d, 0xf4, 0x19, 0x9c, 0xc6, 0x83, 0x01, 0x1d, 0x2e,
747            0x9b, 0x7d, 0x41, 0xa9, 0x6d, 0x8b, 0x48, 0x0c, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00,
748            0x39, 0xc4, 0xba, 0x76, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
749            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
750            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x25, 0x64, 0xd2, 0xef,
751            0xd6, 0x08, 0x4d, 0xf0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
752            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x6f,
753            0x6b, 0x65, 0x6e, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 0x02, 0x00, 0x03, 0x00, 0x00,
754            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
756            0x09, 0x83,
757        ];
758
759        let vaa = Vaa {
760            version: 1,
761            guardian_set_index: 1,
762            signatures: vec![
763                Signature {
764                    index: 2,
765                    signature: [
766                        0x73, 0xaf, 0x3c, 0x2f, 0x55, 0x98, 0x90, 0x41, 0xb0, 0x06, 0x8a, 0x4e,
767                        0xae, 0xba, 0x8f, 0x88, 0x25, 0x10, 0x60, 0x21, 0x99, 0x6d, 0xe6, 0x14,
768                        0x39, 0x54, 0xc0, 0x6f, 0xc4, 0xcf, 0xad, 0x5c, 0x3f, 0x1a, 0xba, 0x6c,
769                        0xa9, 0x51, 0x18, 0x8e, 0x96, 0x2f, 0x11, 0x25, 0x1c, 0x25, 0xca, 0x98,
770                        0x62, 0x86, 0x85, 0xe2, 0xfc, 0x2b, 0x65, 0xec, 0x60, 0x94, 0x50, 0xcf,
771                        0xc4, 0xe6, 0x51, 0x12, 0x00,
772                    ],
773                },
774                Signature {
775                    index: 3,
776                    signature: [
777                        0x00, 0xc6, 0x2e, 0xb0, 0xde, 0x7a, 0xb3, 0xd0, 0x28, 0x92, 0x0f, 0x18,
778                        0xe1, 0x0d, 0xf7, 0xf2, 0xa0, 0x4d, 0x00, 0xeb, 0x88, 0xb8, 0x94, 0x0a,
779                        0x27, 0xbb, 0xce, 0x8c, 0xe6, 0x6c, 0x67, 0x52, 0x68, 0x82, 0xc9, 0x6c,
780                        0xc5, 0x0d, 0xd3, 0x81, 0xbd, 0xbf, 0xf3, 0x0b, 0xb6, 0x5b, 0x93, 0x47,
781                        0xca, 0xdf, 0xf0, 0x96, 0x76, 0x72, 0x90, 0x43, 0xaf, 0x60, 0xd6, 0x52,
782                        0xa0, 0xb9, 0x06, 0x30, 0x00,
783                    ],
784                },
785                Signature {
786                    index: 4,
787                    signature: [
788                        0xf0, 0x7b, 0x0f, 0xe6, 0xca, 0xb1, 0x8b, 0xe7, 0xae, 0x82, 0x7f, 0xe1,
789                        0x1c, 0xa8, 0x99, 0x2f, 0xf0, 0xb5, 0xa2, 0xa3, 0x2d, 0x65, 0xbe, 0x95,
790                        0x82, 0x31, 0xbf, 0x84, 0xcf, 0x6b, 0x14, 0xfb, 0x5e, 0xeb, 0x8a, 0x51,
791                        0xad, 0xe1, 0xc7, 0x0a, 0xa5, 0xb8, 0xb8, 0xcf, 0x83, 0xaf, 0xe3, 0xc2,
792                        0x2d, 0x34, 0x71, 0x48, 0x1b, 0xda, 0x38, 0x96, 0xea, 0x2a, 0x70, 0x46,
793                        0x9f, 0x96, 0x92, 0xb8, 0x00,
794                    ],
795                },
796                Signature {
797                    index: 5,
798                    signature: [
799                        0x74, 0xd4, 0x96, 0x72, 0x9d, 0xde, 0x6e, 0x19, 0x09, 0x59, 0xa1, 0x79,
800                        0x45, 0xe8, 0x7c, 0xd9, 0x5e, 0x23, 0xc1, 0x00, 0x47, 0xab, 0x2e, 0xef,
801                        0x5c, 0x7d, 0x0e, 0xc6, 0xf9, 0x12, 0x08, 0xc7, 0x27, 0x9d, 0x8a, 0x1b,
802                        0x1f, 0x4a, 0x60, 0x06, 0x9d, 0x25, 0x93, 0x2a, 0x67, 0xd6, 0x55, 0xf2,
803                        0xd0, 0xb4, 0x20, 0x59, 0x00, 0x3d, 0xe7, 0x5f, 0xd3, 0xca, 0x79, 0x92,
804                        0xfd, 0xd1, 0xb0, 0xd4, 0x01,
805                    ],
806                },
807                Signature {
808                    index: 6,
809                    signature: [
810                        0x51, 0xf0, 0x6a, 0xb6, 0xfd, 0xfd, 0x42, 0xf3, 0x23, 0x84, 0x0a, 0x81,
811                        0x8b, 0x38, 0xcf, 0xd1, 0xc9, 0x9d, 0x22, 0x36, 0x6c, 0x87, 0x79, 0x03,
812                        0xb9, 0x8d, 0xf4, 0x0b, 0xda, 0xf2, 0xa2, 0x04, 0x2e, 0xb8, 0xcd, 0x0e,
813                        0x59, 0xc4, 0x63, 0x7e, 0x6a, 0x80, 0xa1, 0x99, 0xb1, 0x10, 0x8c, 0xd7,
814                        0x65, 0x9b, 0xa8, 0x37, 0x0f, 0x6f, 0x94, 0x76, 0xb4, 0x79, 0x83, 0x98,
815                        0x54, 0xd8, 0xc1, 0xa6, 0x00,
816                    ],
817                },
818                Signature {
819                    index: 7,
820                    signature: [
821                        0x78, 0x4b, 0x37, 0xc6, 0x10, 0x3c, 0x75, 0x2c, 0xd9, 0x7a, 0x58, 0x6b,
822                        0xe8, 0xe1, 0xce, 0xff, 0x22, 0xa6, 0xe4, 0x88, 0x43, 0x32, 0x84, 0xff,
823                        0x31, 0xcd, 0x90, 0x8b, 0x5c, 0x7d, 0x87, 0xe2, 0x44, 0xda, 0x75, 0x16,
824                        0xd0, 0x7a, 0x0f, 0xa6, 0x92, 0x68, 0x4f, 0x82, 0x6e, 0x5e, 0x6c, 0x8b,
825                        0x45, 0x20, 0x04, 0x20, 0x6d, 0x6f, 0xe5, 0xba, 0xe4, 0x6a, 0xfb, 0x1c,
826                        0x21, 0x8c, 0xf5, 0x0d, 0x00,
827                    ],
828                },
829                Signature {
830                    index: 9,
831                    signature: [
832                        0x0b, 0x6c, 0xcc, 0xe6, 0x7e, 0xd5, 0x01, 0xcb, 0x20, 0xfb, 0x06, 0xde,
833                        0x76, 0xb9, 0x08, 0x3f, 0x13, 0x29, 0xad, 0x78, 0xd3, 0x84, 0x51, 0x7a,
834                        0x94, 0xab, 0x8e, 0x9a, 0xa6, 0x01, 0xbe, 0x7a, 0x0f, 0x00, 0xbb, 0x60,
835                        0x3b, 0x36, 0x50, 0x4a, 0x74, 0xdd, 0xc3, 0x67, 0x35, 0x9c, 0x8e, 0xa0,
836                        0x7f, 0x5c, 0xcd, 0x50, 0x22, 0x77, 0x2c, 0xc1, 0x57, 0xe0, 0x0f, 0x54,
837                        0x15, 0x63, 0x71, 0xe4, 0x01,
838                    ],
839                },
840                Signature {
841                    index: 11,
842                    signature: [
843                        0xe1, 0xe6, 0xb7, 0x12, 0xa2, 0x35, 0x3e, 0x49, 0x07, 0x92, 0x9c, 0x40,
844                        0x57, 0xd5, 0xba, 0xbe, 0xf8, 0x0d, 0xc0, 0x9f, 0xeb, 0xb3, 0xdc, 0x29,
845                        0x34, 0xf4, 0x40, 0x48, 0x79, 0x5e, 0xef, 0x95, 0x4e, 0x99, 0x10, 0x6c,
846                        0xb2, 0x9b, 0x1a, 0x8d, 0x93, 0x53, 0x69, 0xda, 0xec, 0xbb, 0x8b, 0xae,
847                        0x45, 0x19, 0x2e, 0xfc, 0x3c, 0xed, 0xbc, 0x57, 0x31, 0x5d, 0x67, 0xec,
848                        0x9e, 0xa8, 0x00, 0x0a, 0x00,
849                    ],
850                },
851                Signature {
852                    index: 13,
853                    signature: [
854                        0xdc, 0xc0, 0x4c, 0xd7, 0x55, 0x6a, 0x94, 0xe8, 0xb4, 0x18, 0xdc, 0x3a,
855                        0x8a, 0x00, 0xef, 0xb1, 0x28, 0xd4, 0xf7, 0x6f, 0x71, 0x43, 0x12, 0x47,
856                        0xa9, 0x2e, 0x7a, 0x19, 0xa8, 0x33, 0xfc, 0x02, 0x21, 0x5d, 0x1f, 0xd6,
857                        0x9e, 0x0e, 0x59, 0x6d, 0xa5, 0x31, 0xea, 0x58, 0x7a, 0xe2, 0xac, 0x2f,
858                        0x36, 0xd2, 0x0f, 0x3b, 0x19, 0x33, 0x06, 0x0a, 0xd6, 0xef, 0x3e, 0x9d,
859                        0x7d, 0x84, 0x75, 0xba, 0x01,
860                    ],
861                },
862                Signature {
863                    index: 14,
864                    signature: [
865                        0xc7, 0x62, 0x16, 0x49, 0x49, 0x06, 0xae, 0xd8, 0xd8, 0x31, 0x0c, 0x31,
866                        0xa5, 0xe4, 0xa5, 0x45, 0xea, 0x2a, 0xf8, 0xdb, 0xe3, 0x8e, 0xeb, 0x74,
867                        0xa3, 0xd1, 0x4f, 0x07, 0x34, 0xdd, 0x2b, 0x1a, 0x21, 0xb9, 0x85, 0x0e,
868                        0xa2, 0x0e, 0x6c, 0x2c, 0xa4, 0x22, 0x48, 0x78, 0x8b, 0xfb, 0x17, 0x43,
869                        0x9d, 0x37, 0xab, 0xda, 0x25, 0xd7, 0x05, 0xb5, 0x68, 0xb2, 0x65, 0xb1,
870                        0x13, 0xb9, 0x76, 0xc5, 0x00,
871                    ],
872                },
873                Signature {
874                    index: 16,
875                    signature: [
876                        0xc6, 0x1f, 0xe6, 0xeb, 0xea, 0x61, 0xf2, 0xca, 0xe8, 0x95, 0xc3, 0x34,
877                        0x96, 0x50, 0x70, 0x48, 0x7d, 0x39, 0xab, 0x6b, 0xf0, 0x44, 0x28, 0x34,
878                        0x0a, 0xf0, 0xf7, 0x69, 0x9f, 0xdd, 0xd3, 0xc0, 0x1e, 0x0c, 0x86, 0xda,
879                        0xea, 0x9e, 0xb4, 0x49, 0x70, 0x12, 0x48, 0xa2, 0x4f, 0xa4, 0xc0, 0xff,
880                        0x75, 0xfb, 0x60, 0x0b, 0x2c, 0x01, 0x34, 0xbd, 0x72, 0x17, 0x91, 0xf6,
881                        0x67, 0x11, 0x6e, 0x42, 0x00,
882                    ],
883                },
884                Signature {
885                    index: 17,
886                    signature: [
887                        0x19, 0xb7, 0x9c, 0xaa, 0x25, 0x0e, 0x75, 0xda, 0x14, 0x82, 0xc7, 0xf4,
888                        0x12, 0x68, 0x73, 0x08, 0xd1, 0x3e, 0xf7, 0x00, 0xf7, 0x26, 0xb9, 0x94,
889                        0x17, 0xbb, 0x75, 0xae, 0x6d, 0xd1, 0x43, 0xfc, 0x61, 0x9f, 0x8c, 0x9c,
890                        0x29, 0xc7, 0x3f, 0x99, 0x49, 0xaf, 0xfd, 0x16, 0x29, 0xcc, 0x28, 0x6a,
891                        0x61, 0x91, 0x7e, 0xd7, 0x85, 0x37, 0x54, 0xa4, 0x67, 0x02, 0x92, 0x0b,
892                        0x76, 0xcf, 0x90, 0xeb, 0x00,
893                    ],
894                },
895                Signature {
896                    index: 18,
897                    signature: [
898                        0xb0, 0xba, 0xb5, 0xe1, 0xa8, 0xb3, 0x21, 0xe9, 0x2f, 0x9d, 0x3d, 0xf9,
899                        0x24, 0x30, 0x18, 0x3e, 0x48, 0x43, 0xe5, 0x7c, 0x6f, 0x8c, 0x15, 0xc2,
900                        0x2d, 0x62, 0xb2, 0xf8, 0xe4, 0xb8, 0xcd, 0xc2, 0x75, 0x9f, 0x28, 0x54,
901                        0xb8, 0xd1, 0x22, 0xac, 0xdb, 0x4b, 0x4d, 0x89, 0x28, 0xb8, 0x7d, 0xf4,
902                        0x19, 0x9c, 0xc6, 0x83, 0x01, 0x1d, 0x2e, 0x9b, 0x7d, 0x41, 0xa9, 0x6d,
903                        0x8b, 0x48, 0x0c, 0xcc, 0x01,
904                    ],
905                },
906            ],
907            timestamp: 0,
908            nonce: 969_194_102,
909            emitter_chain: Chain::Solana,
910            emitter_address: GOVERNANCE_EMITTER,
911            sequence: 2_694_510_404_604_284_400,
912            consistency_level: 32,
913            payload: GovernancePacket {
914                chain: Chain::Terra,
915                action: Action::ContractUpgrade {
916                    new_contract: Address([
917                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
918                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
919                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x83,
920                    ]),
921                },
922            },
923        };
924
925        assert_eq!(buf.as_ref(), &serde_wormhole::to_vec(&vaa).unwrap());
926        assert_eq!(vaa, serde_wormhole::from_slice(&buf).unwrap());
927
928        let encoded = serde_json::to_string(&vaa).unwrap();
929        assert_eq!(vaa, serde_json::from_str(&encoded).unwrap());
930    }
931}