diff --git a/solana/bridge/Cargo.lock b/solana/bridge/Cargo.lock index 3f19a0ced..f95de2761 100644 --- a/solana/bridge/Cargo.lock +++ b/solana/bridge/Cargo.lock @@ -339,6 +339,26 @@ dependencies = [ "solitaire-client", ] +[[package]] +name = "bridge_stub" +version = "0.1.0" +dependencies = [ + "borsh", + "bridge", + "byteorder", + "hex", + "hex-literal", + "libsecp256k1", + "primitive-types 0.9.0", + "rand 0.7.3", + "sha3", + "solana-client", + "solana-program", + "solana-sdk", + "solitaire", + "solitaire-client", +] + [[package]] name = "bs58" version = "0.3.1" diff --git a/solana/bridge/Cargo.toml b/solana/bridge/Cargo.toml index 596ba634f..95aa69d9d 100644 --- a/solana/bridge/Cargo.toml +++ b/solana/bridge/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["agent", "program", "client"] \ No newline at end of file +members = ["agent", "program", "client", "program_stub"] \ No newline at end of file diff --git a/solana/bridge/program/src/lib.rs b/solana/bridge/program/src/lib.rs index 6e2327c9e..b9e1b972c 100644 --- a/solana/bridge/program/src/lib.rs +++ b/solana/bridge/program/src/lib.rs @@ -50,8 +50,8 @@ pub use vaa::{ SerializePayload, }; -const MAX_LEN_GUARDIAN_KEYS: usize = 19; -const CHAIN_ID_SOLANA: u16 = 1; +pub const MAX_LEN_GUARDIAN_KEYS: usize = 19; +pub const CHAIN_ID_SOLANA: u16 = 1; solitaire! { Initialize(InitializeData) => initialize, diff --git a/solana/bridge/program_stub/Cargo.toml b/solana/bridge/program_stub/Cargo.toml new file mode 100644 index 000000000..4c5d5f16c --- /dev/null +++ b/solana/bridge/program_stub/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "bridge_stub" +version = "0.1.0" +description = "Wormhole bridge core contract" +edition = "2018" + +[lib] +crate-type = ["cdylib", "lib"] +name = "bridge_stub" + +[features] +client = ["solitaire/client", "solitaire-client", "no-entrypoint"] +cpi = ["no-entrypoint"] +default = [] +no-entrypoint = ["solitaire/no-entrypoint"] +trace = ["solitaire/trace"] + +[dependencies] +borsh = "0.8.1" +byteorder = "1.4.3" +primitive-types = { version = "0.9.0", default-features = false } +sha3 = "0.9.1" +solana-program = "=1.7.0" +solitaire-client = { path = "../../solitaire/client", optional = true } +solitaire = { path = "../../solitaire/program" } +bridge = { path = "../program", features = ["no-entrypoint"] } + +[dev-dependencies] +hex = "*" +rand = "0.7.3" +hex-literal = "0.3.1" +libsecp256k1 = { version = "0.3.5", features = [] } +solana-client = "1.7.0" +solana-sdk = "=1.7.0" diff --git a/solana/bridge/program_stub/Xargo.toml b/solana/bridge/program_stub/Xargo.toml new file mode 100644 index 000000000..1744f098a --- /dev/null +++ b/solana/bridge/program_stub/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] \ No newline at end of file diff --git a/solana/bridge/program_stub/src/api.rs b/solana/bridge/program_stub/src/api.rs new file mode 100644 index 000000000..3457f6a20 --- /dev/null +++ b/solana/bridge/program_stub/src/api.rs @@ -0,0 +1,7 @@ +pub mod post_vaa; + +pub use bridge::{ + initialize::*, + post_message::*, +}; +pub use post_vaa::*; diff --git a/solana/bridge/program_stub/src/api/post_vaa.rs b/solana/bridge/program_stub/src/api/post_vaa.rs new file mode 100644 index 000000000..2aaead9fe --- /dev/null +++ b/solana/bridge/program_stub/src/api/post_vaa.rs @@ -0,0 +1,121 @@ +use solitaire::*; + +use borsh::{ + BorshDeserialize, + BorshSerialize, +}; +use solana_program::{ + self, + sysvar::clock::Clock, +}; + +use bridge::{ + accounts::{ + Bridge, + GuardianSetDerivationData, + Message, + MessageDerivationData, + }, + CHAIN_ID_SOLANA, +}; +use solana_program::pubkey::Pubkey; +use solitaire::{ + processors::seeded::Seeded, + CreationLamports::Exempt, +}; + +impl From<&PostVAAData> for GuardianSetDerivationData { + fn from(data: &PostVAAData) -> Self { + GuardianSetDerivationData { + index: data.guardian_set_index, + } + } +} + +#[derive(FromAccounts)] +pub struct PostVAA<'b> { + /// Information about the current guardian set. + pub guardian_set: Info<'b>, + + /// Bridge Info + pub bridge_info: Bridge<'b, { AccountState::Initialized }>, + + /// Signature Info + pub signature_set: Info<'b>, + + /// Message the VAA is associated with. + pub message: Mut>, + + /// Account used to pay for auxillary instructions. + pub payer: Mut>>, + + /// Clock used for timestamping. + pub clock: Sysvar<'b, Clock>, +} + +impl<'b> InstructionContext<'b> for PostVAA<'b> { + fn verify(&self, _program_id: &Pubkey) -> Result<()> { + Ok(()) + } +} + +#[derive(Default, BorshSerialize, BorshDeserialize)] +pub struct Signature { + pub index: u8, + pub r: [u8; 32], + pub s: [u8; 32], + pub v: u8, +} + +pub type ForeignAddress = [u8; 32]; + +#[derive(Default, BorshSerialize, BorshDeserialize)] +pub struct PostVAAData { + // Header part + pub version: u8, + pub guardian_set_index: u32, + + // Body part + pub timestamp: u32, + pub nonce: u32, + pub emitter_chain: u16, + pub emitter_address: ForeignAddress, + pub sequence: u64, + pub consistency_level: u8, + pub payload: Vec, +} + +pub fn post_vaa(ctx: &ExecutionContext, accs: &mut PostVAA, vaa: PostVAAData) -> Result<()> { + let mut msg_derivation = MessageDerivationData { + emitter_key: vaa.emitter_address, + emitter_chain: vaa.emitter_chain, + nonce: vaa.nonce, + payload: vaa.payload.clone(), + sequence: None, + }; + if vaa.emitter_chain != CHAIN_ID_SOLANA { + msg_derivation.sequence = Some(vaa.sequence) + } + + accs.message + .verify_derivation(ctx.program_id, &msg_derivation)?; + + // If the VAA originates from another chain we need to create the account and populate all fields + if !accs.message.is_initialized() { + accs.message.nonce = vaa.nonce; + accs.message.emitter_chain = vaa.emitter_chain; + accs.message.emitter_address = vaa.emitter_address; + accs.message.sequence = vaa.sequence; + accs.message.payload = vaa.payload; + accs.message.consistency_level = vaa.consistency_level; + accs.message + .create(&msg_derivation, ctx, accs.payer.key, Exempt)?; + } + + // Store VAA data in associated message. + accs.message.vaa_version = vaa.version; + accs.message.vaa_time = vaa.timestamp; + accs.message.vaa_signature_account = *accs.signature_set.info().key; + + Ok(()) +} diff --git a/solana/bridge/program_stub/src/lib.rs b/solana/bridge/program_stub/src/lib.rs new file mode 100644 index 000000000..7fb0aa903 --- /dev/null +++ b/solana/bridge/program_stub/src/lib.rs @@ -0,0 +1,27 @@ +#![feature(const_generics)] +#![allow(non_upper_case_globals)] +#![allow(incomplete_features)] + +pub mod api; + +use solitaire::*; + +pub use api::{ + initialize, + post_message, + post_vaa, + Initialize, + InitializeData, + PostMessage, + PostMessageData, + PostVAA, + PostVAAData, + Signature, + UninitializedMessage, +}; + +solitaire! { + Initialize(InitializeData) => initialize, + PostMessage(PostMessageData) => post_message, + PostVAA(PostVAAData) => post_vaa, +}