[solana-receiver-cli] Add logic to receive VAAs with the new Wormhole receiver (#1184)

* Checkpoint

* Checkpoint

* Cleanup

* More cleanup

* Cleanup

* Should work

* Rename

* New receiver post-vaa

* Rename legacy

* Checkpoint

* ADd compute units

* Revert htis file

* Rename

* Comments
This commit is contained in:
guibescos 2023-12-15 10:33:17 +07:00 committed by GitHub
parent f78301d019
commit 7bf41c40e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 191 additions and 210 deletions

View File

@ -690,7 +690,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
dependencies = [
"borsh-derive 0.10.3",
"hashbrown 0.13.2",
"hashbrown 0.12.3",
]
[[package]]
@ -3073,6 +3073,7 @@ dependencies = [
"anchor-client",
"anyhow",
"base64 0.13.1",
"borsh 0.9.3",
"byteorder",
"cfg-if",
"clap 3.2.23",
@ -3084,8 +3085,8 @@ dependencies = [
"shellexpand",
"solana-client",
"solana-sdk",
"wormhole-anchor-sdk",
"wormhole-core",
"wormhole-core-bridge-solana",
"wormhole-sdk",
"wormhole-solana",
]
@ -3457,6 +3458,22 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "ruint"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e1574d439643c8962edf612a888e7cc5581bcdf36cb64e6bc88466b03b2daa"
dependencies = [
"ruint-macro",
"thiserror",
]
[[package]]
name = "ruint-macro"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09"
[[package]]
name = "rustc-demangle"
version = "0.1.22"
@ -6233,6 +6250,36 @@ dependencies = [
"thiserror",
]
[[package]]
name = "wormhole-core-bridge-solana"
version = "0.0.1-alpha.3"
source = "git+https://github.com/guibescos/wormhole?branch=variable-sigs#84ddd45906abf14f1e0ac3b80556c15904301fb6"
dependencies = [
"anchor-lang",
"cfg-if",
"hex",
"ruint",
"solana-program",
"wormhole-io",
"wormhole-raw-vaas",
]
[[package]]
name = "wormhole-io"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4965f46f7a99debe3c2cf9337c6e3eb7068da348aecf074a3e35686937f25c65"
[[package]]
name = "wormhole-raw-vaas"
version = "0.0.1-alpha.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cb59754ad91d99c0e3d7d159fffcbb4087c18a1c13b1b2a945775635ef9bd03"
dependencies = [
"ruint",
"ruint-macro",
]
[[package]]
name = "wormhole-sdk"
version = "0.1.0"

View File

@ -5,8 +5,8 @@ edition = "2021"
[features]
default = ["mainnet"]
mainnet = ["wormhole-anchor-sdk/mainnet", "pyth-solana-receiver/mainnet"]
devnet = ["wormhole-anchor-sdk/solana-devnet", "pyth-solana-receiver/devnet"]
mainnet = ["pyth-solana-receiver/mainnet"]
devnet = ["pyth-solana-receiver/devnet"]
[dependencies]
@ -25,6 +25,7 @@ byteorder = "1.4.3"
serde = "1.0.152"
wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", tag = "v2.17.1" }
serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", tag = "v2.17.1"}
wormhole-anchor-sdk = { version = "0.1.0-alpha.2" , default-features = false }
cfg-if = "1.0.0"
hex = "0.4.3"
borsh = "0.9.3" # Old version of borsh needed for wormhole-solana
wormhole-core-bridge-solana = {git = "https://github.com/guibescos/wormhole", branch = "variable-sigs"}

View File

@ -35,10 +35,10 @@ pub struct Cli {
#[derive(Subcommand, Debug)]
pub enum Action {
#[clap(about = "Verify, post and receive the price VAA on solana")]
PostAndReceiveVAA {
#[clap(short = 'v', long, help = "Price VAA from Pythnet")]
vaa: String,
#[clap(about = "Post a price update from Hermes to Solana")]
PostPriceUpdate {
#[clap(short = 'p', long, help = "Payload from Hermes")]
payload: String,
},
#[clap(
about = "Initialize a wormhole receiver contract by sequentially replaying the guardian set updates"

View File

@ -1,25 +1,22 @@
#![deny(warnings)]
pub mod cli;
pub mod cli;
use {
anchor_client::anchor_lang::{
prelude::*,
AnchorDeserialize,
InstructionData,
ToAccountMetas,
},
anyhow::Result,
borsh::BorshDeserialize,
clap::Parser,
cli::{
Action,
Cli,
},
pythnet_sdk::wire::{
to_vec,
v1::{
AccumulatorUpdateData,
Proof,
},
pythnet_sdk::wire::v1::{
AccumulatorUpdateData,
MerklePriceUpdate,
Proof,
},
serde_wormhole::RawMessage,
solana_client::{
@ -28,15 +25,22 @@ use {
},
solana_sdk::{
commitment_config::CommitmentConfig,
compute_budget::ComputeBudgetInstruction,
instruction::Instruction,
pubkey::Pubkey,
rent::Rent,
signature::{
read_keypair_file,
Keypair,
},
signer::Signer,
system_instruction,
transaction::Transaction,
},
wormhole_anchor_sdk::wormhole::BridgeData,
wormhole_core_bridge_solana::{
processor::WriteEncodedVaaArgs,
state::EncodedVaa,
},
wormhole_sdk::{
vaa::{
Body,
@ -53,9 +57,9 @@ use {
PostVAAData,
},
Account,
Config as WormholeConfig,
GuardianSet as WormholeSolanaGuardianSet,
VAA as WormholeSolanaVAA,
Config as BridgeConfig,
GuardianSet,
VAA as LegacyPostedVaa,
},
};
@ -64,39 +68,6 @@ const UPGRADE_GUARDIAN_SET_VAA_1 : &str = "010000000001007ac31b282c2aeeeb37f3385
const UPGRADE_GUARDIAN_SET_VAA_2 : &str = "01000000010d0012e6b39c6da90c5dfd3c228edbb78c7a4c97c488ff8a346d161a91db067e51d638c17216f368aa9bdf4836b8645a98018ca67d2fec87d769cabfdf2406bf790a0002ef42b288091a670ef3556596f4f47323717882881eaf38e03345078d07a156f312b785b64dae6e9a87e3d32872f59cb1931f728cecf511762981baf48303668f0103cef2616b84c4e511ff03329e0853f1bd7ee9ac5ba71d70a4d76108bddf94f69c2a8a84e4ee94065e8003c334e899184943634e12043d0dda78d93996da073d190104e76d166b9dac98f602107cc4b44ac82868faf00b63df7d24f177aa391e050902413b71046434e67c770b19aecdf7fce1d1435ea0be7262e3e4c18f50ddc8175c0105d9450e8216d741e0206a50f93b750a47e0a258b80eb8fed1314cc300b3d905092de25cd36d366097b7103ae2d184121329ba3aa2d7c6cc53273f11af14798110010687477c8deec89d36a23e7948feb074df95362fc8dcbd8ae910ac556a1dee1e755c56b9db5d710c940938ed79bc1895a3646523a58bc55f475a23435a373ecfdd0107fb06734864f79def4e192497362513171530daea81f07fbb9f698afe7e66c6d44db21323144f2657d4a5386a954bb94eef9f64148c33aef6e477eafa2c5c984c01088769e82216310d1827d9bd48645ec23e90de4ef8a8de99e2d351d1df318608566248d80cdc83bdcac382b3c30c670352be87f9069aab5037d0b747208eae9c650109e9796497ff9106d0d1c62e184d83716282870cef61a1ee13d6fc485b521adcce255c96f7d1bca8d8e7e7d454b65783a830bddc9d94092091a268d311ecd84c26010c468c9fb6d41026841ff9f8d7368fa309d4dbea3ea4bbd2feccf94a92cc8a20a226338a8e2126cd16f70eaf15b4fc9be2c3fa19def14e071956a605e9d1ac4162010e23fcb6bd445b7c25afb722250c1acbc061ed964ba9de1326609ae012acdfb96942b2a102a2de99ab96327859a34a2b49a767dbdb62e0a1fb26af60fe44fd496a00106bb0bac77ac68b347645f2fb1ad789ea9bd76fb9b2324f25ae06f97e65246f142df717f662e73948317182c62ce87d79c73def0dba12e5242dfc038382812cfe00126da03c5e56cb15aeeceadc1e17a45753ab4dc0ec7bf6a75ca03143ed4a294f6f61bc3f478a457833e43084ecd7c985bf2f55a55f168aac0e030fc49e845e497101626e9d9a5d9e343f00010000000000000000000000000000000000000000000000000000000000000004c1759167c43f501c2000000000000000000000000000000000000000000000000000000000436f7265020000000000021358cc3ae5c097b213ce3c81979e1b9f9570746aa5ff6cb952589bde862c25ef4392132fb9d4a42157114de8460193bdf3a2fcf81f86a09765f4762fd1107a0086b32d7a0977926a205131d8731d39cbeb8c82b2fd82faed2711d59af0f2499d16e726f6b211b39756c042441be6d8650b69b54ebe715e234354ce5b4d348fb74b958e8966e2ec3dbd4958a7cd66b9590e1c41e0b226937bf9217d1d67fd4e91f574a3bf913953d695260d88bc1aa25a4eee363ef0000ac0076727b35fbea2dac28fee5ccb0fea768eaf45ced136b9d9e24903464ae889f5c8a723fc14f93124b7c738843cbb89e864c862c38cddcccf95d2cc37a4dc036a8d232b48f62cdd4731412f4890da798f6896a3331f64b48c12d1d57fd9cbe7081171aa1be1d36cafe3867910f99c09e347899c19c38192b6e7387ccd768277c17dab1b7a5027c0b3cf178e21ad2e77ae06711549cfbb1f9c7a9d8096e85e1487f35515d02a92753504a8d75471b9f49edb6fbebc898f403e4773e95feb15e80c9a99c8348d";
const UPGRADE_GUARDIAN_SET_VAA_3 : &str = "01000000020d00ce45474d9e1b1e7790a2d210871e195db53a70ffd6f237cfe70e2686a32859ac43c84a332267a8ef66f59719cf91cc8df0101fd7c36aa1878d5139241660edc0010375cc906156ae530786661c0cd9aef444747bc3d8d5aa84cac6a6d2933d4e1a031cffa30383d4af8131e929d9f203f460b07309a647d6cd32ab1cc7724089392c000452305156cfc90343128f97e499311b5cae174f488ff22fbc09591991a0a73d8e6af3afb8a5968441d3ab8437836407481739e9850ad5c95e6acfcc871e951bc30105a7956eefc23e7c945a1966d5ddbe9e4be376c2f54e45e3d5da88c2f8692510c7429b1ea860ae94d929bd97e84923a18187e777aa3db419813a80deb84cc8d22b00061b2a4f3d2666608e0aa96737689e3ba5793810ff3a52ff28ad57d8efb20967735dc5537a2e43ef10f583d144c12a1606542c207f5b79af08c38656d3ac40713301086b62c8e130af3411b3c0d91b5b50dcb01ed5f293963f901fc36e7b0e50114dce203373b32eb45971cef8288e5d928d0ed51cd86e2a3006b0af6a65c396c009080009e93ab4d2c8228901a5f4525934000b2c26d1dc679a05e47fdf0ff3231d98fbc207103159ff4116df2832eea69b38275283434e6cd4a4af04d25fa7a82990b707010aa643f4cf615dfff06ffd65830f7f6cf6512dabc3690d5d9e210fdc712842dc2708b8b2c22e224c99280cd25e5e8bfb40e3d1c55b8c41774e287c1e2c352aecfc010b89c1e85faa20a30601964ccc6a79c0ae53cfd26fb10863db37783428cd91390a163346558239db3cd9d420cfe423a0df84c84399790e2e308011b4b63e6b8015010ca31dcb564ac81a053a268d8090e72097f94f366711d0c5d13815af1ec7d47e662e2d1bde22678113d15963da100b668ba26c0c325970d07114b83c5698f46097010dc9fda39c0d592d9ed92cd22b5425cc6b37430e236f02d0d1f8a2ef45a00bde26223c0a6eb363c8b25fd3bf57234a1d9364976cefb8360e755a267cbbb674b39501108db01e444ab1003dd8b6c96f8eb77958b40ba7a85fefecf32ad00b7a47c0ae7524216262495977e09c0989dd50f280c21453d3756843608eacd17f4fdfe47600001261025228ef5af837cb060bcd986fcfa84ccef75b3fa100468cfd24e7fadf99163938f3b841a33496c2706d0208faab088bd155b2e20fd74c625bb1cc8c43677a0163c53c409e0c5dfa000100000000000000000000000000000000000000000000000000000000000000046c5a054d7833d1e42000000000000000000000000000000000000000000000000000000000436f7265020000000000031358cc3ae5c097b213ce3c81979e1b9f9570746aa5ff6cb952589bde862c25ef4392132fb9d4a42157114de8460193bdf3a2fcf81f86a09765f4762fd1107a0086b32d7a0977926a205131d8731d39cbeb8c82b2fd82faed2711d59af0f2499d16e726f6b211b39756c042441be6d8650b69b54ebe715e234354ce5b4d348fb74b958e8966e2ec3dbd4958a7cd15e7caf07c4e3dc8e7c469f92c8cd88fb8005a2074a3bf913953d695260d88bc1aa25a4eee363ef0000ac0076727b35fbea2dac28fee5ccb0fea768eaf45ced136b9d9e24903464ae889f5c8a723fc14f93124b7c738843cbb89e864c862c38cddcccf95d2cc37a4dc036a8d232b48f62cdd4731412f4890da798f6896a3331f64b48c12d1d57fd9cbe7081171aa1be1d36cafe3867910f99c09e347899c19c38192b6e7387ccd768277c17dab1b7a5027c0b3cf178e21ad2e77ae06711549cfbb1f9c7a9d8096e85e1487f35515d02a92753504a8d75471b9f49edb6fbebc898f403e4773e95feb15e80c9a99c8348d";
// Note: this is a reimplementation of the GuardianSet from wormhole_solana
// because the wormhole_solana crate does uses an older versions of the dependencies.
// This can be removed once the GuardianSet is added to the wormhole_anchor_sdk
#[derive(Default, AnchorSerialize, AnchorDeserialize, Clone, PartialEq, Eq)]
pub struct GuardianSet {
/// Index representing an incrementing version number for this guardian set.
pub index: u32,
/// ETH style public keys
pub keys: Vec<[u8; 20]>,
/// Timestamp representing the time this guardian became active.
pub creation_time: u32,
/// Expiration time when VAAs issued by this set are no longer valid.
pub expiration_time: u32,
}
impl AccountDeserialize for GuardianSet {
fn try_deserialize_unchecked(
buf: &mut &[u8],
) -> anchor_client::anchor_lang::prelude::Result<Self> {
Self::deserialize(buf).map_err(Into::into)
}
}
impl AccountSerialize for GuardianSet {
}
impl Owner for GuardianSet {
fn owner() -> Pubkey {
wormhole_anchor_sdk::wormhole::program::Wormhole::id()
}
}
fn main() -> Result<()> {
let cli = Cli::parse();
let Cli {
@ -107,146 +78,16 @@ fn main() -> Result<()> {
} = cli;
match action {
Action::PostAndReceiveVAA {
vaa: accumulator_update_data_str,
} => {
let wormhole = wormhole_anchor_sdk::wormhole::program::id();
Action::PostPriceUpdate { payload } => {
let rpc_client = RpcClient::new(url);
let payer =
read_keypair_file(&*shellexpand::tilde(&keypair)).expect("Keypair not found");
println!("[1/5] Decode the AccumulatorUpdateData");
//TODO: refactor the various steps below
let accumulator_update_data_bytes: Vec<u8> =
base64::decode(accumulator_update_data_str)?;
let accumulator_update_data =
AccumulatorUpdateData::try_from_slice(accumulator_update_data_bytes.as_slice())?;
let (vaa, _) = deserialize_accumulator_update_data(&payload)?;
match &accumulator_update_data.proof {
Proof::WormholeMerkle { vaa, updates } => {
let parsed_vaa: Vaa<&RawMessage> =
serde_wormhole::from_slice(vaa.as_ref()).unwrap();
let (header, body): (Header, Body<&RawMessage>) = parsed_vaa.into();
println!("[2/5] Get wormhole guardian set configuration");
let wormhole_config = WormholeConfig::key(&wormhole, ());
let wormhole_config_data = BridgeData::try_from_slice(
&rpc_client.get_account_data(&wormhole_config)?,
)?;
let guardian_set = Pubkey::find_program_address(
&[
b"GuardianSet",
&wormhole_config_data.guardian_set_index.to_be_bytes(),
],
&wormhole,
)
.0;
let guardian_set_data =
GuardianSet::try_from_slice(&rpc_client.get_account_data(&guardian_set)?)?;
let payer = read_keypair_file(&*shellexpand::tilde(&keypair))
.expect("Keypair not found");
let vaa_hash = body.digest().unwrap().hash;
let vaa_pubkey = WormholeSolanaVAA::key(&wormhole, vaa_hash);
let _vaa_account = match rpc_client.get_account_data(&vaa_pubkey) {
Ok(account_data) => {
println!("[3/5] VAA already posted on solana. Skipping verifying signatures step");
println!("[4/5] VAA already posted on solana. Skipping posting the VAA data onto a solana account using pyth-solana-receiver::PostAccumulatorUpdateVaa");
Some(account_data)
}
Err(_) => {
println!("[3/5] Invoke wormhole on solana to verify the signatures on the VAA");
let signature_set_keypair = Keypair::new();
println!("signature_set_pubkey: {}", signature_set_keypair.pubkey());
let verify_txs = verify_signatures_txs(
vaa.as_ref(),
WormholeSolanaGuardianSet {
index: guardian_set_data.index,
keys: guardian_set_data.keys,
creation_time: guardian_set_data.creation_time,
expiration_time: guardian_set_data.expiration_time,
},
wormhole,
payer.pubkey(),
wormhole_config_data.guardian_set_index,
signature_set_keypair.pubkey(),
)?;
for tx in verify_txs {
process_transaction(
&rpc_client,
tx,
&vec![&payer, &signature_set_keypair],
)?;
}
println!("[4/5] Post the VAA data onto a solana account");
let post_vaa_data = PostVAAData {
version: header.version,
guardian_set_index: header.guardian_set_index,
timestamp: body.timestamp,
nonce: body.nonce,
emitter_chain: body.emitter_chain.into(),
emitter_address: body.emitter_address.0,
sequence: body.sequence,
consistency_level: body.consistency_level,
payload: body.payload.to_vec(),
};
process_transaction(
&rpc_client,
vec![post_vaa(
wormhole,
payer.pubkey(),
signature_set_keypair.pubkey(),
post_vaa_data,
)?],
&vec![&payer],
)?;
rpc_client.get_account_data(&vaa_pubkey).ok()
}
};
println!("[5/5] Post updates from AccumulatorUpdateData and use the PostedVAA on solana using pyth-solana-receiver::PostUpdates");
// TODO need to figure out max number of updates that can be sent in 1 txn
// update_bytes_len: 288 (1 price feed)
let update_bytes = updates
.iter()
.map(|u| to_vec::<_, byteorder::BE>(u).unwrap())
.collect::<Vec<_>>();
let update_bytes_len: usize = update_bytes
.iter()
.map(|u| u.len())
.collect::<Vec<usize>>()
.iter()
.sum();
println!("update_bytes_len: {}", update_bytes_len);
let post_updates_accounts = pyth_solana_receiver::accounts::PostUpdates {
payer: payer.pubkey(),
posted_vaa: vaa_pubkey,
}
.to_account_metas(None);
let post_updates_ix_data = pyth_solana_receiver::instruction::PostUpdates {
price_updates: update_bytes,
}
.data();
let post_updates_ix = Instruction::new_with_bytes(
pyth_solana_receiver::ID,
&post_updates_ix_data,
post_updates_accounts,
);
println!("Sending txn with PostUpdates ix");
process_transaction(&rpc_client, vec![post_updates_ix], &vec![&payer])?;
}
}
process_write_encoded_vaa(&rpc_client, &vaa, wormhole, &payer)?;
}
Action::InitializeWormholeReceiver {} => {
let rpc_client = RpcClient::new(url);
let payer =
@ -289,6 +130,17 @@ fn main() -> Result<()> {
Ok(())
}
pub fn deserialize_accumulator_update_data(
payload: &str,
) -> Result<(Vec<u8>, Vec<MerklePriceUpdate>)> {
let payload_bytes: Vec<u8> = base64::decode(payload)?;
let accumulator_update_data = AccumulatorUpdateData::try_from_slice(payload_bytes.as_slice())?;
match accumulator_update_data.proof {
Proof::WormholeMerkle { vaa, updates } => return Ok((vaa.as_ref().to_vec(), updates)),
}
}
pub fn process_upgrade_guardian_set(
rpc_client: &RpcClient,
vaa: &[u8],
@ -297,7 +149,7 @@ pub fn process_upgrade_guardian_set(
legacy_guardian_set: bool,
) -> Result<()> {
let posted_vaa =
process_post_vaa(rpc_client, vaa, wormhole, payer, legacy_guardian_set).unwrap();
process_legacy_post_vaa(rpc_client, vaa, wormhole, payer, legacy_guardian_set).unwrap();
let parsed_vaa: Vaa<&RawMessage> = serde_wormhole::from_slice(vaa).unwrap();
let (header, body): (Header, Body<&RawMessage>) = parsed_vaa.into();
let guardian_set_index_old = header.guardian_set_index;
@ -331,7 +183,10 @@ fn deserialize_guardian_set(buf: &mut &[u8], legacy_guardian_set: bool) -> Resul
Ok(guardian_set)
}
pub fn process_post_vaa(
/**
* This function posts a VAA to Solana using the legacy way, this way is still used for governance messages like guardian set updates
*/
pub fn process_legacy_post_vaa(
rpc_client: &RpcClient,
vaa: &[u8],
wormhole: Pubkey,
@ -341,19 +196,12 @@ pub fn process_post_vaa(
let parsed_vaa: Vaa<&RawMessage> = serde_wormhole::from_slice(vaa).unwrap();
let (header, body): (Header, Body<&RawMessage>) = parsed_vaa.into();
let wormhole_config = WormholeConfig::key(&wormhole, ());
let wormhole_config = BridgeConfig::key(&wormhole, ());
let wormhole_config_data =
BridgeData::try_from_slice(&rpc_client.get_account_data(&wormhole_config)?)?;
BridgeConfig::try_from_slice(&rpc_client.get_account_data(&wormhole_config)?)?;
let guardian_set = Pubkey::find_program_address(
&[
b"GuardianSet",
&wormhole_config_data.guardian_set_index.to_be_bytes(),
],
&wormhole,
)
.0;
let guardian_set = GuardianSet::key(&wormhole, wormhole_config_data.guardian_set_index);
let guardian_set_data = deserialize_guardian_set(
&mut &rpc_client.get_account_data(&guardian_set)?[..],
@ -361,18 +209,13 @@ pub fn process_post_vaa(
)?;
let vaa_hash = body.digest().unwrap().hash;
let vaa_pubkey = WormholeSolanaVAA::key(&wormhole, vaa_hash);
let vaa_pubkey = LegacyPostedVaa::key(&wormhole, vaa_hash);
let signature_set_keypair = Keypair::new();
let verify_txs = verify_signatures_txs(
vaa,
WormholeSolanaGuardianSet {
index: guardian_set_data.index,
keys: guardian_set_data.keys,
creation_time: guardian_set_data.creation_time,
expiration_time: guardian_set_data.expiration_time,
},
guardian_set_data,
wormhole,
payer.pubkey(),
wormhole_config_data.guardian_set_index,
@ -410,6 +253,96 @@ pub fn process_post_vaa(
Ok(vaa_pubkey)
}
/**
* This function posts a VAA using the new way of interacting with wormhole, we will use it for price updates
*/
pub fn process_write_encoded_vaa(
rpc_client: &RpcClient,
vaa: &[u8],
wormhole: Pubkey,
payer: &Keypair,
) -> Result<Pubkey> {
let encoded_vaa_keypair = Keypair::new();
let encoded_vaa_size: usize = vaa.len() + EncodedVaa::VAA_START;
let create_encoded_vaa = system_instruction::create_account(
&payer.pubkey(),
&encoded_vaa_keypair.pubkey(),
Rent::default().minimum_balance(encoded_vaa_size),
encoded_vaa_size as u64,
&wormhole,
);
let init_encoded_vaa_accounts = wormhole_core_bridge_solana::accounts::InitEncodedVaa {
write_authority: payer.pubkey(),
encoded_vaa: encoded_vaa_keypair.pubkey(),
}
.to_account_metas(None);
let init_encoded_vaa_instruction = Instruction {
program_id: wormhole,
accounts: init_encoded_vaa_accounts,
data: wormhole_core_bridge_solana::instruction::InitEncodedVaa.data(),
};
process_transaction(
rpc_client,
vec![create_encoded_vaa, init_encoded_vaa_instruction],
&vec![payer, &encoded_vaa_keypair],
)?;
let write_encoded_vaa_accounts = wormhole_core_bridge_solana::accounts::WriteEncodedVaa {
write_authority: payer.pubkey(),
draft_vaa: encoded_vaa_keypair.pubkey(),
}
.to_account_metas(None);
let write_encoded_vaa_accounts_instruction = Instruction {
program_id: wormhole,
accounts: write_encoded_vaa_accounts,
data: wormhole_core_bridge_solana::instruction::WriteEncodedVaa {
args: WriteEncodedVaaArgs {
index: 0,
data: vaa.to_vec(),
},
}
.data(),
};
process_transaction(
rpc_client,
vec![write_encoded_vaa_accounts_instruction],
&vec![payer],
)?;
let (header, _): (Header, Body<&RawMessage>) = serde_wormhole::from_slice(vaa).unwrap();
let guardian_set = GuardianSet::key(&wormhole, header.guardian_set_index);
let request_compute_units_instruction: Instruction =
ComputeBudgetInstruction::set_compute_unit_limit(400_000);
let verify_encoded_vaa_accounts = wormhole_core_bridge_solana::accounts::VerifyEncodedVaaV1 {
guardian_set,
write_authority: payer.pubkey(),
draft_vaa: encoded_vaa_keypair.pubkey(),
}
.to_account_metas(None);
let verify_encoded_vaa_instruction = Instruction {
program_id: wormhole,
accounts: verify_encoded_vaa_accounts,
data: wormhole_core_bridge_solana::instruction::VerifyEncodedVaaV1 {}.data(),
};
process_transaction(
rpc_client,
vec![
request_compute_units_instruction,
verify_encoded_vaa_instruction,
],
&vec![payer],
)?;
Ok(encoded_vaa_keypair.pubkey())
}
pub fn process_transaction(
rpc_client: &RpcClient,
instructions: Vec<Instruction>,