pythnet_sdk/
wormhole.rs

1//! This module provides Wormhole primitives.
2//!
3//! Wormhole does not provide an SDK for working with Solana versions of Wormhole related types, so
4//! we clone the definitions from the Solana contracts here and adapt them to Pyth purposes. This
5//! allows us to emit and parse messages through Wormhole.
6use {
7    crate::Pubkey,
8    borsh::{BorshDeserialize, BorshSerialize},
9    serde::{Deserialize, Serialize},
10    std::{
11        io::{Error, ErrorKind::InvalidData, Write},
12        ops::{Deref, DerefMut},
13    },
14};
15
16#[repr(transparent)]
17#[derive(Default, PartialEq, Debug)]
18pub struct PostedMessageUnreliableData {
19    pub message: MessageData,
20}
21
22#[derive(
23    Debug, Default, BorshSerialize, BorshDeserialize, Clone, Serialize, Deserialize, PartialEq,
24)]
25pub struct MessageData {
26    pub vaa_version: u8,
27    pub consistency_level: u8,
28    pub vaa_time: u32,
29    pub vaa_signature_account: Pubkey,
30    pub submission_time: u32,
31    pub nonce: u32,
32    pub sequence: u64,
33    pub emitter_chain: u16,
34    pub emitter_address: [u8; 32],
35    pub payload: Vec<u8>,
36}
37
38impl BorshSerialize for PostedMessageUnreliableData {
39    fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
40        writer.write_all(b"msu")?;
41        BorshSerialize::serialize(&self.message, writer)
42    }
43}
44
45impl BorshDeserialize for PostedMessageUnreliableData {
46    fn deserialize_reader<R: std::io::prelude::Read>(reader: &mut R) -> std::io::Result<Self> {
47        let mut magic = [0u8; 3];
48        reader.read_exact(&mut magic)?;
49
50        let expected = b"msu";
51        if &magic != expected {
52            return Err(Error::new(
53                InvalidData,
54                format!("Magic mismatch. Expected {expected:?} but got {magic:?}"),
55            ));
56        };
57        Ok(PostedMessageUnreliableData {
58            message: <MessageData as BorshDeserialize>::deserialize_reader(reader)?,
59        })
60    }
61}
62
63impl Deref for PostedMessageUnreliableData {
64    type Target = MessageData;
65    fn deref(&self) -> &Self::Target {
66        &self.message
67    }
68}
69
70impl DerefMut for PostedMessageUnreliableData {
71    fn deref_mut(&mut self) -> &mut Self::Target {
72        &mut self.message
73    }
74}
75
76impl Clone for PostedMessageUnreliableData {
77    fn clone(&self) -> Self {
78        PostedMessageUnreliableData {
79            message: self.message.clone(),
80        }
81    }
82}
83
84#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize)]
85pub struct AccumulatorSequenceTracker {
86    pub sequence: u64,
87}
88
89#[test]
90fn test_borsh_roundtrip() {
91    let post_message_unreliable_data = PostedMessageUnreliableData {
92        message: MessageData {
93            vaa_version: 1,
94            consistency_level: 2,
95            vaa_time: 3,
96            vaa_signature_account: [4u8; 32],
97            submission_time: 5,
98            nonce: 6,
99            sequence: 7,
100            emitter_chain: 8,
101            emitter_address: [9u8; 32],
102            payload: vec![10u8; 32],
103        },
104    };
105
106    let encoded = borsh::to_vec(&post_message_unreliable_data).unwrap();
107
108    let decoded = PostedMessageUnreliableData::try_from_slice(encoded.as_slice()).unwrap();
109    assert_eq!(decoded, post_message_unreliable_data);
110}