Переглянути джерело

Fix bridge fee and implement CLI

Change-Id: Ib17b335e05359fd4baf614d0b4eaae459814b04d
Hendrik Hofstadt 4 роки тому
батько
коміт
ece0de4bef

+ 3 - 2
solana/.dockerignore

@@ -1,4 +1,5 @@
 target
 bin
-cli/target
-agent/target
+bridge/target
+solitaire/target
+modules/token_bridge/target

+ 11 - 85
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"

+ 6 - 3
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"

+ 378 - 68
solana/bridge/client/src/main.rs

@@ -1,104 +1,414 @@
-use borsh::BorshSerialize;
+#![feature(const_generics)]
+#![allow(warnings)]
+
+use std::{
+    fmt::Display,
+    mem::size_of,
+    process::exit,
+};
+
+use borsh::BorshDeserialize;
 use bridge::{
-    api,
-    types,
+    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,
+}
+
+type Error = Box<dyn std::error::Error>;
+type CommmandResult = Result<Option<Transaction>, Error>;
+
+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);
+
+    let minimum_balance_for_rent_exemption = config
+        .rpc_client
+        .get_minimum_balance_for_rent_exemption(size_of::<BridgeData>())?;
+
+    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()));
+
+    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))
 }
 
-pub type ErrBox = Box<dyn error::Error>;
+fn command_post_message(
+    config: &Config,
+    bridge: &Pubkey,
+    nonce: u32,
+    payload: Vec<u8>,
+) -> CommmandResult {
+    println!("Posting a message to the wormhole");
 
-pub const DEFAULT_MESSAGE_FEE: u64 = 42;
-pub const DEFAULT_GUARDIAN_SET_EXPIRATION_TIME: u32 = 42;
+    // 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);
+
+    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()));
 
-fn main() -> Result<(), ErrBox> {
-    let opts = Opts::parse();
+    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))
+}
 
-    let payer = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json"))
-        .expect("Example requires a keypair file");
+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();
 
-    // 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 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 = RpcClient::new(url);
+        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 program_id = opts.bridge_address;
+        let owner = keypair_of(&matches, "owner").unwrap_or_else(client_keypair);
+        let fee_payer = keypair_of(&matches, "fee_payer").unwrap_or_else(client_keypair);
 
-    use AccEntry::*;
-    let init = api::InitializeAccounts {
-        bridge: Derived(program_id.clone()),
-        guardian_set: Unprivileged(<GuardianSet<'_, { AccountState::Uninitialized }>>::key(
-            &GuardianSetDerivationData { index: 0 },
-            &program_id,
-        )),
-        payer: Signer(payer),
+        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 ix_data = init_args.try_to_vec()?;
+            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();
 
-    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::<Vec<_>>()
-    );
+            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);
+    });
+}
+
+pub fn is_u8<T>(amount: T) -> Result<(), String>
+where
+    T: AsRef<str> + Display,
+{
+    if amount.as_ref().parse::<u8>().is_ok() {
+        Ok(())
+    } else {
+        Err(format!(
+            "Unable to parse input amount as integer, provided: {}",
+            amount
+        ))
+    }
+}
 
-    let mut tx = Transaction::new_with_payer(&[ix], Some(&payer_for_tx.pubkey()));
+pub fn is_u32<T>(amount: T) -> Result<(), String>
+where
+    T: AsRef<str> + Display,
+{
+    if amount.as_ref().parse::<u32>().is_ok() {
+        Ok(())
+    } else {
+        Err(format!(
+            "Unable to parse input amount as integer, provided: {}",
+            amount
+        ))
+    }
+}
 
-    tx.try_sign(&signers.iter().collect::<Vec<_>>(), recent_blockhash)?;
-    println!("Transaction signed.");
+pub fn is_u64<T>(amount: T) -> Result<(), String>
+where
+    T: AsRef<str> + Display,
+{
+    if amount.as_ref().parse::<u64>().is_ok() {
+        Ok(())
+    } else {
+        Err(format!(
+            "Unable to parse input amount as integer, provided: {}",
+            amount
+        ))
+    }
+}
 
-    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);
+pub fn is_hex<T>(value: T) -> Result<(), String>
+where
+    T: AsRef<str> + Display,
+{
+    hex::decode(value.to_string())
+        .map(|_| ())
+        .map_err(|e| format!("{}", e))
+}
 
-    Ok(())
+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(())
+    }
 }

+ 12 - 0
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<Info<'a>>;
 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(())
 }

+ 1 - 6
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
-}

+ 30 - 26
solana/bridge/program/src/instructions.rs → 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<Instruction> {
     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<u8>,
 ) -> solitaire::Result<Instruction> {
     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(),
     }
 }

+ 3 - 2
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;