|
|
@@ -1,57 +1,31 @@
|
|
|
-pub mod attestation_cfg;
|
|
|
pub mod cli;
|
|
|
|
|
|
use std::{
|
|
|
fs::File,
|
|
|
- path::{
|
|
|
- Path,
|
|
|
- PathBuf,
|
|
|
- },
|
|
|
};
|
|
|
|
|
|
-use borsh::{
|
|
|
- BorshDeserialize,
|
|
|
- BorshSerialize,
|
|
|
-};
|
|
|
use clap::Clap;
|
|
|
use log::{
|
|
|
debug,
|
|
|
error,
|
|
|
info,
|
|
|
- warn,
|
|
|
LevelFilter,
|
|
|
};
|
|
|
use solana_client::rpc_client::RpcClient;
|
|
|
use solana_program::{
|
|
|
- hash::Hash,
|
|
|
- instruction::{
|
|
|
- AccountMeta,
|
|
|
- Instruction,
|
|
|
- },
|
|
|
pubkey::Pubkey,
|
|
|
- system_program,
|
|
|
- sysvar::{
|
|
|
- clock,
|
|
|
- rent,
|
|
|
- },
|
|
|
};
|
|
|
use solana_sdk::{
|
|
|
commitment_config::CommitmentConfig,
|
|
|
signature::read_keypair_file,
|
|
|
- transaction::Transaction,
|
|
|
};
|
|
|
use solana_transaction_status::UiTransactionEncoding;
|
|
|
use solitaire::{
|
|
|
processors::seeded::Seeded,
|
|
|
- AccountState,
|
|
|
- Derive,
|
|
|
- Info,
|
|
|
+ ErrBox,
|
|
|
};
|
|
|
use solitaire_client::{
|
|
|
- AccEntry,
|
|
|
Keypair,
|
|
|
- SolSigner,
|
|
|
- ToInstruction,
|
|
|
};
|
|
|
|
|
|
use cli::{
|
|
|
@@ -59,33 +33,14 @@ use cli::{
|
|
|
Cli,
|
|
|
};
|
|
|
|
|
|
-use bridge::{
|
|
|
- accounts::{
|
|
|
- Bridge,
|
|
|
- FeeCollector,
|
|
|
- Sequence,
|
|
|
- SequenceDerivationData,
|
|
|
- },
|
|
|
- types::ConsistencyLevel,
|
|
|
- CHAIN_ID_SOLANA,
|
|
|
-};
|
|
|
-
|
|
|
use pyth2wormhole::{
|
|
|
attest::{
|
|
|
P2WEmitter,
|
|
|
- P2W_MAX_BATCH_SIZE,
|
|
|
},
|
|
|
- config::P2WConfigAccount,
|
|
|
- initialize::InitializeAccounts,
|
|
|
- set_config::SetConfigAccounts,
|
|
|
- types::PriceAttestation,
|
|
|
- AttestData,
|
|
|
- Pyth2WormholeConfig,
|
|
|
};
|
|
|
|
|
|
-use crate::attestation_cfg::AttestationConfig;
|
|
|
|
|
|
-pub type ErrBox = Box<dyn std::error::Error>;
|
|
|
+use pyth2wormhole_client::*;
|
|
|
|
|
|
pub const SEQNO_PREFIX: &'static str = "Program log: Sequence: ";
|
|
|
|
|
|
@@ -106,7 +61,7 @@ fn main() -> Result<(), ErrBox> {
|
|
|
pyth_owner_addr,
|
|
|
wh_prog,
|
|
|
} => {
|
|
|
- let tx = handle_init(
|
|
|
+ let tx = gen_init_tx(
|
|
|
payer,
|
|
|
p2w_addr,
|
|
|
owner_addr,
|
|
|
@@ -116,13 +71,16 @@ fn main() -> Result<(), ErrBox> {
|
|
|
)?;
|
|
|
rpc_client.send_and_confirm_transaction_with_spinner(&tx)?;
|
|
|
}
|
|
|
+ Action::GetConfig => {
|
|
|
+ println!("{:?}", get_config_account(&rpc_client, &p2w_addr)?);
|
|
|
+ }
|
|
|
Action::SetConfig {
|
|
|
ref owner,
|
|
|
new_owner_addr,
|
|
|
new_wh_prog,
|
|
|
new_pyth_owner_addr,
|
|
|
} => {
|
|
|
- let tx = handle_set_config(
|
|
|
+ let tx = gen_set_config_tx(
|
|
|
payer,
|
|
|
p2w_addr,
|
|
|
read_keypair_file(&*shellexpand::tilde(&owner))?,
|
|
|
@@ -146,81 +104,6 @@ fn main() -> Result<(), ErrBox> {
|
|
|
|
|
|
Ok(())
|
|
|
}
|
|
|
-
|
|
|
-fn handle_init(
|
|
|
- payer: Keypair,
|
|
|
- p2w_addr: Pubkey,
|
|
|
- new_owner_addr: Pubkey,
|
|
|
- wh_prog: Pubkey,
|
|
|
- pyth_owner_addr: Pubkey,
|
|
|
- latest_blockhash: Hash,
|
|
|
-) -> Result<Transaction, ErrBox> {
|
|
|
- use AccEntry::*;
|
|
|
-
|
|
|
- let payer_pubkey = payer.pubkey();
|
|
|
-
|
|
|
- let accs = InitializeAccounts {
|
|
|
- payer: Signer(payer),
|
|
|
- new_config: Derived(p2w_addr),
|
|
|
- };
|
|
|
-
|
|
|
- let config = Pyth2WormholeConfig {
|
|
|
- max_batch_size: P2W_MAX_BATCH_SIZE,
|
|
|
- owner: new_owner_addr,
|
|
|
- wh_prog: wh_prog,
|
|
|
- pyth_owner: pyth_owner_addr,
|
|
|
- };
|
|
|
- let ix_data = (pyth2wormhole::instruction::Instruction::Initialize, config);
|
|
|
-
|
|
|
- let (ix, signers) = accs.to_ix(p2w_addr, ix_data.try_to_vec()?.as_slice())?;
|
|
|
-
|
|
|
- let tx_signed = Transaction::new_signed_with_payer::<Vec<&Keypair>>(
|
|
|
- &[ix],
|
|
|
- Some(&payer_pubkey),
|
|
|
- signers.iter().collect::<Vec<_>>().as_ref(),
|
|
|
- latest_blockhash,
|
|
|
- );
|
|
|
- Ok(tx_signed)
|
|
|
-}
|
|
|
-
|
|
|
-fn handle_set_config(
|
|
|
- payer: Keypair,
|
|
|
- p2w_addr: Pubkey,
|
|
|
- owner: Keypair,
|
|
|
- new_owner_addr: Pubkey,
|
|
|
- new_wh_prog: Pubkey,
|
|
|
- new_pyth_owner_addr: Pubkey,
|
|
|
- latest_blockhash: Hash,
|
|
|
-) -> Result<Transaction, ErrBox> {
|
|
|
- use AccEntry::*;
|
|
|
-
|
|
|
- let payer_pubkey = payer.pubkey();
|
|
|
-
|
|
|
- let accs = SetConfigAccounts {
|
|
|
- payer: Signer(payer),
|
|
|
- current_owner: Signer(owner),
|
|
|
- config: Derived(p2w_addr),
|
|
|
- };
|
|
|
-
|
|
|
- let config = Pyth2WormholeConfig {
|
|
|
- max_batch_size: P2W_MAX_BATCH_SIZE,
|
|
|
- owner: new_owner_addr,
|
|
|
- wh_prog: new_wh_prog,
|
|
|
- pyth_owner: new_pyth_owner_addr,
|
|
|
- };
|
|
|
- let ix_data = (pyth2wormhole::instruction::Instruction::SetConfig, config);
|
|
|
-
|
|
|
- let (ix, signers) = accs.to_ix(p2w_addr, ix_data.try_to_vec()?.as_slice())?;
|
|
|
-
|
|
|
- let tx_signed = Transaction::new_signed_with_payer::<Vec<&Keypair>>(
|
|
|
- &[ix],
|
|
|
- Some(&payer_pubkey),
|
|
|
- signers.iter().collect::<Vec<_>>().as_ref(),
|
|
|
- latest_blockhash,
|
|
|
- );
|
|
|
- Ok(tx_signed)
|
|
|
-}
|
|
|
-
|
|
|
fn handle_attest(
|
|
|
rpc_client: &RpcClient, // Needed for reading Pyth account data
|
|
|
payer: Keypair,
|
|
|
@@ -232,18 +115,7 @@ fn handle_attest(
|
|
|
|
|
|
info!("Using emitter addr {}", emitter_addr);
|
|
|
|
|
|
- let p2w_config_addr = P2WConfigAccount::<{ AccountState::Initialized }>::key(None, &p2w_addr);
|
|
|
-
|
|
|
- let config = Pyth2WormholeConfig::try_from_slice(
|
|
|
- rpc_client.get_account_data(&p2w_config_addr)?.as_slice(),
|
|
|
- )?;
|
|
|
-
|
|
|
- let seq_addr = Sequence::key(
|
|
|
- &SequenceDerivationData {
|
|
|
- emitter_key: &emitter_addr,
|
|
|
- },
|
|
|
- &config.wh_prog,
|
|
|
- );
|
|
|
+ let config = get_config_account(rpc_client, &p2w_addr)?;
|
|
|
|
|
|
// Read the current max batch size from the contract's settings
|
|
|
let max_batch_size = config.max_batch_size;
|
|
|
@@ -277,7 +149,6 @@ fn handle_attest(
|
|
|
.enumerate()
|
|
|
{
|
|
|
let batch_no = idx + 1;
|
|
|
- let sym_msg_keypair = Keypair::new();
|
|
|
info!(
|
|
|
"Batch {}/{} contents: {:?}",
|
|
|
batch_no,
|
|
|
@@ -291,87 +162,19 @@ fn handle_attest(
|
|
|
.collect::<Vec<_>>()
|
|
|
);
|
|
|
|
|
|
- let mut sym_metas_vec: Vec<_> = symbols
|
|
|
- .iter()
|
|
|
- .map(|s| {
|
|
|
- vec![
|
|
|
- AccountMeta::new_readonly(s.product_addr, false),
|
|
|
- AccountMeta::new_readonly(s.price_addr, false),
|
|
|
- ]
|
|
|
- })
|
|
|
- .flatten()
|
|
|
- .collect();
|
|
|
-
|
|
|
- // Align to max batch size with null accounts
|
|
|
- let mut blank_accounts =
|
|
|
- vec![
|
|
|
- AccountMeta::new_readonly(Pubkey::new_from_array([0u8; 32]), false);
|
|
|
- 2 * (max_batch_size as usize - symbols.len())
|
|
|
- ];
|
|
|
- sym_metas_vec.append(&mut blank_accounts);
|
|
|
-
|
|
|
- // Arrange Attest accounts
|
|
|
- let mut acc_metas = vec![
|
|
|
- // payer
|
|
|
- AccountMeta::new(payer.pubkey(), true),
|
|
|
- // system_program
|
|
|
- AccountMeta::new_readonly(system_program::id(), false),
|
|
|
- // config
|
|
|
- AccountMeta::new_readonly(p2w_config_addr, false),
|
|
|
- ];
|
|
|
-
|
|
|
- // Insert max_batch_size metas
|
|
|
- acc_metas.append(&mut sym_metas_vec);
|
|
|
-
|
|
|
- // Continue with other pyth2wormhole accounts
|
|
|
- let mut acc_metas_remainder = vec![
|
|
|
- // clock
|
|
|
- AccountMeta::new_readonly(clock::id(), false),
|
|
|
- // wh_prog
|
|
|
- AccountMeta::new_readonly(config.wh_prog, false),
|
|
|
- // wh_bridge
|
|
|
- AccountMeta::new(
|
|
|
- Bridge::<{ AccountState::Initialized }>::key(None, &config.wh_prog),
|
|
|
- false,
|
|
|
- ),
|
|
|
- // wh_message
|
|
|
- AccountMeta::new(sym_msg_keypair.pubkey(), true),
|
|
|
- // wh_emitter
|
|
|
- AccountMeta::new_readonly(emitter_addr, false),
|
|
|
- // wh_sequence
|
|
|
- AccountMeta::new(seq_addr, false),
|
|
|
- // wh_fee_collector
|
|
|
- AccountMeta::new(FeeCollector::<'_>::key(None, &config.wh_prog), false),
|
|
|
- AccountMeta::new_readonly(rent::id(), false),
|
|
|
- ];
|
|
|
-
|
|
|
- acc_metas.append(&mut acc_metas_remainder);
|
|
|
-
|
|
|
- let ix_data = (
|
|
|
- pyth2wormhole::instruction::Instruction::Attest,
|
|
|
- AttestData {
|
|
|
- consistency_level: ConsistencyLevel::Finalized,
|
|
|
- },
|
|
|
- );
|
|
|
-
|
|
|
- let ix = Instruction::new_with_bytes(p2w_addr, ix_data.try_to_vec()?.as_slice(), acc_metas);
|
|
|
-
|
|
|
// Execute the transaction, obtain the resulting sequence
|
|
|
- // number. The and_then() calls enforce error handling
|
|
|
- // location near loop end.
|
|
|
+ // number. The and_then() calls enforce permissible error
|
|
|
+ // handling location near loop end.
|
|
|
let res = rpc_client
|
|
|
.get_latest_blockhash()
|
|
|
+ .map_err(|e| -> ErrBox { e.into() })
|
|
|
.and_then(|latest_blockhash| {
|
|
|
- let tx_signed = Transaction::new_signed_with_payer::<Vec<&Keypair>>(
|
|
|
- &[ix],
|
|
|
- Some(&payer.pubkey()),
|
|
|
- &vec![&payer, &sym_msg_keypair],
|
|
|
- latest_blockhash,
|
|
|
- );
|
|
|
- rpc_client.send_and_confirm_transaction_with_spinner(&tx_signed)
|
|
|
+ let tx_signed = gen_attest_tx(p2w_addr, &config, &payer, symbols, &Keypair::new(), latest_blockhash)?;
|
|
|
+
|
|
|
+ rpc_client.send_and_confirm_transaction_with_spinner(&tx_signed).map_err(|e| -> ErrBox { e.into() })
|
|
|
})
|
|
|
- .and_then(|sig| rpc_client.get_transaction(&sig, UiTransactionEncoding::Json))
|
|
|
- .map_err(|e| -> ErrBox { e.into() })
|
|
|
+ .and_then(|sig| rpc_client.get_transaction(&sig, UiTransactionEncoding::Json).map_err(|e| -> ErrBox { e.into() })
|
|
|
+ )
|
|
|
.and_then(|this_tx| {
|
|
|
this_tx
|
|
|
.transaction
|
|
|
@@ -413,7 +216,13 @@ fn handle_attest(
|
|
|
if errors.len() > 0 {
|
|
|
let err_list = errors.join("\n");
|
|
|
|
|
|
- Err(format!("{} of {} batches failed:\n{}", errors.len(), batch_count, err_list).into())
|
|
|
+ Err(format!(
|
|
|
+ "{} of {} batches failed:\n{}",
|
|
|
+ errors.len(),
|
|
|
+ batch_count,
|
|
|
+ err_list
|
|
|
+ )
|
|
|
+ .into())
|
|
|
} else {
|
|
|
Ok(())
|
|
|
}
|