lib.rs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. pub mod attestation_cfg;
  2. use borsh::{
  3. BorshDeserialize,
  4. BorshSerialize,
  5. };
  6. use solana_client::rpc_client::RpcClient;
  7. use solana_program::{
  8. hash::Hash,
  9. instruction::{
  10. AccountMeta,
  11. Instruction,
  12. },
  13. pubkey::Pubkey,
  14. system_program,
  15. sysvar::{
  16. clock,
  17. rent,
  18. },
  19. };
  20. use solana_sdk::transaction::Transaction;
  21. use solitaire::{
  22. processors::seeded::Seeded,
  23. AccountState,
  24. ErrBox,
  25. };
  26. use solitaire_client::{
  27. AccEntry,
  28. Keypair,
  29. SolSigner,
  30. ToInstruction,
  31. };
  32. use bridge::{
  33. accounts::{
  34. Bridge,
  35. FeeCollector,
  36. Sequence,
  37. SequenceDerivationData,
  38. },
  39. types::ConsistencyLevel,
  40. };
  41. use p2w_sdk::P2WEmitter;
  42. use pyth2wormhole::{
  43. attest::P2W_MAX_BATCH_SIZE,
  44. config::P2WConfigAccount,
  45. initialize::InitializeAccounts,
  46. set_config::SetConfigAccounts,
  47. AttestData,
  48. Pyth2WormholeConfig,
  49. };
  50. pub use attestation_cfg::{
  51. AttestationConfig,
  52. P2WSymbol,
  53. };
  54. pub fn gen_init_tx(
  55. payer: Keypair,
  56. p2w_addr: Pubkey,
  57. new_owner_addr: Pubkey,
  58. wh_prog: Pubkey,
  59. pyth_owner_addr: Pubkey,
  60. latest_blockhash: Hash,
  61. ) -> Result<Transaction, ErrBox> {
  62. use AccEntry::*;
  63. let payer_pubkey = payer.pubkey();
  64. let accs = InitializeAccounts {
  65. payer: Signer(payer),
  66. new_config: Derived(p2w_addr),
  67. };
  68. let config = Pyth2WormholeConfig {
  69. max_batch_size: P2W_MAX_BATCH_SIZE,
  70. owner: new_owner_addr,
  71. wh_prog: wh_prog,
  72. pyth_owner: pyth_owner_addr,
  73. };
  74. let ix_data = (pyth2wormhole::instruction::Instruction::Initialize, config);
  75. let (ix, signers) = accs.to_ix(p2w_addr, ix_data.try_to_vec()?.as_slice())?;
  76. let tx_signed = Transaction::new_signed_with_payer::<Vec<&Keypair>>(
  77. &[ix],
  78. Some(&payer_pubkey),
  79. signers.iter().collect::<Vec<_>>().as_ref(),
  80. latest_blockhash,
  81. );
  82. Ok(tx_signed)
  83. }
  84. pub fn gen_set_config_tx(
  85. payer: Keypair,
  86. p2w_addr: Pubkey,
  87. owner: Keypair,
  88. new_owner_addr: Pubkey,
  89. new_wh_prog: Pubkey,
  90. new_pyth_owner_addr: Pubkey,
  91. latest_blockhash: Hash,
  92. ) -> Result<Transaction, ErrBox> {
  93. use AccEntry::*;
  94. let payer_pubkey = payer.pubkey();
  95. let accs = SetConfigAccounts {
  96. payer: Signer(payer),
  97. current_owner: Signer(owner),
  98. config: Derived(p2w_addr),
  99. };
  100. let config = Pyth2WormholeConfig {
  101. max_batch_size: P2W_MAX_BATCH_SIZE,
  102. owner: new_owner_addr,
  103. wh_prog: new_wh_prog,
  104. pyth_owner: new_pyth_owner_addr,
  105. };
  106. let ix_data = (pyth2wormhole::instruction::Instruction::SetConfig, config);
  107. let (ix, signers) = accs.to_ix(p2w_addr, ix_data.try_to_vec()?.as_slice())?;
  108. let tx_signed = Transaction::new_signed_with_payer::<Vec<&Keypair>>(
  109. &[ix],
  110. Some(&payer_pubkey),
  111. signers.iter().collect::<Vec<_>>().as_ref(),
  112. latest_blockhash,
  113. );
  114. Ok(tx_signed)
  115. }
  116. /// Get the current config account data for given p2w program address
  117. pub fn get_config_account(
  118. rpc_client: &RpcClient,
  119. p2w_addr: &Pubkey,
  120. ) -> Result<Pyth2WormholeConfig, ErrBox> {
  121. let p2w_config_addr = P2WConfigAccount::<{ AccountState::Initialized }>::key(None, p2w_addr);
  122. let config = Pyth2WormholeConfig::try_from_slice(
  123. rpc_client.get_account_data(&p2w_config_addr)?.as_slice(),
  124. )?;
  125. Ok(config)
  126. }
  127. /// Generate an Instruction for making the attest() contract
  128. /// call.
  129. pub fn gen_attest_tx(
  130. p2w_addr: Pubkey,
  131. p2w_config: &Pyth2WormholeConfig, // Must be fresh, not retrieved inside to keep side effects away
  132. payer: &Keypair,
  133. symbols: &[P2WSymbol],
  134. wh_msg: &Keypair,
  135. latest_blockhash: Hash,
  136. ) -> Result<Transaction, ErrBox> {
  137. let emitter_addr = P2WEmitter::key(None, &p2w_addr);
  138. let seq_addr = Sequence::key(
  139. &SequenceDerivationData {
  140. emitter_key: &emitter_addr,
  141. },
  142. &p2w_config.wh_prog,
  143. );
  144. let p2w_config_addr = P2WConfigAccount::<{ AccountState::Initialized }>::key(None, &p2w_addr);
  145. if symbols.len() > p2w_config.max_batch_size as usize {
  146. return Err(format!(
  147. "Expected up to {} symbols for batch, {} were found",
  148. p2w_config.max_batch_size,
  149. symbols.len()
  150. )
  151. .into());
  152. }
  153. // Initial attest() accounts
  154. let mut acc_metas = vec![
  155. // payer
  156. AccountMeta::new(payer.pubkey(), true),
  157. // system_program
  158. AccountMeta::new_readonly(system_program::id(), false),
  159. // config
  160. AccountMeta::new_readonly(p2w_config_addr, false),
  161. ];
  162. // Batch contents and padding if applicable
  163. let mut padded_symbols = {
  164. let mut not_padded: Vec<_> = symbols
  165. .iter()
  166. .map(|s| {
  167. vec![
  168. AccountMeta::new_readonly(s.product_addr, false),
  169. AccountMeta::new_readonly(s.price_addr, false),
  170. ]
  171. })
  172. .flatten()
  173. .collect();
  174. // Align to max batch size with null accounts
  175. let mut padding_accounts =
  176. vec![
  177. AccountMeta::new_readonly(Pubkey::new_from_array([0u8; 32]), false);
  178. 2 * (p2w_config.max_batch_size as usize - symbols.len())
  179. ];
  180. not_padded.append(&mut padding_accounts);
  181. not_padded
  182. };
  183. acc_metas.append(&mut padded_symbols);
  184. // Continue with other pyth2wormhole accounts
  185. let mut acc_metas_remainder = vec![
  186. // clock
  187. AccountMeta::new_readonly(clock::id(), false),
  188. // wh_prog
  189. AccountMeta::new_readonly(p2w_config.wh_prog, false),
  190. // wh_bridge
  191. AccountMeta::new(
  192. Bridge::<{ AccountState::Initialized }>::key(None, &p2w_config.wh_prog),
  193. false,
  194. ),
  195. // wh_message
  196. AccountMeta::new(wh_msg.pubkey(), true),
  197. // wh_emitter
  198. AccountMeta::new_readonly(emitter_addr, false),
  199. // wh_sequence
  200. AccountMeta::new(seq_addr, false),
  201. // wh_fee_collector
  202. AccountMeta::new(FeeCollector::<'_>::key(None, &p2w_config.wh_prog), false),
  203. AccountMeta::new_readonly(rent::id(), false),
  204. ];
  205. acc_metas.append(&mut acc_metas_remainder);
  206. let ix_data = (
  207. pyth2wormhole::instruction::Instruction::Attest,
  208. AttestData {
  209. consistency_level: ConsistencyLevel::Finalized,
  210. },
  211. );
  212. let ix = Instruction::new_with_bytes(p2w_addr, ix_data.try_to_vec()?.as_slice(), acc_metas);
  213. let tx_signed = Transaction::new_signed_with_payer::<Vec<&Keypair>>(
  214. &[ix],
  215. Some(&payer.pubkey()),
  216. &vec![&payer, &wh_msg],
  217. latest_blockhash,
  218. );
  219. Ok(tx_signed)
  220. }