Fix bridge fee and implement CLI

Change-Id: Ib17b335e05359fd4baf614d0b4eaae459814b04d
This commit is contained in:
Hendrik Hofstadt 2021-06-23 16:49:25 +02:00
parent d677311d70
commit ece0de4bef
8 changed files with 450 additions and 198 deletions

View File

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

View File

@ -34,7 +34,7 @@ dependencies = [
"bridge", "bridge",
"bs58", "bs58",
"byteorder", "byteorder",
"clap 2.33.3", "clap",
"futures 0.3.15", "futures 0.3.15",
"hex", "hex",
"libc", "libc",
@ -463,44 +463,12 @@ dependencies = [
"ansi_term", "ansi_term",
"atty", "atty",
"bitflags", "bitflags",
"strsim 0.8.0", "strsim",
"textwrap 0.11.0", "textwrap",
"unicode-width", "unicode-width",
"vec_map", "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]] [[package]]
name = "client" name = "client"
version = "0.1.0" version = "0.1.0"
@ -508,9 +476,12 @@ dependencies = [
"anyhow", "anyhow",
"borsh", "borsh",
"bridge", "bridge",
"clap 3.0.0-beta.2", "clap",
"hex",
"rand 0.7.3", "rand 0.7.3",
"shellexpand", "shellexpand",
"solana-clap-utils",
"solana-cli-config",
"solana-client", "solana-client",
"solana-program", "solana-program",
"solana-sdk", "solana-sdk",
@ -2024,12 +1995,6 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "os_str_bytes"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85"
[[package]] [[package]]
name = "ouroboros" name = "ouroboros"
version = "0.5.1" version = "0.5.1"
@ -2282,30 +2247,6 @@ dependencies = [
"toml", "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]] [[package]]
name = "proc-macro-hack" name = "proc-macro-hack"
version = "0.5.19" version = "0.5.19"
@ -3026,7 +2967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "484288242b2b175bf2b7554497318e39b23ee921989f976387dbe48e60b2f256" checksum = "484288242b2b175bf2b7554497318e39b23ee921989f976387dbe48e60b2f256"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap 2.33.3", "clap",
"rpassword", "rpassword",
"solana-remote-wallet", "solana-remote-wallet",
"solana-sdk", "solana-sdk",
@ -3059,7 +3000,7 @@ dependencies = [
"base64 0.13.0", "base64 0.13.0",
"bincode", "bincode",
"bs58", "bs58",
"clap 2.33.3", "clap",
"indicatif", "indicatif",
"jsonrpc-core", "jsonrpc-core",
"log", "log",
@ -3132,7 +3073,7 @@ checksum = "ed5e6adf551ca4e761c3395bb684ba5d907a051007a6dbf2d57cb99d2691e031"
dependencies = [ dependencies = [
"bincode", "bincode",
"byteorder", "byteorder",
"clap 2.33.3", "clap",
"log", "log",
"serde", "serde",
"serde_derive", "serde_derive",
@ -3222,7 +3163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa68e25fb6452b85733cf5c301988b56fd2d5d5a8e93c75cf38cbec06efc2eae" checksum = "fa68e25fb6452b85733cf5c301988b56fd2d5d5a8e93c75cf38cbec06efc2eae"
dependencies = [ dependencies = [
"bincode", "bincode",
"clap 2.33.3", "clap",
"log", "log",
"nix", "nix",
"rand 0.7.3", "rand 0.7.3",
@ -3591,12 +3532,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "1.0.0" version = "1.0.0"
@ -3711,15 +3646,6 @@ dependencies = [
"unicode-width", "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]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.25" version = "1.0.25"

View File

@ -7,12 +7,15 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0.40" anyhow = "1.0.40"
borsh = "0.8.1" borsh = "0.8.1"
bridge = {path = "../program", features = ["no-idl", "no-entrypoint", "client"]} bridge = { path = "../program", features = ["no-idl", "no-entrypoint", "client"] }
clap = "3.0.0-beta.2" clap = "2.33.0"
rand = "0.7.3" rand = "0.7.3"
shellexpand = "2.1.0" shellexpand = "2.1.0"
solana-client = "=1.7.0" solana-client = "=1.7.0"
solana-program = "=1.7.0" solana-program = "=1.7.0"
solana-sdk = "=1.7.0" solana-sdk = "=1.7.0"
solana-cli-config = "=1.7.0"
solitaire = { path = "../../solitaire/program" } solitaire = { path = "../../solitaire/program" }
solitaire-client = {path = "../../solitaire/client" } solitaire-client = { path = "../../solitaire/client" }
solana-clap-utils = "=1.7.0"
hex = "0.4.3"

View File

@ -1,97 +1,336 @@
use borsh::BorshSerialize; #![feature(const_generics)]
use bridge::{ #![allow(warnings)]
api,
types, 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::{ use solana_client::{
rpc_client::RpcClient, rpc_client::RpcClient,
rpc_config::RpcSendTransactionConfig, rpc_config::RpcSendTransactionConfig,
}; };
use solana_program::pubkey::Pubkey;
use solana_sdk::{ use solana_sdk::{
commitment_config::CommitmentConfig, commitment_config::CommitmentConfig,
native_token::*,
program_error::ProgramError::AccountAlreadyInitialized,
pubkey::Pubkey,
signature::{ signature::{
read_keypair_file, read_keypair_file,
Signer as SolSigner, Keypair,
Signer,
}, },
system_instruction::transfer,
transaction::Transaction, transaction::Transaction,
}; };
use solitaire_client::{
AccEntry,
ToInstruction,
};
use bridge::accounts::{
GuardianSet,
GuardianSetDerivationData,
};
use solitaire::{ use solitaire::{
processors::seeded::Seeded, processors::seeded::Seeded,
AccountState, AccountState,
}; };
use std::error;
#[derive(Clap)] struct Config {
pub struct Opts { rpc_client: RpcClient,
#[clap(long)] owner: Keypair,
bridge_address: Pubkey, fee_payer: Keypair,
commitment_config: CommitmentConfig,
} }
pub type ErrBox = Box<dyn error::Error>; type Error = Box<dyn std::error::Error>;
type CommmandResult = Result<Option<Transaction>, Error>;
pub const DEFAULT_MESSAGE_FEE: u64 = 42; fn command_deploy_bridge(
pub const DEFAULT_GUARDIAN_SET_EXPIRATION_TIME: u32 = 42; 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 minimum_balance_for_rent_exemption = config
let opts = Opts::parse(); .rpc_client
.get_minimum_balance_for_rent_exemption(size_of::<BridgeData>())?;
let payer = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json")) let ix = bridge::client_instructions::initialize(
.expect("Example requires a keypair file"); *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 (recent_blockhash, fee_calculator) = config.rpc_client.get_recent_blockhash()?;
let payer_for_tx = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json")) check_fee_payer_balance(
.expect("Example requires a keypair file"); config,
let url = "http://localhost:8899".to_owned(); 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<u8>,
) -> 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 transfer_ix = transfer(
let init = api::InitializeAccounts { &config.owner.pubkey(),
bridge: Derived(program_id.clone()), &FeeCollector::key(None, bridge),
guardian_set: Unprivileged(<GuardianSet<'_, { AccountState::Uninitialized }>>::key( bridge_config.config.fee,
&GuardianSetDerivationData { index: 0 }, );
&program_id, let ix = bridge::client_instructions::post_message(
)), *bridge,
payer: Signer(payer), 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 init_args = bridge::instruction::Instruction::Initialize(types::BridgeConfig { let owner = keypair_of(&matches, "owner").unwrap_or_else(client_keypair);
guardian_set_expiration_time: DEFAULT_GUARDIAN_SET_EXPIRATION_TIME, let fee_payer = keypair_of(&matches, "fee_payer").unwrap_or_else(client_keypair);
fee: DEFAULT_MESSAGE_FEE,
});
let ix_data = init_args.try_to_vec()?; Config {
rpc_client: RpcClient::new(json_rpc_url),
owner,
fee_payer,
commitment_config: CommitmentConfig::processed(),
}
};
let (ix, signers) = init.to_ix(program_id, ix_data.as_slice())?; let _ = match matches.subcommand() {
let (recent_blockhash, _) = client.get_recent_blockhash()?; ("create-bridge", Some(arg_matches)) => {
println!("Instruction ready."); let bridge = pubkey_of(arg_matches, "bridge").unwrap();
println!( let initial_guardian: String = value_of(arg_matches, "guardian").unwrap();
"Signing for {} signer(s): {:?}", let initial_data = hex::decode(initial_guardian).unwrap();
signers.len(), let guardian_expiration: u32 =
signers.iter().map(|s| s.pubkey()).collect::<Vec<_>>() value_of(arg_matches, "guardian_set_expiration").unwrap();
); let msg_fee: u64 = value_of(arg_matches, "message_fee").unwrap();
let mut tx = Transaction::new_with_payer(&[ix], Some(&payer_for_tx.pubkey())); 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();
tx.try_sign(&signers.iter().collect::<Vec<_>>(), recent_blockhash)?; command_post_message(&config, &bridge, nonce, data)
println!("Transaction signed."); }
let signature = client.send_and_confirm_transaction_with_spinner_and_config( _ => unreachable!(),
&tx, }
CommitmentConfig::processed(), .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 { RpcSendTransactionConfig {
skip_preflight: true, skip_preflight: true,
preflight_commitment: None, preflight_commitment: None,
@ -99,6 +338,77 @@ fn main() -> Result<(), ErrBox> {
}, },
)?; )?;
println!("Signature: {}", signature); println!("Signature: {}", signature);
}
Ok(()) 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
))
}
}
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
))
}
}
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
))
}
}
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))
}
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(())
}
} }

View File

@ -1,6 +1,7 @@
use crate::{ use crate::{
accounts::{ accounts::{
Bridge, Bridge,
FeeCollector,
GuardianSet, GuardianSet,
GuardianSetDerivationData, GuardianSetDerivationData,
}, },
@ -17,6 +18,7 @@ type Payer<'a> = Signer<Info<'a>>;
pub struct Initialize<'b> { pub struct Initialize<'b> {
pub bridge: Bridge<'b, { AccountState::Uninitialized }>, pub bridge: Bridge<'b, { AccountState::Uninitialized }>,
pub guardian_set: GuardianSet<'b, { AccountState::Uninitialized }>, pub guardian_set: GuardianSet<'b, { AccountState::Uninitialized }>,
pub fee_collector: FeeCollector<'b>,
pub payer: Payer<'b>, pub payer: Payer<'b>,
} }
@ -49,5 +51,15 @@ pub fn initialize(
accs.bridge.guardian_set_index = 0; accs.bridge.guardian_set_index = 0;
accs.bridge.config = config; 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(()) Ok(())
} }

View File

@ -89,13 +89,12 @@ pub fn post_message(
.verify_derivation(ctx.program_id, &msg_derivation)?; .verify_derivation(ctx.program_id, &msg_derivation)?;
// Fee handling // Fee handling
let fee = transfer_fee();
if accs if accs
.fee_collector .fee_collector
.lamports() .lamports()
.checked_sub(accs.bridge.last_lamports) .checked_sub(accs.bridge.last_lamports)
.ok_or(MathOverflow)? .ok_or(MathOverflow)?
< fee < accs.bridge.config.fee
{ {
return Err(InsufficientFees.into()); return Err(InsufficientFees.into());
} }
@ -124,7 +123,3 @@ pub fn post_message(
Ok(()) Ok(())
} }
pub fn transfer_fee() -> u64 {
500
}

View File

@ -1,6 +1,4 @@
use borsh::BorshSerialize; use borsh::BorshSerialize;
use solitaire::processors::seeded::Seeded;
use solitaire::AccountState;
use solana_program::{ use solana_program::{
borsh::try_from_slice_unchecked, borsh::try_from_slice_unchecked,
hash, hash,
@ -17,6 +15,10 @@ use solana_program::{
system_program, system_program,
sysvar, sysvar,
}; };
use solitaire::{
processors::seeded::Seeded,
AccountState,
};
use crate::{ use crate::{
accounts::{ accounts::{
@ -41,25 +43,22 @@ use crate::{
pub fn initialize( pub fn initialize(
program_id: Pubkey, program_id: Pubkey,
payer: Pubkey, payer: Pubkey,
bridge: Pubkey,
guardian_set_index: u32,
guardian_set: Pubkey,
fee: u64, fee: u64,
guardian_set_expiration_time: u32, guardian_set_expiration_time: u32,
) -> solitaire::Result<Instruction> { ) -> solitaire::Result<Instruction> {
let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id); let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id);
let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key( let guardian_set = GuardianSet::<'_, { AccountState::Uninitialized }>::key(
&GuardianSetDerivationData { &GuardianSetDerivationData { index: 0 },
index: guardian_set_index,
},
&program_id, &program_id,
); );
let fee_collector = FeeCollector::key(None, &program_id);
Ok(Instruction { Ok(Instruction {
program_id, program_id,
accounts: vec![ accounts: vec![
AccountMeta::new(bridge, false), AccountMeta::new(bridge, false),
AccountMeta::new(guardian_set, false), AccountMeta::new(guardian_set, false),
AccountMeta::new(fee_collector, false),
AccountMeta::new(payer, true), AccountMeta::new(payer, true),
AccountMeta::new_readonly(sysvar::rent::id(), false), AccountMeta::new_readonly(sysvar::rent::id(), false),
AccountMeta::new_readonly(solana_program::system_program::id(), false), AccountMeta::new_readonly(solana_program::system_program::id(), false),
@ -75,22 +74,27 @@ pub fn initialize(
pub fn post_message( pub fn post_message(
program_id: Pubkey, program_id: Pubkey,
payer: Pubkey, payer: Pubkey,
bridge: Pubkey,
emitter: Pubkey, emitter: Pubkey,
message: PostedMessage, nonce: u32,
sequence: u64, payload: Vec<u8>,
) -> solitaire::Result<Instruction> { ) -> solitaire::Result<Instruction> {
let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id); let bridge = Bridge::<'_, { AccountState::Uninitialized }>::key(None, &program_id);
let fee_collector = FeeCollector::<'_>::key(None, &program_id); let fee_collector = FeeCollector::<'_>::key(None, &program_id);
let sequence = Sequence::<'_>::key(&SequenceDerivationData { let sequence = Sequence::<'_>::key(
&SequenceDerivationData {
emitter_key: &emitter, emitter_key: &emitter,
}, &program_id); },
let message = Message::<'_, { AccountState::Uninitialized }>::key(&MessageDerivationData { &program_id,
);
let message = Message::<'_, { AccountState::Uninitialized }>::key(
&MessageDerivationData {
emitter_key: emitter.to_bytes(), emitter_key: emitter.to_bytes(),
emitter_chain: message.emitter_chain, emitter_chain: 1,
nonce: message.nonce, nonce,
payload: message.payload.clone(), payload: payload.clone(),
}, &program_id); },
&program_id,
);
Ok(Instruction { Ok(Instruction {
program_id, program_id,
@ -108,10 +112,10 @@ pub fn post_message(
], ],
data: crate::instruction::Instruction::PostMessage(PostMessageData { data: crate::instruction::Instruction::PostMessage(PostMessageData {
nonce: 0, nonce,
payload: vec![], payload: payload.clone(),
}) })
.try_to_vec()? .try_to_vec()?,
}) })
} }
@ -155,7 +159,7 @@ pub fn verify_signatures(
signers, signers,
initial_creation: true, initial_creation: true,
}) })
.try_to_vec()? .try_to_vec()?,
}) })
} }

View File

@ -8,6 +8,7 @@ use solana_program::msg;
// package as soon as possible. // package as soon as possible.
pub mod accounts; pub mod accounts;
pub mod api; pub mod api;
pub mod client_instructions;
pub mod types; pub mod types;
pub mod vaa; pub mod vaa;
@ -25,14 +26,14 @@ pub use api::{
PostMessageData, PostMessageData,
PostVAA, PostVAA,
PostVAAData, PostVAAData,
Signature,
UninitializedMessage,
UpgradeContract, UpgradeContract,
UpgradeContractData, UpgradeContractData,
UpgradeGuardianSet, UpgradeGuardianSet,
UpgradeGuardianSetData, UpgradeGuardianSetData,
VerifySignatures, VerifySignatures,
VerifySignaturesData, VerifySignaturesData,
UninitializedMessage,
Signature,
}; };
use types::BridgeConfig; use types::BridgeConfig;