diff --git a/solana/.dockerignore b/solana/.dockerignore index 581635346..fac60ba50 100644 --- a/solana/.dockerignore +++ b/solana/.dockerignore @@ -1,4 +1,5 @@ target bin -cli/target -agent/target +bridge/target +solitaire/target +modules/token_bridge/target \ No newline at end of file diff --git a/solana/bridge/Cargo.lock b/solana/bridge/Cargo.lock index 0eb42e7bc..5712c0e6e 100644 --- a/solana/bridge/Cargo.lock +++ b/solana/bridge/Cargo.lock @@ -34,7 +34,7 @@ dependencies = [ "bridge", "bs58", "byteorder", - "clap 2.33.3", + "clap", "futures 0.3.15", "hex", "libc", @@ -463,44 +463,12 @@ dependencies = [ "ansi_term", "atty", "bitflags", - "strsim 0.8.0", - "textwrap 0.11.0", + "strsim", + "textwrap", "unicode-width", "vec_map", ] -[[package]] -name = "clap" -version = "3.0.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd1061998a501ee7d4b6d449020df3266ca3124b941ec56cf2005c3779ca142" -dependencies = [ - "atty", - "bitflags", - "clap_derive", - "indexmap", - "lazy_static", - "os_str_bytes", - "strsim 0.10.0", - "termcolor", - "textwrap 0.12.1", - "unicode-width", - "vec_map", -] - -[[package]] -name = "clap_derive" -version = "3.0.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "370f715b81112975b1b69db93e0b56ea4cd4e5002ac43b2da8474106a54096a1" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2 1.0.27", - "quote 1.0.9", - "syn 1.0.73", -] - [[package]] name = "client" version = "0.1.0" @@ -508,9 +476,12 @@ dependencies = [ "anyhow", "borsh", "bridge", - "clap 3.0.0-beta.2", + "clap", + "hex", "rand 0.7.3", "shellexpand", + "solana-clap-utils", + "solana-cli-config", "solana-client", "solana-program", "solana-sdk", @@ -2024,12 +1995,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "os_str_bytes" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" - [[package]] name = "ouroboros" version = "0.5.1" @@ -2282,30 +2247,6 @@ dependencies = [ "toml", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2 1.0.27", - "quote 1.0.9", - "syn 1.0.73", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2 1.0.27", - "quote 1.0.9", - "version_check", -] - [[package]] name = "proc-macro-hack" version = "0.5.19" @@ -3026,7 +2967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "484288242b2b175bf2b7554497318e39b23ee921989f976387dbe48e60b2f256" dependencies = [ "chrono", - "clap 2.33.3", + "clap", "rpassword", "solana-remote-wallet", "solana-sdk", @@ -3059,7 +3000,7 @@ dependencies = [ "base64 0.13.0", "bincode", "bs58", - "clap 2.33.3", + "clap", "indicatif", "jsonrpc-core", "log", @@ -3132,7 +3073,7 @@ checksum = "ed5e6adf551ca4e761c3395bb684ba5d907a051007a6dbf2d57cb99d2691e031" dependencies = [ "bincode", "byteorder", - "clap 2.33.3", + "clap", "log", "serde", "serde_derive", @@ -3222,7 +3163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa68e25fb6452b85733cf5c301988b56fd2d5d5a8e93c75cf38cbec06efc2eae" dependencies = [ "bincode", - "clap 2.33.3", + "clap", "log", "nix", "rand 0.7.3", @@ -3591,12 +3532,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "subtle" version = "1.0.0" @@ -3711,15 +3646,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "textwrap" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203008d98caf094106cfaba70acfed15e18ed3ddb7d94e49baec153a2b462789" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" version = "1.0.25" diff --git a/solana/bridge/client/Cargo.toml b/solana/bridge/client/Cargo.toml index 1e413da78..abbd55bd8 100644 --- a/solana/bridge/client/Cargo.toml +++ b/solana/bridge/client/Cargo.toml @@ -7,12 +7,15 @@ edition = "2018" [dependencies] anyhow = "1.0.40" borsh = "0.8.1" -bridge = {path = "../program", features = ["no-idl", "no-entrypoint", "client"]} -clap = "3.0.0-beta.2" +bridge = { path = "../program", features = ["no-idl", "no-entrypoint", "client"] } +clap = "2.33.0" rand = "0.7.3" shellexpand = "2.1.0" solana-client = "=1.7.0" solana-program = "=1.7.0" solana-sdk = "=1.7.0" +solana-cli-config = "=1.7.0" solitaire = { path = "../../solitaire/program" } -solitaire-client = {path = "../../solitaire/client" } +solitaire-client = { path = "../../solitaire/client" } +solana-clap-utils = "=1.7.0" +hex = "0.4.3" \ No newline at end of file diff --git a/solana/bridge/client/src/main.rs b/solana/bridge/client/src/main.rs index a55638c2d..316cf1b88 100644 --- a/solana/bridge/client/src/main.rs +++ b/solana/bridge/client/src/main.rs @@ -1,104 +1,414 @@ -use borsh::BorshSerialize; -use bridge::{ - api, - types, +#![feature(const_generics)] +#![allow(warnings)] + +use std::{ + fmt::Display, + mem::size_of, + process::exit, +}; + +use borsh::BorshDeserialize; +use bridge::{ + accounts::{ + Bridge, + FeeCollector, + }, + types::BridgeData, +}; +use clap::{ + crate_description, + crate_name, + crate_version, + value_t, + App, + AppSettings, + Arg, + SubCommand, +}; +use hex; +use solana_clap_utils::{ + input_parsers::{ + keypair_of, + pubkey_of, + value_of, + }, + input_validators::{ + is_keypair, + is_pubkey_or_keypair, + is_url, + }, }; -use clap::Clap; use solana_client::{ rpc_client::RpcClient, rpc_config::RpcSendTransactionConfig, }; -use solana_program::pubkey::Pubkey; use solana_sdk::{ commitment_config::CommitmentConfig, + native_token::*, + program_error::ProgramError::AccountAlreadyInitialized, + pubkey::Pubkey, signature::{ read_keypair_file, - Signer as SolSigner, + Keypair, + Signer, }, + system_instruction::transfer, transaction::Transaction, }; -use solitaire_client::{ - AccEntry, - ToInstruction, -}; - -use bridge::accounts::{ - GuardianSet, - GuardianSetDerivationData, -}; use solitaire::{ processors::seeded::Seeded, AccountState, }; -use std::error; -#[derive(Clap)] -pub struct Opts { - #[clap(long)] - bridge_address: Pubkey, +struct Config { + rpc_client: RpcClient, + owner: Keypair, + fee_payer: Keypair, + commitment_config: CommitmentConfig, } -pub type ErrBox = Box; +type Error = Box; +type CommmandResult = Result, Error>; -pub const DEFAULT_MESSAGE_FEE: u64 = 42; -pub const DEFAULT_GUARDIAN_SET_EXPIRATION_TIME: u32 = 42; +fn command_deploy_bridge( + config: &Config, + bridge: &Pubkey, + _initial_guardian: Vec<[u8; 20]>, + guardian_expiration: u32, + message_fee: u64, +) -> CommmandResult { + println!("Initializing Wormhole bridge {}", bridge); -fn main() -> Result<(), ErrBox> { - let opts = Opts::parse(); + let minimum_balance_for_rent_exemption = config + .rpc_client + .get_minimum_balance_for_rent_exemption(size_of::())?; - let payer = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json")) - .expect("Example requires a keypair file"); + let ix = bridge::client_instructions::initialize( + *bridge, + config.owner.pubkey(), + message_fee, + guardian_expiration, + ) + .unwrap(); + println!("config account: {}, ", ix.accounts[0].pubkey.to_string()); + let mut transaction = Transaction::new_with_payer(&[ix], Some(&config.fee_payer.pubkey())); - // Keypair is not Clone - let payer_for_tx = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json")) - .expect("Example requires a keypair file"); - let url = "http://localhost:8899".to_owned(); + let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?; + check_fee_payer_balance( + config, + minimum_balance_for_rent_exemption + fee_calculator.calculate_fee(&transaction.message()), + )?; + transaction.sign(&[&config.fee_payer, &config.owner], recent_blockhash); + Ok(Some(transaction)) +} - let client = RpcClient::new(url); +fn command_post_message( + config: &Config, + bridge: &Pubkey, + nonce: u32, + payload: Vec, +) -> CommmandResult { + println!("Posting a message to the wormhole"); - let program_id = opts.bridge_address; + // Fetch the message fee + let bridge_config_account = config + .rpc_client + .get_account(&Bridge::<'_, { AccountState::Initialized }>::key( + None, bridge, + ))?; + let bridge_config = BridgeData::try_from_slice(bridge_config_account.data.as_slice())?; + println!("Message fee: {} lamports", bridge_config.config.fee); - use AccEntry::*; - let init = api::InitializeAccounts { - bridge: Derived(program_id.clone()), - guardian_set: Unprivileged(>::key( - &GuardianSetDerivationData { index: 0 }, - &program_id, - )), - payer: Signer(payer), + let transfer_ix = transfer( + &config.owner.pubkey(), + &FeeCollector::key(None, bridge), + bridge_config.config.fee, + ); + let ix = bridge::client_instructions::post_message( + *bridge, + config.owner.pubkey(), + config.fee_payer.pubkey(), + nonce, + payload, + ) + .unwrap(); + let mut transaction = + Transaction::new_with_payer(&[transfer_ix, ix], Some(&config.fee_payer.pubkey())); + + let (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?; + check_fee_payer_balance(config, fee_calculator.calculate_fee(&transaction.message()))?; + transaction.sign(&[&config.fee_payer, &config.owner], recent_blockhash); + Ok(Some(transaction)) +} + +fn main() { + let matches = App::new(crate_name!()) + .about(crate_description!()) + .version(crate_version!()) + .setting(AppSettings::SubcommandRequiredElseHelp) + .arg({ + let arg = Arg::with_name("config_file") + .short("C") + .long("config") + .value_name("PATH") + .takes_value(true) + .global(true) + .help("Configuration file to use"); + if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE { + arg.default_value(&config_file) + } else { + arg + } + }) + .arg( + Arg::with_name("json_rpc_url") + .long("url") + .value_name("URL") + .takes_value(true) + .validator(is_url) + .help("JSON RPC URL for the cluster. Default from the configuration file."), + ) + .arg( + Arg::with_name("owner") + .long("owner") + .value_name("KEYPAIR") + .validator(is_keypair) + .takes_value(true) + .help( + "Specify the contract payer account. \ + This may be a keypair file, the ASK keyword. \ + Defaults to the client keypair.", + ), + ) + .arg( + Arg::with_name("fee_payer") + .long("fee-payer") + .value_name("KEYPAIR") + .validator(is_keypair) + .takes_value(true) + .help( + "Specify the fee-payer account. \ + This may be a keypair file, the ASK keyword. \ + Defaults to the client keypair.", + ), + ) + .subcommand( + SubCommand::with_name("create-bridge") + .about("Create a new bridge") + .arg( + Arg::with_name("bridge") + .long("bridge") + .value_name("BRIDGE_KEY") + .validator(is_pubkey_or_keypair) + .takes_value(true) + .index(1) + .required(true) + .help("Specify the bridge program address"), + ) + .arg( + Arg::with_name("guardian") + .validator(is_hex) + .value_name("GUARDIAN_ADDRESS") + .takes_value(true) + .index(2) + .required(true) + .help("Address of the initial guardian"), + ) + .arg( + Arg::with_name("guardian_set_expiration") + .validator(is_u32) + .value_name("GUARDIAN_SET_EXPIRATION") + .takes_value(true) + .index(3) + .required(true) + .help("Time in seconds after which a guardian set expires after an update"), + ) + .arg( + Arg::with_name("message_fee") + .validator(is_u64) + .value_name("MESSAGE_FEE") + .takes_value(true) + .index(4) + .required(true) + .help("Initial message posting fee"), + ), + ) + .subcommand( + SubCommand::with_name("post-message") + .about("Post a message via Wormhole") + .arg( + Arg::with_name("bridge") + .long("bridge") + .value_name("BRIDGE_KEY") + .validator(is_pubkey_or_keypair) + .takes_value(true) + .index(1) + .required(true) + .help("Specify the bridge program address"), + ) + .arg( + Arg::with_name("nonce") + .validator(is_u32) + .value_name("NONCE") + .takes_value(true) + .index(2) + .required(true) + .help("Nonce of the message"), + ) + .arg( + Arg::with_name("data") + .validator(is_hex) + .value_name("DATA") + .takes_value(true) + .index(3) + .required(true) + .help("Payload of the message"), + ), + ) + .get_matches(); + + let config = { + let cli_config = if let Some(config_file) = matches.value_of("config_file") { + solana_cli_config::Config::load(config_file).unwrap_or_default() + } else { + solana_cli_config::Config::default() + }; + let json_rpc_url = value_t!(matches, "json_rpc_url", String) + .unwrap_or_else(|_| cli_config.json_rpc_url.clone()); + + let client_keypair = || { + read_keypair_file(&cli_config.keypair_path).unwrap_or_else(|err| { + eprintln!("Unable to read {}: {}", cli_config.keypair_path, err); + exit(1) + }) + }; + + let owner = keypair_of(&matches, "owner").unwrap_or_else(client_keypair); + let fee_payer = keypair_of(&matches, "fee_payer").unwrap_or_else(client_keypair); + + Config { + rpc_client: RpcClient::new(json_rpc_url), + owner, + fee_payer, + commitment_config: CommitmentConfig::processed(), + } }; - let init_args = bridge::instruction::Instruction::Initialize(types::BridgeConfig { - guardian_set_expiration_time: DEFAULT_GUARDIAN_SET_EXPIRATION_TIME, - fee: DEFAULT_MESSAGE_FEE, + let _ = match matches.subcommand() { + ("create-bridge", Some(arg_matches)) => { + let bridge = pubkey_of(arg_matches, "bridge").unwrap(); + let initial_guardian: String = value_of(arg_matches, "guardian").unwrap(); + let initial_data = hex::decode(initial_guardian).unwrap(); + let guardian_expiration: u32 = + value_of(arg_matches, "guardian_set_expiration").unwrap(); + let msg_fee: u64 = value_of(arg_matches, "message_fee").unwrap(); + + let mut guardian = [0u8; 20]; + guardian.copy_from_slice(&initial_data); + command_deploy_bridge( + &config, + &bridge, + vec![guardian], + guardian_expiration, + msg_fee, + ) + } + ("post-message", Some(arg_matches)) => { + let bridge = pubkey_of(arg_matches, "bridge").unwrap(); + let data_str: String = value_of(arg_matches, "data").unwrap(); + let data = hex::decode(data_str).unwrap(); + let nonce: u32 = value_of(arg_matches, "nonce").unwrap(); + + command_post_message(&config, &bridge, nonce, data) + } + + _ => unreachable!(), + } + .and_then(|transaction| { + if let Some(transaction) = transaction { + let signature = config + .rpc_client + .send_and_confirm_transaction_with_spinner_and_config( + &transaction, + config.commitment_config, + RpcSendTransactionConfig { + skip_preflight: true, + preflight_commitment: None, + encoding: None, + }, + )?; + println!("Signature: {}", signature); + } + Ok(()) + }) + .map_err(|err| { + eprintln!("{}", err); + exit(1); }); - - let ix_data = init_args.try_to_vec()?; - - let (ix, signers) = init.to_ix(program_id, ix_data.as_slice())?; - let (recent_blockhash, _) = client.get_recent_blockhash()?; - println!("Instruction ready."); - println!( - "Signing for {} signer(s): {:?}", - signers.len(), - signers.iter().map(|s| s.pubkey()).collect::>() - ); - - let mut tx = Transaction::new_with_payer(&[ix], Some(&payer_for_tx.pubkey())); - - tx.try_sign(&signers.iter().collect::>(), recent_blockhash)?; - println!("Transaction signed."); - - let signature = client.send_and_confirm_transaction_with_spinner_and_config( - &tx, - CommitmentConfig::processed(), - RpcSendTransactionConfig { - skip_preflight: true, - preflight_commitment: None, - encoding: None, - }, - )?; - println!("Signature: {}", signature); - - Ok(()) +} + +pub fn is_u8(amount: T) -> Result<(), String> +where + T: AsRef + Display, +{ + if amount.as_ref().parse::().is_ok() { + Ok(()) + } else { + Err(format!( + "Unable to parse input amount as integer, provided: {}", + amount + )) + } +} + +pub fn is_u32(amount: T) -> Result<(), String> +where + T: AsRef + Display, +{ + if amount.as_ref().parse::().is_ok() { + Ok(()) + } else { + Err(format!( + "Unable to parse input amount as integer, provided: {}", + amount + )) + } +} + +pub fn is_u64(amount: T) -> Result<(), String> +where + T: AsRef + Display, +{ + if amount.as_ref().parse::().is_ok() { + Ok(()) + } else { + Err(format!( + "Unable to parse input amount as integer, provided: {}", + amount + )) + } +} + +pub fn is_hex(value: T) -> Result<(), String> +where + T: AsRef + Display, +{ + hex::decode(value.to_string()) + .map(|_| ()) + .map_err(|e| format!("{}", e)) +} + +fn check_fee_payer_balance(config: &Config, required_balance: u64) -> Result<(), Error> { + let balance = config.rpc_client.get_balance(&config.fee_payer.pubkey())?; + if balance < required_balance { + Err(format!( + "Fee payer, {}, has insufficient balance: {} required, {} available", + config.fee_payer.pubkey(), + lamports_to_sol(required_balance), + lamports_to_sol(balance) + ) + .into()) + } else { + Ok(()) + } } diff --git a/solana/bridge/program/src/api/initialize.rs b/solana/bridge/program/src/api/initialize.rs index 820c760eb..88a073a67 100644 --- a/solana/bridge/program/src/api/initialize.rs +++ b/solana/bridge/program/src/api/initialize.rs @@ -1,6 +1,7 @@ use crate::{ accounts::{ Bridge, + FeeCollector, GuardianSet, GuardianSetDerivationData, }, @@ -17,6 +18,7 @@ type Payer<'a> = Signer>; pub struct Initialize<'b> { pub bridge: Bridge<'b, { AccountState::Uninitialized }>, pub guardian_set: GuardianSet<'b, { AccountState::Uninitialized }>, + pub fee_collector: FeeCollector<'b>, pub payer: Payer<'b>, } @@ -49,5 +51,15 @@ pub fn initialize( accs.bridge.guardian_set_index = 0; accs.bridge.config = config; + // Initialize the fee collector account so it's rent exempt and will keep funds + accs.fee_collector.create( + ctx, + accs.payer.key, + Exempt, + 0, + &solana_program::system_program::id(), + )?; + accs.bridge.last_lamports = accs.fee_collector.lamports(); + Ok(()) } diff --git a/solana/bridge/program/src/api/post_message.rs b/solana/bridge/program/src/api/post_message.rs index c3f910486..b0a7e6a52 100644 --- a/solana/bridge/program/src/api/post_message.rs +++ b/solana/bridge/program/src/api/post_message.rs @@ -89,13 +89,12 @@ pub fn post_message( .verify_derivation(ctx.program_id, &msg_derivation)?; // Fee handling - let fee = transfer_fee(); if accs .fee_collector .lamports() .checked_sub(accs.bridge.last_lamports) .ok_or(MathOverflow)? - < fee + < accs.bridge.config.fee { return Err(InsufficientFees.into()); } @@ -124,7 +123,3 @@ pub fn post_message( Ok(()) } - -pub fn transfer_fee() -> u64 { - 500 -} diff --git a/solana/bridge/program/src/instructions.rs b/solana/bridge/program/src/client_instructions.rs similarity index 87% rename from solana/bridge/program/src/instructions.rs rename to solana/bridge/program/src/client_instructions.rs index fc548c928..1d84c1033 100644 --- a/solana/bridge/program/src/instructions.rs +++ b/solana/bridge/program/src/client_instructions.rs @@ -1,6 +1,4 @@ use borsh::BorshSerialize; -use solitaire::processors::seeded::Seeded; -use solitaire::AccountState; use solana_program::{ borsh::try_from_slice_unchecked, hash, @@ -17,6 +15,10 @@ use solana_program::{ system_program, sysvar, }; +use solitaire::{ + processors::seeded::Seeded, + AccountState, +}; use crate::{ accounts::{ @@ -41,25 +43,22 @@ use crate::{ pub fn initialize( program_id: Pubkey, payer: Pubkey, - bridge: Pubkey, - guardian_set_index: u32, - guardian_set: Pubkey, fee: u64, guardian_set_expiration_time: u32, ) -> solitaire::Result { let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id); let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key( - &GuardianSetDerivationData { - index: guardian_set_index, - }, + &GuardianSetDerivationData { index: 0 }, &program_id, ); + let fee_collector = FeeCollector::key(None, &program_id); Ok(Instruction { program_id, accounts: vec![ AccountMeta::new(bridge, false), AccountMeta::new(guardian_set, false), + AccountMeta::new(fee_collector, false), AccountMeta::new(payer, true), AccountMeta::new_readonly(sysvar::rent::id(), false), AccountMeta::new_readonly(solana_program::system_program::id(), false), @@ -75,22 +74,27 @@ pub fn initialize( pub fn post_message( program_id: Pubkey, payer: Pubkey, - bridge: Pubkey, emitter: Pubkey, - message: PostedMessage, - sequence: u64, + nonce: u32, + payload: Vec, ) -> solitaire::Result { let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id); let fee_collector = FeeCollector::<'_>::key(None, &program_id); - let sequence = Sequence::<'_>::key(&SequenceDerivationData { - emitter_key: &emitter, - }, &program_id); - let message = Message::<'_, { AccountState::Uninitialized }>::key(&MessageDerivationData { - emitter_key: emitter.to_bytes(), - emitter_chain: message.emitter_chain, - nonce: message.nonce, - payload: message.payload.clone(), - }, &program_id); + let sequence = Sequence::<'_>::key( + &SequenceDerivationData { + emitter_key: &emitter, + }, + &program_id, + ); + let message = Message::<'_, { AccountState::Uninitialized }>::key( + &MessageDerivationData { + emitter_key: emitter.to_bytes(), + emitter_chain: 1, + nonce, + payload: payload.clone(), + }, + &program_id, + ); Ok(Instruction { program_id, @@ -108,10 +112,10 @@ pub fn post_message( ], data: crate::instruction::Instruction::PostMessage(PostMessageData { - nonce: 0, - payload: vec![], + nonce, + payload: payload.clone(), }) - .try_to_vec()? + .try_to_vec()?, }) } @@ -155,7 +159,7 @@ pub fn verify_signatures( signers, initial_creation: true, }) - .try_to_vec()? + .try_to_vec()?, }) } @@ -206,7 +210,7 @@ pub fn post_vaa( ], data: crate::instruction::Instruction::PostVAA(vaa) - .try_to_vec() - .unwrap(), + .try_to_vec() + .unwrap(), } } diff --git a/solana/bridge/program/src/lib.rs b/solana/bridge/program/src/lib.rs index 57ce24f34..4794df496 100644 --- a/solana/bridge/program/src/lib.rs +++ b/solana/bridge/program/src/lib.rs @@ -8,6 +8,7 @@ use solana_program::msg; // package as soon as possible. pub mod accounts; pub mod api; +pub mod client_instructions; pub mod types; pub mod vaa; @@ -25,14 +26,14 @@ pub use api::{ PostMessageData, PostVAA, PostVAAData, + Signature, + UninitializedMessage, UpgradeContract, UpgradeContractData, UpgradeGuardianSet, UpgradeGuardianSetData, VerifySignatures, VerifySignaturesData, - UninitializedMessage, - Signature, }; use types::BridgeConfig;