diff --git a/solana/bridge/src/error.rs b/solana/bridge/src/error.rs index 356d58fe..9ed7496a 100644 --- a/solana/bridge/src/error.rs +++ b/solana/bridge/src/error.rs @@ -1,6 +1,8 @@ //! Error types use num_derive::FromPrimitive; +use num_traits::FromPrimitive; +use solana_program::program_error::PrintProgramError; use solana_program::{decode_error::DecodeError, program_error::ProgramError}; use thiserror::Error; @@ -31,12 +33,6 @@ pub enum Error { /// The deserialization of the GuardianSet state returned something besides State::GuardianSet. #[error("ExpectedGuardianSet")] ExpectedGuardianSet, - /// The deserialization of the TransferOutProposal state returned something besides State::TransferOutProposal. - #[error("ExpectedTransferOutProposal")] - ExpectedTransferOutProposal, - /// The deserialization of the GuardianSet state returned something besides State::WrappedAssetMeta. - #[error("ExpectedWrappedAssetMeta")] - ExpectedWrappedAssetMeta, /// State is uninitialized. #[error("State is unititialized")] UninitializedState, @@ -58,18 +54,9 @@ pub enum Error { /// An account was not derived correctly #[error("InvalidDerivedAccount")] InvalidDerivedAccount, - /// A given token account does not belong to the given mint - #[error("TokenMintMismatch")] - TokenMintMismatch, - /// A given mint account does not belong to the program - #[error("WrongMintOwner")] - WrongMintOwner, /// A given bridge account does not belong to the program #[error("WrongBridgeOwner")] WrongBridgeOwner, - /// A given token account does not belong to the program - #[error("WrongTokenAccountOwner")] - WrongTokenAccountOwner, /// A parsing operation failed #[error("ParseFailed")] ParseFailed, @@ -87,16 +74,10 @@ pub enum Error { GuardianIndexNotIncreasing, /// The given VAA does not match the proposal #[error("VAAProposalMismatch")] - VAAProposalMismatch, - /// Invalid transfer with src=dst - #[error("SameChainTransfer")] - SameChainTransfer, + VAAMessageMismatch, /// VAA is longer than the maximum size #[error("VAATooLong")] VAATooLong, - /// Cannot wrap a solana native asset - #[error("CannotWrapNative")] - CannotWrapNative, /// VAA for this transfer has already been submitted #[error("VAAAlreadySubmitted")] VAAAlreadySubmitted, @@ -115,6 +96,46 @@ pub enum Error { /// Invalid Chain #[error("InvalidChain")] InvalidChain, + /// Emitter is not a signer + #[error("EmitterNotSigner")] + EmitterNotSigner, +} + +#[cfg(feature = "program")] +impl PrintProgramError for Error { + fn print(&self) + where + E: 'static + std::error::Error + DecodeError + PrintProgramError + FromPrimitive, + { + match self { + Error::ExpectedToken => msg!("Error: ExpectedToken"), + Error::ExpectedAccount => msg!("Error: ExpectedAccount"), + Error::ExpectedBridge => msg!("Error: ExpectedBridge"), + Error::ExpectedGuardianSet => msg!("Error: ExpectedGuardianSet"), + Error::UninitializedState => msg!("Error: State is unititialized"), + Error::InvalidProgramAddress => msg!("Error: InvalidProgramAddress"), + Error::InvalidVAAFormat => msg!("Error: InvalidVAAFormat"), + Error::InvalidVAASignature => msg!("Error: InvalidVAASignature"), + Error::AlreadyExists => msg!("Error: AlreadyExists"), + Error::InvalidDerivedAccount => msg!("Error: InvalidDerivedAccount"), + Error::ParseFailed => msg!("Error: ParseFailed"), + Error::GuardianSetExpired => msg!("Error: GuardianSetExpired"), + Error::VAAClaimed => msg!("Error: VAAClaimed"), + Error::WrongBridgeOwner => msg!("Error: WrongBridgeOwner"), + Error::OldGuardianSet => msg!("Error: OldGuardianSet"), + Error::GuardianIndexNotIncreasing => msg!("Error: GuardianIndexNotIncreasing"), + Error::VAAMessageMismatch => msg!("Error: VAAProposalMismatch"), + Error::VAATooLong => msg!("Error: VAATooLong"), + Error::VAAAlreadySubmitted => msg!("Error: VAAAlreadySubmitted"), + Error::GuardianSetMismatch => msg!("Error: GuardianSetMismatch"), + Error::InsufficientFees => msg!("Error: InsufficientFees"), + Error::InvalidOwner => msg!("Error: InvalidOwner"), + Error::InvalidSysvar => msg!("Error: InvalidSysvar"), + Error::InvalidChain => msg!("Error: InvalidChain"), + Error::InvalidVAAAction => msg!("Error: InvalidVAAAction"), + Error::EmitterNotSigner => msg!("Error: EmitterNotSigner"), + } + } } impl From for ProgramError { diff --git a/solana/bridge/src/error_program.rs b/solana/bridge/src/error_program.rs deleted file mode 100644 index 40151b91..00000000 --- a/solana/bridge/src/error_program.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![cfg(feature = "program")] - -use num_traits::FromPrimitive; -use solana_program::{decode_error::DecodeError, program_error::PrintProgramError}; - -use crate::error::*; - -impl PrintProgramError for Error { - fn print(&self) - where - E: 'static + std::error::Error + DecodeError + PrintProgramError + FromPrimitive, - { - match self { - Error::ExpectedToken => msg!("Error: ExpectedToken"), - Error::ExpectedAccount => msg!("Error: ExpectedAccount"), - Error::ExpectedBridge => msg!("Error: ExpectedBridge"), - Error::ExpectedGuardianSet => msg!("Error: ExpectedGuardianSet"), - Error::ExpectedWrappedAssetMeta => msg!("Error: ExpectedWrappedAssetMeta"), - Error::UninitializedState => msg!("Error: State is unititialized"), - Error::InvalidProgramAddress => msg!("Error: InvalidProgramAddress"), - Error::InvalidVAAFormat => msg!("Error: InvalidVAAFormat"), - Error::InvalidVAAAction => msg!("Error: InvalidVAAAction"), - Error::InvalidVAASignature => msg!("Error: InvalidVAASignature"), - Error::AlreadyExists => msg!("Error: AlreadyExists"), - Error::InvalidDerivedAccount => msg!("Error: InvalidDerivedAccount"), - Error::TokenMintMismatch => msg!("Error: TokenMintMismatch"), - Error::WrongMintOwner => msg!("Error: WrongMintOwner"), - Error::WrongTokenAccountOwner => msg!("Error: WrongTokenAccountOwner"), - Error::ParseFailed => msg!("Error: ParseFailed"), - Error::GuardianSetExpired => msg!("Error: GuardianSetExpired"), - Error::VAAClaimed => msg!("Error: VAAClaimed"), - Error::WrongBridgeOwner => msg!("Error: WrongBridgeOwner"), - Error::OldGuardianSet => msg!("Error: OldGuardianSet"), - Error::GuardianIndexNotIncreasing => msg!("Error: GuardianIndexNotIncreasing"), - Error::ExpectedTransferOutProposal => msg!("Error: ExpectedTransferOutProposal"), - Error::VAAProposalMismatch => msg!("Error: VAAProposalMismatch"), - Error::SameChainTransfer => msg!("Error: SameChainTransfer"), - Error::VAATooLong => msg!("Error: VAATooLong"), - Error::CannotWrapNative => msg!("Error: CannotWrapNative"), - Error::VAAAlreadySubmitted => msg!("Error: VAAAlreadySubmitted"), - Error::GuardianSetMismatch => msg!("Error: GuardianSetMismatch"), - Error::InsufficientFees => msg!("Error: InsufficientFees"), - Error::InvalidOwner => msg!("Error: InvalidOwner"), - Error::InvalidSysvar => msg!("Error: InvalidSysvar"), - Error::InvalidChain => msg!("Error: InvalidChain"), - } - } -} diff --git a/solana/bridge/src/vaa.rs b/solana/bridge/src/vaa.rs index f080de5e..ad51b809 100644 --- a/solana/bridge/src/vaa.rs +++ b/solana/bridge/src/vaa.rs @@ -1,11 +1,10 @@ use std::io::{Cursor, Read, Write}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use primitive_types::U256; use sha3::Digest; use solana_program::program_error::ProgramError; -use crate::{error::Error, state::AssetMeta}; +use crate::error::Error; use solana_program::pubkey::Pubkey; pub type ForeignAddress = [u8; 32]; @@ -19,7 +18,10 @@ pub struct VAA { // Body part pub timestamp: u32, - pub payload: Option, + pub nonce: u32, + pub emitter_chain: u8, + pub emitter_address: ForeignAddress, + pub payload: Vec, } #[derive(Clone, Copy, Debug, Default, PartialEq)] @@ -37,7 +39,10 @@ impl VAA { guardian_set_index: 0, signatures: vec![], timestamp: 0, - payload: None, + emitter_chain: 0, + emitter_address: [0u8; 32], + nonce: 0, + payload: vec![], }; } @@ -71,12 +76,10 @@ impl VAA { } v.write_u32::(self.timestamp)?; - - let payload = self.payload.as_ref().ok_or(Error::InvalidVAAAction)?; - v.write_u8(payload.action_id())?; - - let payload_data = payload.serialize()?; - v.write(payload_data.as_slice())?; + v.write_u32::(self.nonce)?; + v.write_u8(self.emitter_chain)?; + v.write(&self.emitter_address)?; + v.write(&self.payload)?; Ok(v.into_inner()) } @@ -85,12 +88,10 @@ impl VAA { let mut v = Cursor::new(Vec::new()); v.write_u32::(self.timestamp)?; - - let payload = self.payload.as_ref().ok_or(Error::InvalidVAAAction)?; - v.write_u8(payload.action_id())?; - - let payload_data = payload.serialize()?; - v.write(payload_data.as_slice())?; + v.write_u32::(self.nonce)?; + v.write_u8(self.emitter_chain)?; + v.write(&self.emitter_address)?; + v.write(&self.payload)?; Ok(v.into_inner()) } @@ -117,388 +118,11 @@ impl VAA { v.signatures = sigs; v.timestamp = rdr.read_u32::()?; - - let mut payload_d = Vec::new(); - rdr.read_to_end(&mut payload_d)?; - v.payload = Some(VAABody::deserialize(&payload_d)?); + v.nonce = rdr.read_u32::()?; + v.emitter_chain = rdr.read_u8()?; + rdr.read_exact(&mut v.emitter_address)?; + rdr.read_to_end(&mut v.payload)?; Ok(v) } } - -#[derive(Clone, Debug, PartialEq)] -pub enum VAABody { - UpdateGuardianSet(BodyUpdateGuardianSet), - Transfer(BodyTransfer), - UpgradeContract(BodyContractUpgrade), -} - -impl VAABody { - fn action_id(&self) -> u8 { - match self { - VAABody::UpdateGuardianSet(_) => 0x01, - VAABody::UpgradeContract(_) => 0x02, - VAABody::Transfer(_) => 0x10, - } - } - - fn deserialize(data: &Vec) -> Result { - let mut payload_data = Cursor::new(data); - let action = payload_data.read_u8()?; - - let payload = match action { - 0x01 => { - VAABody::UpdateGuardianSet(BodyUpdateGuardianSet::deserialize(&mut payload_data)?) - } - 0x02 => VAABody::UpgradeContract(BodyContractUpgrade::deserialize(&mut payload_data)?), - 0x10 => VAABody::Transfer(BodyTransfer::deserialize(&mut payload_data)?), - _ => { - return Err(Error::InvalidVAAAction); - } - }; - - Ok(payload) - } - - fn serialize(&self) -> Result, Error> { - match self { - VAABody::Transfer(b) => b.serialize(), - VAABody::UpdateGuardianSet(b) => b.serialize(), - VAABody::UpgradeContract(b) => b.serialize(), - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BodyUpdateGuardianSet { - pub new_index: u32, - pub new_keys: Vec<[u8; 20]>, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BodyTransfer { - pub nonce: u32, - pub source_chain: u8, - pub target_chain: u8, - pub source_address: ForeignAddress, - pub target_address: ForeignAddress, - pub asset: AssetMeta, - pub amount: U256, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BodyContractUpgrade { - pub chain_id: u8, - pub buffer: Pubkey, -} - -impl BodyContractUpgrade { - fn deserialize(data: &mut Cursor<&Vec>) -> Result { - let chain_id = data.read_u8()?; - let mut key: [u8; 32] = [0; 32]; - data.read(&mut key[..])?; - - Ok(BodyContractUpgrade { - chain_id, - buffer: Pubkey::new(&key[..]), - }) - } - - fn serialize(&self) -> Result, Error> { - let mut v: Cursor> = Cursor::new(Vec::new()); - v.write_u8(self.chain_id)?; - v.write(&self.buffer.to_bytes()); - - Ok(v.into_inner()) - } -} - - -impl BodyUpdateGuardianSet { - fn deserialize(data: &mut Cursor<&Vec>) -> Result { - let new_index = data.read_u32::()?; - - let keys_len = data.read_u8()?; - let mut keys = Vec::with_capacity(keys_len as usize); - for _ in 0..keys_len { - let mut key: [u8; 20] = [0; 20]; - data.read(&mut key)?; - keys.push(key); - } - - Ok(BodyUpdateGuardianSet { - new_index, - new_keys: keys, - }) - } - - fn serialize(&self) -> Result, Error> { - let mut v: Cursor> = Cursor::new(Vec::new()); - v.write_u32::(self.new_index)?; - v.write_u8(self.new_keys.len() as u8)?; - - for k in self.new_keys.iter() { - v.write(k)?; - } - - Ok(v.into_inner()) - } -} - -impl BodyTransfer { - fn deserialize(data: &mut Cursor<&Vec>) -> Result { - let nonce = data.read_u32::()?; - let source_chain = data.read_u8()?; - let target_chain = data.read_u8()?; - let mut source_address: ForeignAddress = ForeignAddress::default(); - data.read_exact(&mut source_address)?; - let mut target_address: ForeignAddress = ForeignAddress::default(); - data.read_exact(&mut target_address)?; - let token_chain = data.read_u8()?; - let mut token_address: ForeignAddress = ForeignAddress::default(); - data.read_exact(&mut token_address)?; - let token_decimals = data.read_u8()?; - - let mut am_data: [u8; 32] = [0; 32]; - data.read_exact(&mut am_data)?; - let amount = U256::from_big_endian(&am_data); - - Ok(BodyTransfer { - nonce, - source_chain, - target_chain, - source_address, - target_address, - asset: AssetMeta { - address: token_address, - chain: token_chain, - decimals: token_decimals, - }, - amount, - }) - } - - fn serialize(&self) -> Result, Error> { - let mut v: Cursor> = Cursor::new(Vec::new()); - v.write_u32::(self.nonce)?; - v.write_u8(self.source_chain)?; - v.write_u8(self.target_chain)?; - v.write(&self.source_address)?; - v.write(&self.target_address)?; - v.write_u8(self.asset.chain)?; - v.write(&self.asset.address)?; - v.write_u8(self.asset.decimals)?; - - let mut am_data: [u8; 32] = [0; 32]; - self.amount.to_big_endian(&mut am_data); - v.write(&am_data[..])?; - - Ok(v.into_inner()) - } -} - -#[cfg(test)] -mod tests { - use hex; - use primitive_types::U256; - - use crate::{ - state::AssetMeta, - vaa::{BodyTransfer, BodyUpdateGuardianSet, Signature, VAABody, VAA}, - }; - use crate::vaa::BodyContractUpgrade; - use solana_program::pubkey::Pubkey; - - #[test] - fn serialize_deserialize_vaa_transfer() { - let vaa = VAA { - version: 8, - guardian_set_index: 3, - signatures: vec![Signature { - index: 1, - r: [2; 32], - s: [2; 32], - v: 7, - }], - timestamp: 83, - payload: Some(VAABody::Transfer(BodyTransfer { - nonce: 28, - source_chain: 1, - target_chain: 2, - source_address: [1; 32], - target_address: [1; 32], - asset: AssetMeta { - address: [2; 32], - chain: 8, - decimals: 9, - }, - amount: U256::from(3), - })), - }; - - let data = vaa.serialize().unwrap(); - let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap(); - assert_eq!(vaa, parsed_vaa) - } - - #[test] - fn serialize_deserialize_vaa_guardian() { - let vaa = VAA { - version: 8, - guardian_set_index: 3, - signatures: vec![Signature { - index: 1, - r: [2; 32], - s: [2; 32], - v: 7, - }], - timestamp: 83, - payload: Some(VAABody::UpdateGuardianSet(BodyUpdateGuardianSet { - new_index: 29, - new_keys: vec![], - })), - }; - - let data = vaa.serialize().unwrap(); - let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap(); - assert_eq!(vaa, parsed_vaa) - } - - #[test] - fn serialize_deserialize_vaa_contract_upgrade() { - let vaa = VAA { - version: 8, - guardian_set_index: 3, - signatures: vec![Signature { - index: 1, - r: [2; 32], - s: [2; 32], - v: 7, - }], - timestamp: 83, - payload: Some(VAABody::UpgradeContract(BodyContractUpgrade { - chain_id: 3, - buffer: Pubkey::new_unique(), - })), - }; - - let data = vaa.serialize().unwrap(); - let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap(); - assert_eq!(vaa, parsed_vaa) - } - - #[test] - fn parse_given_guardian_set_update() { - let vaa = VAA { - version: 1, - guardian_set_index: 0, - signatures: vec![Signature { - index: 0, - r: [ - 51, 130, 199, 26, 76, 121, 225, 81, 138, 108, 226, 156, 145, 86, 159, 100, 39, - 166, 10, 149, 105, 106, 53, 21, 184, 194, 52, 11, 106, 207, 253, 114, - ], - s: [ - 51, 21, 189, 16, 17, 170, 119, 159, 34, 87, 56, 130, 164, 237, 254, 27, 130, 6, - 84, 142, 19, 72, 113, 162, 63, 139, 160, 193, 199, 208, 181, 237, - ], - v: 1, - }], - timestamp: 3000, - payload: Some(VAABody::UpdateGuardianSet(BodyUpdateGuardianSet { - new_index: 1, - new_keys: vec![[ - 190, 250, 66, 157, 87, 205, 24, 183, 248, 164, 217, 26, 45, 169, 171, 74, 240, - 93, 15, 190, - ]], - })), - }; - let data = hex::decode("010000000001003382c71a4c79e1518a6ce29c91569f6427a60a95696a3515b8c2340b6acffd723315bd1011aa779f22573882a4edfe1b8206548e134871a23f8ba0c1c7d0b5ed0100000bb8010000000101befa429d57cd18b7f8a4d91a2da9ab4af05d0fbe").unwrap(); - let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap(); - assert_eq!(vaa, parsed_vaa); - - let rec_data = parsed_vaa.serialize().unwrap(); - assert_eq!(data, rec_data); - } - - #[test] - fn parse_given_transfer() { - let vaa = VAA { - version: 1, - guardian_set_index: 0, - signatures: vec![Signature { - index: 0, - r: [ - 146, 115, 122, 21, 4, 243, 179, 223, 140, 147, 203, 133, 198, 74, 72, 96, 187, - 39, 14, 38, 2, 107, 110, 55, 240, 149, 53, 106, 64, 111, 106, 244, - ], - s: [ - 57, 198, 178, 233, 119, 95, 161, 198, 102, 149, 37, 240, 110, 218, 176, 51, - 186, 93, 68, 115, 8, 244, 227, 189, 179, 60, 15, 54, 29, 195, 46, 195, - ], - v: 1, - }], - timestamp: 1597440008, - payload: Some(VAABody::Transfer(BodyTransfer { - nonce: 53, - source_chain: 1, - target_chain: 2, - source_address: [ - 2, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - ], - target_address: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 248, 191, 106, 71, 159, 50, 14, 173, - 7, 68, 17, 164, 176, 231, 148, 78, 168, 201, 193, - ], - asset: AssetMeta { - address: [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 71, 239, 52, 104, 123, 220, 159, 24, - 158, 135, 169, 32, 6, 88, 217, 196, 14, 153, 136, - ], - chain: 1, - decimals: 8, - }, - amount: U256::from_dec_str("5000000000000000000").unwrap(), - })), - }; - let data = hex::decode("0100000000010092737a1504f3b3df8c93cb85c64a4860bb270e26026b6e37f095356a406f6af439c6b2e9775fa1c6669525f06edab033ba5d447308f4e3bdb33c0f361dc32ec3015f37000810000000350102020104000000000000000000000000000000000000000000000000000000000000000000000000000000000090f8bf6a479f320ead074411a4b0e7944ea8c9c1010000000000000000000000000347ef34687bdc9f189e87a9200658d9c40e9988080000000000000000000000000000000000000000000000004563918244f40000").unwrap(); - let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap(); - assert_eq!(vaa, parsed_vaa); - - let rec_data = parsed_vaa.serialize().unwrap(); - assert_eq!(data, rec_data); - } - - #[test] - fn parse_given_contract_upgrade() { - let vaa = VAA { - version: 1, - guardian_set_index: 2, - signatures: vec![Signature { - index: 0, - r: [ - 72, 156, 56, 20, 222, 146, 161, 112, 22, 97, 69, 59, 188, 199, 130, 240, 89, - 249, 241, 79, 96, 27, 235, 10, 99, 16, 56, 80, 232, 188, 235, 11 - ], - s: [ - 65, 19, 144, 42, 104, 122, 52, 0, 126, 7, 43, 127, 120, 85, 5, 21, 216, 207, - 78, 73, 213, 207, 142, 103, 211, 192, 100, 90, 27, 98, 176, 98 - ], - v: 1, - }], - timestamp: 4000, - payload: Some(VAABody::UpgradeContract(BodyContractUpgrade { - chain_id: 2, - buffer: Pubkey::new(&[146, 115, 122, 21, 4, 243, 179, 223, 140, 147, 203, 133, 198, 74, 72, 96, 187, - 39, 14, 38, 2, 107, 110, 55, 240, 149, 53, 106, 64, 111, 106, 244]), - })), - }; - let data = hex::decode("01000000020100489c3814de92a1701661453bbcc782f059f9f14f601beb0a63103850e8bceb0b4113902a687a34007e072b7f78550515d8cf4e49d5cf8e67d3c0645a1b62b0620100000fa0020292737a1504f3b3df8c93cb85c64a4860bb270e26026b6e37f095356a406f6af4").unwrap(); - let parsed_vaa = VAA::deserialize(data.as_slice()).unwrap(); - assert_eq!(vaa, parsed_vaa); - - let rec_data = parsed_vaa.serialize().unwrap(); - assert_eq!(data, rec_data); - } -}