gmsol/pyth/pull_oracle/wormhole/
mod.rs

1use std::{future::Future, ops::Deref, sync::Arc};
2
3use anchor_client::{
4    solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction},
5    ClientError,
6};
7use gmsol_solana_utils::{
8    compute_budget::ComputeBudget, program::Program, transaction_builder::TransactionBuilder,
9};
10
11mod accounts;
12mod instruction;
13
14/// Wormhole Core Bridge Program Address.
15pub const WORMHOLE_PROGRAM_ID: Pubkey = Pubkey::new_from_array([
16    241, 11, 180, 229, 13, 86, 253, 161, 61, 254, 31, 50, 155, 141, 57, 61, 210, 74, 1, 69, 145,
17    225, 131, 22, 151, 148, 13, 124, 52, 163, 141, 221,
18]);
19
20/// The start offset of the VAA bytes.
21pub const VAA_START: u64 = 46;
22
23/// Seed for guardian set account.
24pub const GUARDIAN_SET_SEED: &[u8] = b"GuardianSet";
25
26/// `init_encoded_vaa` compute budget.
27pub const INIT_ENCODED_VAA_COMPUTE_BUDGET: u32 = 3_000;
28
29/// `write_encoded_vaa` compute budget.
30pub const WRITE_ENCODED_VAA_COMPUTE_BUDGET: u32 = 3_000;
31
32/// `verify_encoded_vaa_v1` compute budget.
33pub const VERIFY_ENCODED_VAA_V1_COMPUTE_BUDGET: u32 = 350_000;
34
35/// `close_encoded_vaa` compute budget.
36pub const CLOSE_ENCODED_VAA_COMPUTE_BUDGET: u32 = 3_000;
37
38/// Find PDA for guardian set.
39pub fn find_guardian_set_pda(guardian_set_index: i32) -> (Pubkey, u8) {
40    Pubkey::find_program_address(
41        &[GUARDIAN_SET_SEED, &guardian_set_index.to_be_bytes()],
42        &WORMHOLE_PROGRAM_ID,
43    )
44}
45
46/// Wormhole Ops.
47pub trait WormholeOps<C> {
48    /// Create and initialize an encoded vaa account.
49    fn create_encoded_vaa(
50        &self,
51        encoded_vaa: Keypair,
52        vaa_buffer_len: u64,
53    ) -> impl Future<Output = crate::Result<TransactionBuilder<C, Pubkey>>>;
54
55    /// Write to encoded vaa account.
56    fn write_encoded_vaa(
57        &self,
58        draft_vaa: &Pubkey,
59        index: u32,
60        data: &[u8],
61    ) -> TransactionBuilder<C>;
62
63    /// Verify encoded vaa account.
64    fn verify_encoded_vaa_v1(
65        &self,
66        draft_vaa: &Pubkey,
67        guardian_set_index: i32,
68    ) -> TransactionBuilder<C>;
69
70    /// Close encoded vaa account.
71    fn close_encoded_vaa(&self, encoded_vaa: &Pubkey) -> TransactionBuilder<C>;
72}
73
74impl<S, C> WormholeOps<C> for Program<C>
75where
76    C: Deref<Target = S> + Clone,
77    S: Signer,
78{
79    async fn create_encoded_vaa(
80        &self,
81        encoded_vaa: Keypair,
82        vaa_buffer_len: u64,
83    ) -> crate::Result<TransactionBuilder<C, Pubkey>> {
84        let space = vaa_buffer_len + VAA_START;
85        let lamports = self
86            .rpc()
87            .get_minimum_balance_for_rent_exemption(space as usize)
88            .await
89            .map_err(ClientError::from)?;
90        let request = self
91            .transaction()
92            .pre_instruction(system_instruction::create_account(
93                &self.payer(),
94                &encoded_vaa.pubkey(),
95                lamports,
96                space,
97                self.id(),
98            ))
99            .anchor_args(instruction::InitEncodedVaa {})
100            .anchor_accounts(accounts::InitEncodedVaa {
101                write_authority: self.payer(),
102                encoded_vaa: encoded_vaa.pubkey(),
103            })
104            .output(encoded_vaa.pubkey())
105            .owned_signer(Arc::new(encoded_vaa))
106            .compute_budget(ComputeBudget::default().with_limit(INIT_ENCODED_VAA_COMPUTE_BUDGET));
107        Ok(request)
108    }
109
110    fn write_encoded_vaa(
111        &self,
112        draft_vaa: &Pubkey,
113        index: u32,
114        data: &[u8],
115    ) -> TransactionBuilder<C> {
116        self.transaction()
117            .anchor_args(instruction::WriteEncodedVaa {
118                index,
119                data: data.to_owned(),
120            })
121            .anchor_accounts(accounts::WriteEncodedVaa {
122                write_authority: self.payer(),
123                draft_vaa: *draft_vaa,
124            })
125            .compute_budget(ComputeBudget::default().with_limit(WRITE_ENCODED_VAA_COMPUTE_BUDGET))
126    }
127
128    fn verify_encoded_vaa_v1(
129        &self,
130        draft_vaa: &Pubkey,
131        guardian_set_index: i32,
132    ) -> TransactionBuilder<C> {
133        self.transaction()
134            .anchor_args(instruction::VerifyEncodedVaaV1 {})
135            .anchor_accounts(accounts::VerifyEncodedVaaV1 {
136                write_authority: self.payer(),
137                draft_vaa: *draft_vaa,
138                guardian_set: find_guardian_set_pda(guardian_set_index).0,
139            })
140            .compute_budget(
141                ComputeBudget::default().with_limit(VERIFY_ENCODED_VAA_V1_COMPUTE_BUDGET),
142            )
143    }
144
145    fn close_encoded_vaa(&self, encoded_vaa: &Pubkey) -> TransactionBuilder<C> {
146        self.transaction()
147            .anchor_args(instruction::CloseEncodedVaa {})
148            .anchor_accounts(accounts::CloseEncodedVaa {
149                write_authority: self.payer(),
150                encoded_vaa: *encoded_vaa,
151            })
152            .compute_budget(ComputeBudget::default().with_limit(CLOSE_ENCODED_VAA_COMPUTE_BUDGET))
153    }
154}