소스 검색

feat(solana): move as many things as possible to the sdk (#1602)

* Add

* Bump

* Cleanup

* Delete cargo expand

* cleanup
guibescos 1 년 전
부모
커밋
9230bae9c8

+ 5 - 5
target_chains/solana/Cargo.lock

@@ -1030,7 +1030,7 @@ dependencies = [
  "pyth-sdk",
  "pyth-sdk-solana",
  "pyth-solana-receiver",
- "pyth-solana-receiver-sdk 0.2.0",
+ "pyth-solana-receiver-sdk 0.3.0",
  "pythnet-sdk 2.1.0",
  "rand 0.8.5",
  "serde_wormhole",
@@ -3023,7 +3023,7 @@ dependencies = [
  "common-test-utils",
  "program-simulator",
  "pyth-solana-receiver",
- "pyth-solana-receiver-sdk 0.2.0",
+ "pyth-solana-receiver-sdk 0.3.0",
  "pythnet-sdk 2.1.0",
  "serde_wormhole",
  "solana-program",
@@ -3071,7 +3071,7 @@ dependencies = [
  "byteorder",
  "common-test-utils",
  "program-simulator",
- "pyth-solana-receiver-sdk 0.2.0",
+ "pyth-solana-receiver-sdk 0.3.0",
  "pythnet-sdk 2.1.0",
  "rand 0.8.5",
  "serde_wormhole",
@@ -3094,7 +3094,7 @@ dependencies = [
  "clap 3.2.23",
  "hex",
  "pyth-solana-receiver",
- "pyth-solana-receiver-sdk 0.2.0",
+ "pyth-solana-receiver-sdk 0.3.0",
  "pythnet-sdk 2.1.0",
  "serde_wormhole",
  "shellexpand",
@@ -3119,7 +3119,7 @@ dependencies = [
 
 [[package]]
 name = "pyth-solana-receiver-sdk"
-version = "0.2.0"
+version = "0.3.0"
 dependencies = [
  "anchor-lang",
  "hex",

+ 5 - 5
target_chains/solana/common_test_utils/src/lib.rs

@@ -4,11 +4,7 @@ use {
     program_simulator::ProgramSimulator,
     pyth_solana_receiver::{
         instruction::Initialize,
-        sdk::{
-            get_config_address,
-            get_guardian_set_address,
-            get_treasury_address,
-        },
+        sdk::get_guardian_set_address,
         ID,
     },
     pyth_solana_receiver_sdk::{
@@ -16,6 +12,10 @@ use {
             Config,
             DataSource,
         },
+        pda::{
+            get_config_address,
+            get_treasury_address,
+        },
         PYTH_PUSH_ORACLE_ID,
     },
     pythnet_sdk::test_utils::{

+ 1 - 1
target_chains/solana/programs/pyth-push-oracle/Cargo.toml

@@ -21,9 +21,9 @@ pythnet-sdk = { path = "../../../../pythnet/pythnet_sdk" }
 solana-program = { workspace = true }
 byteorder = "1.4.3"
 pyth-solana-receiver-sdk = { path = "../../pyth_solana_receiver_sdk"}
-pyth-solana-receiver = { path = "../pyth-solana-receiver", features = ["cpi"]}
 
 [dev-dependencies]
+pyth-solana-receiver = { path = "../pyth-solana-receiver", features = ["no-entrypoint"]}
 solana-sdk = { workspace = true }
 tokio = "1.14.1"
 program-simulator = { path = "../../program_simulator" }

+ 3 - 6
target_chains/solana/programs/pyth-push-oracle/src/lib.rs

@@ -1,12 +1,10 @@
 use {
     anchor_lang::prelude::*,
-    pyth_solana_receiver::{
+    pyth_solana_receiver_sdk::{
         cpi::accounts::PostUpdate,
+        price_update::PriceUpdateV2,
         program::PythSolanaReceiver,
         PostUpdateParams,
-    },
-    pyth_solana_receiver_sdk::{
-        price_update::PriceUpdateV2,
         PYTH_PUSH_ORACLE_ID,
     },
     pythnet_sdk::{
@@ -35,7 +33,6 @@ pub enum PushOracleError {
 }
 #[program]
 pub mod pyth_push_oracle {
-
     use super::*;
 
     pub fn update_price_feed(
@@ -94,7 +91,7 @@ pub mod pyth_push_oracle {
         // Only update the price feed if the message contains a newer price. Pushing a stale price
         // suceeds without changing the on-chain state.
         if next_timestamp > current_timestamp {
-            pyth_solana_receiver::cpi::post_update(cpi_context, params)?;
+            pyth_solana_receiver_sdk::cpi::post_update(cpi_context, params)?;
             {
                 let price_feed_account_data = ctx.accounts.price_feed_account.try_borrow_data()?;
                 let price_feed_account =

+ 2 - 2
target_chains/solana/programs/pyth-push-oracle/src/sdk.rs

@@ -10,7 +10,7 @@ use {
         system_program,
         InstructionData,
     },
-    pyth_solana_receiver::sdk::{
+    pyth_solana_receiver_sdk::pda::{
         get_config_address,
         get_treasury_address,
     },
@@ -39,7 +39,7 @@ impl accounts::UpdatePriceFeed {
             config: get_config_address(),
             treasury: get_treasury_address(treasury_id),
             price_feed_account: get_price_feed_address(shard_id, feed_id),
-            pyth_solana_receiver: pyth_solana_receiver::ID,
+            pyth_solana_receiver: pyth_solana_receiver_sdk::ID,
             system_program: system_program::ID,
         }
     }

+ 6 - 16
target_chains/solana/programs/pyth-solana-receiver/src/lib.rs

@@ -7,10 +7,16 @@ use {
             Config,
             DataSource,
         },
+        pda::{
+            CONFIG_SEED,
+            TREASURY_SEED,
+        },
         price_update::{
             PriceUpdateV2,
             VerificationLevel,
         },
+        PostUpdateAtomicParams,
+        PostUpdateParams,
     },
     pythnet_sdk::{
         accumulators::merkle::MerkleRoot,
@@ -250,9 +256,6 @@ pub mod pyth_solana_receiver {
     }
 }
 
-pub const CONFIG_SEED: &str = "config";
-pub const TREASURY_SEED: &str = "treasury";
-
 #[derive(Accounts)]
 #[instruction(initial_config : Config)]
 pub struct Initialize<'info> {
@@ -337,19 +340,6 @@ pub struct ReclaimRent<'info> {
     pub price_update_account: Account<'info, PriceUpdateV2>,
 }
 
-#[derive(Debug, AnchorSerialize, AnchorDeserialize, Clone)]
-pub struct PostUpdateAtomicParams {
-    pub vaa:                 Vec<u8>,
-    pub merkle_price_update: MerklePriceUpdate,
-    pub treasury_id:         u8,
-}
-
-#[derive(Debug, AnchorSerialize, AnchorDeserialize, Clone)]
-pub struct PostUpdateParams {
-    pub merkle_price_update: MerklePriceUpdate,
-    pub treasury_id:         u8,
-}
-
 fn deserialize_guardian_set_checked(
     account_info: &AccountInfo<'_>,
     wormhole: &Pubkey,

+ 11 - 18
target_chains/solana/programs/pyth-solana-receiver/src/sdk.rs

@@ -2,20 +2,24 @@ use {
     crate::{
         accounts,
         instruction,
-        PostUpdateAtomicParams,
-        PostUpdateParams,
-        CONFIG_SEED,
         ID,
-        TREASURY_SEED,
     },
     anchor_lang::{
         prelude::*,
         system_program,
         InstructionData,
     },
-    pyth_solana_receiver_sdk::config::{
-        Config,
-        DataSource,
+    pyth_solana_receiver_sdk::{
+        config::{
+            Config,
+            DataSource,
+        },
+        pda::{
+            get_config_address,
+            get_treasury_address,
+        },
+        PostUpdateAtomicParams,
+        PostUpdateParams,
     },
     pythnet_sdk::wire::v1::{
         AccumulatorUpdateData,
@@ -298,17 +302,6 @@ impl instruction::ReclaimRent {
     }
 }
 
-
-// There is one treasury for each u8 value
-// This is to load balance the write load
-pub fn get_treasury_address(treasury_id: u8) -> Pubkey {
-    Pubkey::find_program_address(&[TREASURY_SEED.as_ref(), &[treasury_id]], &ID).0
-}
-
-pub fn get_config_address() -> Pubkey {
-    Pubkey::find_program_address(&[CONFIG_SEED.as_ref()], &ID).0
-}
-
 pub fn get_guardian_set_address(wormhole_address: Pubkey, guardian_set_index: u32) -> Pubkey {
     Pubkey::find_program_address(
         &[

+ 6 - 4
target_chains/solana/programs/pyth-solana-receiver/tests/test_governance.rs

@@ -16,11 +16,13 @@ use {
             SetMinimumSignatures,
             SetWormholeAddress,
         },
-        sdk::get_config_address,
     },
-    pyth_solana_receiver_sdk::config::{
-        Config,
-        DataSource,
+    pyth_solana_receiver_sdk::{
+        config::{
+            Config,
+            DataSource,
+        },
+        pda::get_config_address,
     },
     pythnet_sdk::test_utils::SECONDARY_DATA_SOURCE,
     solana_program::{

+ 1 - 1
target_chains/solana/pyth_solana_receiver_sdk/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "pyth-solana-receiver-sdk"
-version = "0.2.0"
+version = "0.3.0"
 description = "SDK for the Pyth Solana Receiver program"
 authors = ["Pyth Data Association"]
 repository = "https://github.com/pyth-network/pyth-crosschain"

+ 170 - 0
target_chains/solana/pyth_solana_receiver_sdk/src/cpi/accounts.rs

@@ -0,0 +1,170 @@
+// This file was populated with the expanded macros of programs/pyth-solana-receiver/src/lib.rs
+
+pub struct PostUpdateAtomic<'info> {
+    pub payer:                anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    ///Instead we do the same steps in deserialize_guardian_set_checked.
+    pub guardian_set:         anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    pub config:               anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    pub treasury:             anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    ///The constraint is such that either the price_update_account is uninitialized or the write_authority is the write_authority.
+    ///Pubkey::default() is the SystemProgram on Solana and it can't sign so it's impossible that price_update_account.write_authority == Pubkey::default() once the account is initialized
+    pub price_update_account: anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    pub system_program:       anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    pub write_authority:      anchor_lang::solana_program::account_info::AccountInfo<'info>,
+}
+#[automatically_derived]
+impl<'info> anchor_lang::ToAccountMetas for PostUpdateAtomic<'info> {
+    fn to_account_metas(
+        &self,
+        is_signer: Option<bool>,
+    ) -> Vec<anchor_lang::solana_program::instruction::AccountMeta> {
+        let mut account_metas = vec![];
+        account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new(
+            anchor_lang::Key::key(&self.payer),
+            true,
+        ));
+        account_metas.push(
+            anchor_lang::solana_program::instruction::AccountMeta::new_readonly(
+                anchor_lang::Key::key(&self.guardian_set),
+                false,
+            ),
+        );
+        account_metas.push(
+            anchor_lang::solana_program::instruction::AccountMeta::new_readonly(
+                anchor_lang::Key::key(&self.config),
+                false,
+            ),
+        );
+        account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new(
+            anchor_lang::Key::key(&self.treasury),
+            false,
+        ));
+        account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new(
+            anchor_lang::Key::key(&self.price_update_account),
+            true,
+        ));
+        account_metas.push(
+            anchor_lang::solana_program::instruction::AccountMeta::new_readonly(
+                anchor_lang::Key::key(&self.system_program),
+                false,
+            ),
+        );
+        account_metas.push(
+            anchor_lang::solana_program::instruction::AccountMeta::new_readonly(
+                anchor_lang::Key::key(&self.write_authority),
+                true,
+            ),
+        );
+        account_metas
+    }
+}
+#[automatically_derived]
+impl<'info> anchor_lang::ToAccountInfos<'info> for PostUpdateAtomic<'info> {
+    fn to_account_infos(
+        &self,
+    ) -> Vec<anchor_lang::solana_program::account_info::AccountInfo<'info>> {
+        let mut account_infos = vec![];
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(&self.payer));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.guardian_set,
+        ));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(&self.config));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.treasury,
+        ));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.price_update_account,
+        ));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.system_program,
+        ));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.write_authority,
+        ));
+        account_infos
+    }
+}
+
+pub struct PostUpdate<'info> {
+    pub payer:                anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    pub encoded_vaa:          anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    pub config:               anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    pub treasury:             anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    ///The constraint is such that either the price_update_account is uninitialized or the write_authority is the write_authority.
+    ///Pubkey::default() is the SystemProgram on Solana and it can't sign so it's impossible that price_update_account.write_authority == Pubkey::default() once the account is initialized
+    pub price_update_account: anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    pub system_program:       anchor_lang::solana_program::account_info::AccountInfo<'info>,
+    pub write_authority:      anchor_lang::solana_program::account_info::AccountInfo<'info>,
+}
+#[automatically_derived]
+impl<'info> anchor_lang::ToAccountMetas for PostUpdate<'info> {
+    fn to_account_metas(
+        &self,
+        is_signer: Option<bool>,
+    ) -> Vec<anchor_lang::solana_program::instruction::AccountMeta> {
+        let mut account_metas = vec![];
+        account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new(
+            anchor_lang::Key::key(&self.payer),
+            true,
+        ));
+        account_metas.push(
+            anchor_lang::solana_program::instruction::AccountMeta::new_readonly(
+                anchor_lang::Key::key(&self.encoded_vaa),
+                false,
+            ),
+        );
+        account_metas.push(
+            anchor_lang::solana_program::instruction::AccountMeta::new_readonly(
+                anchor_lang::Key::key(&self.config),
+                false,
+            ),
+        );
+        account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new(
+            anchor_lang::Key::key(&self.treasury),
+            false,
+        ));
+        account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new(
+            anchor_lang::Key::key(&self.price_update_account),
+            true,
+        ));
+        account_metas.push(
+            anchor_lang::solana_program::instruction::AccountMeta::new_readonly(
+                anchor_lang::Key::key(&self.system_program),
+                false,
+            ),
+        );
+        account_metas.push(
+            anchor_lang::solana_program::instruction::AccountMeta::new_readonly(
+                anchor_lang::Key::key(&self.write_authority),
+                true,
+            ),
+        );
+        account_metas
+    }
+}
+#[automatically_derived]
+impl<'info> anchor_lang::ToAccountInfos<'info> for PostUpdate<'info> {
+    fn to_account_infos(
+        &self,
+    ) -> Vec<anchor_lang::solana_program::account_info::AccountInfo<'info>> {
+        let mut account_infos = vec![];
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(&self.payer));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.encoded_vaa,
+        ));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(&self.config));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.treasury,
+        ));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.price_update_account,
+        ));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.system_program,
+        ));
+        account_infos.extend(anchor_lang::ToAccountInfos::to_account_infos(
+            &self.write_authority,
+        ));
+        account_infos
+    }
+}

+ 57 - 0
target_chains/solana/pyth_solana_receiver_sdk/src/cpi/mod.rs

@@ -0,0 +1,57 @@
+use {
+    self::accounts::{
+        PostUpdate,
+        PostUpdateAtomic,
+    },
+    crate::{
+        PostUpdateAtomicParams,
+        PostUpdateParams,
+    },
+    anchor_lang::prelude::*,
+};
+
+pub mod accounts;
+
+// This implementation comes from the expanded macros of programs/pyth-solana-receiver/src/lib.rs
+pub fn post_update<'info>(
+    ctx: anchor_lang::context::CpiContext<'_, '_, '_, 'info, PostUpdate<'info>>,
+    params: PostUpdateParams,
+) -> anchor_lang::Result<()> {
+    let ix = {
+        let mut ix_data = AnchorSerialize::try_to_vec(&params)
+            .map_err(|_| anchor_lang::error::ErrorCode::InstructionDidNotSerialize)?;
+        let mut data = [133, 95, 207, 175, 11, 79, 118, 44].to_vec();
+        data.append(&mut ix_data);
+        let accounts = ctx.to_account_metas(None);
+        anchor_lang::solana_program::instruction::Instruction {
+            program_id: crate::ID,
+            accounts,
+            data,
+        }
+    };
+    let acc_infos = ctx.to_account_infos();
+    anchor_lang::solana_program::program::invoke_signed(&ix, &acc_infos, ctx.signer_seeds)
+        .map_or_else(|e| Err(Into::into(e)), |_| Ok(()))
+}
+
+// This implementation comes from the expanded macros of programs/pyth-solana-receiver/src/lib.rs
+pub fn post_update_atomic<'info>(
+    ctx: anchor_lang::context::CpiContext<'_, '_, '_, 'info, PostUpdateAtomic<'info>>,
+    params: PostUpdateAtomicParams,
+) -> anchor_lang::Result<()> {
+    let ix = {
+        let mut ix_data = AnchorSerialize::try_to_vec(&params)
+            .map_err(|_| anchor_lang::error::ErrorCode::InstructionDidNotSerialize)?;
+        let mut data = [49, 172, 84, 192, 175, 180, 52, 234].to_vec();
+        data.append(&mut ix_data);
+        let accounts = ctx.to_account_metas(None);
+        anchor_lang::solana_program::instruction::Instruction {
+            program_id: crate::ID,
+            accounts,
+            data,
+        }
+    };
+    let acc_infos = ctx.to_account_infos();
+    anchor_lang::solana_program::program::invoke_signed(&ix, &acc_infos, ctx.signer_seeds)
+        .map_or_else(|e| Err(Into::into(e)), |_| Ok(()))
+}

+ 21 - 1
target_chains/solana/pyth_solana_receiver_sdk/src/lib.rs

@@ -1,5 +1,9 @@
 use {
-    anchor_lang::declare_id,
+    anchor_lang::{
+        declare_id,
+        prelude::*,
+    },
+    pythnet_sdk::wire::v1::MerklePriceUpdate,
     solana_program::{
         pubkey,
         pubkey::Pubkey,
@@ -7,9 +11,25 @@ use {
 };
 
 pub mod config;
+pub mod cpi;
 pub mod error;
+pub mod pda;
 pub mod price_update;
+pub mod program;
 
 declare_id!("rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ");
 
 pub const PYTH_PUSH_ORACLE_ID: Pubkey = pubkey!("pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT");
+
+#[derive(Debug, AnchorSerialize, AnchorDeserialize, Clone)]
+pub struct PostUpdateAtomicParams {
+    pub vaa:                 Vec<u8>,
+    pub merkle_price_update: MerklePriceUpdate,
+    pub treasury_id:         u8,
+}
+
+#[derive(Debug, AnchorSerialize, AnchorDeserialize, Clone)]
+pub struct PostUpdateParams {
+    pub merkle_price_update: MerklePriceUpdate,
+    pub treasury_id:         u8,
+}

+ 17 - 0
target_chains/solana/pyth_solana_receiver_sdk/src/pda.rs

@@ -0,0 +1,17 @@
+use {
+    crate::ID,
+    anchor_lang::prelude::*,
+};
+
+pub const CONFIG_SEED: &str = "config";
+pub const TREASURY_SEED: &str = "treasury";
+
+// There is one treasury for each u8 value
+// This is to load balance the write load
+pub fn get_treasury_address(treasury_id: u8) -> Pubkey {
+    Pubkey::find_program_address(&[TREASURY_SEED.as_ref(), &[treasury_id]], &ID).0
+}
+
+pub fn get_config_address() -> Pubkey {
+    Pubkey::find_program_address(&[CONFIG_SEED.as_ref()], &ID).0
+}

+ 9 - 0
target_chains/solana/pyth_solana_receiver_sdk/src/program.rs

@@ -0,0 +1,9 @@
+use anchor_lang::prelude::*;
+
+pub struct PythSolanaReceiver;
+
+impl Id for PythSolanaReceiver {
+    fn id() -> Pubkey {
+        crate::ID
+    }
+}