From 0a669111dd82f9cc39b25271f2fc6db68e0f004d Mon Sep 17 00:00:00 2001 From: Reisen Date: Thu, 29 Jul 2021 18:21:53 +0000 Subject: [PATCH] Derive Wrapped Mint/Tokens Change-Id: Ic530013e1932daef382cd89b9f14d1069c4006b0 --- solana/bridge/program/src/api/governance.rs | 25 +++++++++++++++++++ solana/bridge/program/src/vaa.rs | 15 ----------- .../token_bridge/program/src/accounts.rs | 11 +++++--- .../program/src/api/complete_transfer.rs | 12 +++++---- .../program/src/api/create_wrapped.rs | 14 ++++++++++- .../program/src/api/governance.rs | 8 +++--- .../token_bridge/program/src/api/transfer.rs | 21 +++++++++++++--- .../token_bridge/program/src/instructions.rs | 11 ++++---- .../token_bridge/program/tests/common.rs | 2 +- .../token_bridge/program/tests/integration.rs | 6 ++--- 10 files changed, 83 insertions(+), 42 deletions(-) diff --git a/solana/bridge/program/src/api/governance.rs b/solana/bridge/program/src/api/governance.rs index c70145c8..7d9c0a50 100644 --- a/solana/bridge/program/src/api/governance.rs +++ b/solana/bridge/program/src/api/governance.rs @@ -2,6 +2,7 @@ use solitaire::*; use solana_program::{ program::invoke_signed, + pubkey::Pubkey, sysvar::{ clock::Clock, rent::Rent, @@ -20,6 +21,7 @@ use crate::{ }, error::Error::{ InvalidFeeRecipient, + InvalidGovernanceKey, InvalidGovernanceWithdrawal, InvalidGuardianSetUpgrade, }, @@ -30,8 +32,27 @@ use crate::{ GovernancePayloadUpgrade, }, vaa::ClaimableVAA, + DeserializePayload, + CHAIN_ID_SOLANA, }; +fn verify_governance<'a, T>(vaa: &ClaimableVAA<'a, T>) -> Result<()> +where + T: DeserializePayload, +{ + let expected_emitter = std::env!("EMITTER_ADDRESS"); + let current_emitter = format!( + "{}", + Pubkey::new_from_array(vaa.message.meta().emitter_address) + ); + // Fail if the emitter is not the known governance key, or the emitting chain is not Solana. + if expected_emitter != current_emitter || vaa.message.meta().emitter_chain != CHAIN_ID_SOLANA { + Err(InvalidGovernanceKey.into()) + } else { + Ok(()) + } +} + #[derive(FromAccounts)] pub struct UpgradeContract<'b> { /// Payer for account creation (vaa-claim) @@ -76,6 +97,7 @@ pub fn upgrade_contract( accs: &mut UpgradeContract, _data: UpgradeContractData, ) -> Result<()> { + verify_governance(&accs.vaa)?; accs.vaa.verify(ctx.program_id)?; accs.vaa.claim(ctx, accs.payer.key)?; @@ -135,6 +157,7 @@ pub fn upgrade_guardian_set( return Err(InvalidGuardianSetUpgrade.into()); } + verify_governance(&accs.vaa)?; accs.vaa.verify(ctx.program_id)?; accs.guardian_set_old.verify_derivation( ctx.program_id, @@ -196,6 +219,7 @@ impl<'b> InstructionContext<'b> for SetFees<'b> { pub struct SetFeesData {} pub fn set_fees(ctx: &ExecutionContext, accs: &mut SetFees, _data: SetFeesData) -> Result<()> { + verify_governance(&accs.vaa)?; accs.vaa.verify(ctx.program_id)?; accs.vaa.claim(ctx, accs.payer.key)?; accs.bridge.config.fee = accs.vaa.fee.as_u64(); @@ -240,6 +264,7 @@ pub fn transfer_fees( return Err(InvalidFeeRecipient.into()); } + verify_governance(&accs.vaa)?; accs.vaa.verify(ctx.program_id)?; if accs diff --git a/solana/bridge/program/src/vaa.rs b/solana/bridge/program/src/vaa.rs index be945ed7..936856b1 100644 --- a/solana/bridge/program/src/vaa.rs +++ b/solana/bridge/program/src/vaa.rs @@ -6,7 +6,6 @@ use crate::{ error::Error::{ InvalidGovernanceAction, InvalidGovernanceChain, - InvalidGovernanceKey, InvalidGovernanceModule, VAAAlreadyExecuted, }, @@ -162,20 +161,6 @@ impl<'b, T: DeserializePayload> ClaimableVAA<'b, T> { pub fn verify(&self, program_id: &Pubkey) -> Result<()> { trace!("Seq: {}", self.message.meta().sequence); - // Do the Posted Message verification - let (expected_emitter, current_emitter) = ( - std::env!("EMITTER_ADDRESS"), - format!( - "{}", - Pubkey::new_from_array(self.message.meta().emitter_address) - ), - ); - - // Fail if the emitter is not the known governance key, or the emitting chain is not Solana. - if expected_emitter != current_emitter || self.message.meta().emitter_chain != CHAIN_ID_SOLANA { - return Err(InvalidGovernanceKey.into()); - } - // Verify that the claim account is derived correctly self.claim.verify_derivation( program_id, diff --git a/solana/modules/token_bridge/program/src/accounts.rs b/solana/modules/token_bridge/program/src/accounts.rs index 8d95c622..ef677a11 100644 --- a/solana/modules/token_bridge/program/src/accounts.rs +++ b/solana/modules/token_bridge/program/src/accounts.rs @@ -54,14 +54,17 @@ impl<'b, const State: AccountState> Seeded<&WrappedDerivationData> for WrappedMi pub type WrappedTokenMeta<'b, const State: AccountState> = Data<'b, WrappedMeta, { State }>; -impl<'b, const State: AccountState> Seeded<&WrappedDerivationData> +pub struct WrappedMetaDerivationData { + pub mint_key: Pubkey, +} + +impl<'b, const State: AccountState> Seeded<&WrappedMetaDerivationData> for WrappedTokenMeta<'b, { State }> { - fn seeds(data: &WrappedDerivationData) -> Vec> { + fn seeds(data: &WrappedMetaDerivationData) -> Vec> { vec![ String::from("meta").as_bytes().to_vec(), - data.token_chain.to_be_bytes().to_vec(), - data.token_address.to_vec(), + data.mint_key.to_bytes().to_vec(), ] } } diff --git a/solana/modules/token_bridge/program/src/api/complete_transfer.rs b/solana/modules/token_bridge/program/src/api/complete_transfer.rs index 8e32fb6e..0e4e5a3e 100644 --- a/solana/modules/token_bridge/program/src/api/complete_transfer.rs +++ b/solana/modules/token_bridge/program/src/api/complete_transfer.rs @@ -90,14 +90,14 @@ pub fn complete_native( accs.custody.verify_derivation(ctx.program_id, &derivation_data)?; // Verify mints - if accs.mint.info().key != accs.to.info().key { + if *accs.mint.info().key != accs.to.mint { return Err(InvalidMint.into()); } - if accs.mint.info().key != accs.custody.info().key { + if *accs.mint.info().key != accs.custody.mint { return Err(InvalidMint.into()); } - if &accs.custody.owner != accs.custody_signer.key { - return Err(InvalidMint.into()); + if *accs.custody_signer.key != accs.custody.owner { + return Err(WrongAccountOwner.into()); } // Verify VAA @@ -109,6 +109,7 @@ pub fn complete_native( } // Prevent vaa double signing + accs.vaa.verify(ctx.program_id)?; accs.vaa.claim(ctx, accs.payer.key)?; let mut amount = accs.vaa.amount.as_u64(); @@ -189,10 +190,11 @@ pub fn complete_wrapped( accs.mint.verify_derivation(ctx.program_id, &derivation_data)?; // Verify mints - if accs.mint.info().key != accs.to.info().key { + if *accs.mint.info().key != accs.to.mint { return Err(InvalidMint.into()); } + accs.vaa.verify(ctx.program_id)?; accs.vaa.claim(ctx, accs.payer.key)?; // Mint tokens diff --git a/solana/modules/token_bridge/program/src/api/create_wrapped.rs b/solana/modules/token_bridge/program/src/api/create_wrapped.rs index c81cddeb..42c75b80 100644 --- a/solana/modules/token_bridge/program/src/api/create_wrapped.rs +++ b/solana/modules/token_bridge/program/src/api/create_wrapped.rs @@ -4,6 +4,7 @@ use crate::{ Endpoint, EndpointDerivationData, MintSigner, + WrappedMetaDerivationData, WrappedDerivationData, WrappedMint, WrappedTokenMeta, @@ -71,6 +72,14 @@ impl<'a> From<&CreateWrapped<'a>> for WrappedDerivationData { } } +impl<'a> From<&CreateWrapped<'a>> for WrappedMetaDerivationData { + fn from(accs: &CreateWrapped<'a>) -> Self { + WrappedMetaDerivationData { + mint_key: *accs.mint.info().key, + } + } +} + impl<'b> InstructionContext<'b> for CreateWrapped<'b> { } @@ -84,11 +93,14 @@ pub fn create_wrapped( ) -> Result<()> { let derivation_data: WrappedDerivationData = (&*accs).into(); accs.mint.verify_derivation(ctx.program_id, &derivation_data)?; - accs.meta.verify_derivation(ctx.program_id, &derivation_data)?; + + let meta_derivation_data: WrappedMetaDerivationData = (&*accs).into(); + accs.meta.verify_derivation(ctx.program_id, &meta_derivation_data)?; let derivation_data: EndpointDerivationData = (&*accs).into(); accs.chain_registration.verify_derivation(ctx.program_id, &derivation_data)?; + accs.vaa.verify(ctx.program_id)?; accs.vaa.claim(ctx, accs.payer.key)?; // Create mint account diff --git a/solana/modules/token_bridge/program/src/api/governance.rs b/solana/modules/token_bridge/program/src/api/governance.rs index d1e8c673..35966956 100644 --- a/solana/modules/token_bridge/program/src/api/governance.rs +++ b/solana/modules/token_bridge/program/src/api/governance.rs @@ -40,7 +40,7 @@ use std::ops::{ }; // Confirm that a ClaimableVAA came from the correct chain, signed by the right emitter. -fn verify_claim<'a, T>(vaa: &ClaimableVAA<'a, T>) -> Result<()> +fn verify_governance<'a, T>(vaa: &ClaimableVAA<'a, T>) -> Result<()> where T: DeserializePayload, { @@ -49,7 +49,6 @@ where "{}", Pubkey::new_from_array(vaa.message.meta().emitter_address) ); - // Fail if the emitter is not the known governance key, or the emitting chain is not Solana. if expected_emitter != current_emitter || vaa.message.meta().emitter_chain != CHAIN_ID_SOLANA { Err(InvalidGovernanceKey.into()) @@ -99,7 +98,8 @@ pub fn upgrade_contract( accs: &mut UpgradeContract, _data: UpgradeContractData, ) -> Result<()> { - verify_claim(&accs.vaa)?; + verify_governance(&accs.vaa); + accs.vaa.verify(&ctx.program_id)?; accs.vaa.claim(ctx, accs.payer.key)?; @@ -154,6 +154,8 @@ pub fn register_chain( accs.endpoint.verify_derivation(ctx.program_id, &derivation_data)?; // Claim VAA + verify_governance(&accs.vaa); + accs.vaa.verify(&ctx.program_id)?; accs.vaa.claim(ctx, accs.payer.key)?; // Create endpoint diff --git a/solana/modules/token_bridge/program/src/api/transfer.rs b/solana/modules/token_bridge/program/src/api/transfer.rs index 08789e3a..7547751f 100644 --- a/solana/modules/token_bridge/program/src/api/transfer.rs +++ b/solana/modules/token_bridge/program/src/api/transfer.rs @@ -8,6 +8,7 @@ use crate::{ EmitterAccount, MintSigner, WrappedDerivationData, + WrappedMetaDerivationData, WrappedMint, WrappedTokenMeta, }, @@ -123,10 +124,11 @@ pub fn transfer_native( ) -> Result<()> { // Verify that the custody account is derived correctly let derivation_data: CustodyAccountDerivationData = (&*accs).into(); - accs.custody.verify_derivation(ctx.program_id, &derivation_data)?; + accs.custody + .verify_derivation(ctx.program_id, &derivation_data)?; // Verify mints - if accs.mint.info().key != accs.from.info().key { + if accs.from.mint != *accs.mint.info().key { return Err(TokenBridgeError::InvalidMint.into()); } @@ -243,6 +245,14 @@ impl<'a> From<&TransferWrapped<'a>> for WrappedDerivationData { } } +impl<'a> From<&TransferWrapped<'a>> for WrappedMetaDerivationData { + fn from(accs: &TransferWrapped<'a>) -> Self { + WrappedMetaDerivationData { + mint_key: *accs.mint.info().key, + } + } +} + impl<'b> InstructionContext<'b> for TransferWrapped<'b> { } @@ -271,8 +281,11 @@ pub fn transfer_wrapped( } // Verify that meta is correct - accs.wrapped_meta - .verify_derivation(ctx.program_id, &(&*accs).into())?; + let derivation_data: WrappedMetaDerivationData = (&*accs).into(); + accs.wrapped_meta.verify_derivation( + ctx.program_id, + &derivation_data, + )?; // Burn tokens let burn_ix = spl_token::instruction::burn( diff --git a/solana/modules/token_bridge/program/src/instructions.rs b/solana/modules/token_bridge/program/src/instructions.rs index 6bbd083b..700f8f5c 100644 --- a/solana/modules/token_bridge/program/src/instructions.rs +++ b/solana/modules/token_bridge/program/src/instructions.rs @@ -10,6 +10,7 @@ use crate::{ EndpointDerivationData, MintSigner, WrappedDerivationData, + WrappedMetaDerivationData, WrappedMint, WrappedTokenMeta, }, @@ -215,9 +216,8 @@ pub fn create_wrapped( &program_id, ); let mint_meta_key = WrappedTokenMeta::<'_, { AccountState::Uninitialized }>::key( - &WrappedDerivationData { - token_chain: payload.token_chain, - token_address: payload.token_address, + &WrappedMetaDerivationData { + mint_key, }, &program_id, ); @@ -395,9 +395,8 @@ pub fn transfer_wrapped( &program_id, ); let wrapped_meta_key = WrappedTokenMeta::<'_, { AccountState::Uninitialized }>::key( - &WrappedDerivationData { - token_chain, - token_address, + &WrappedMetaDerivationData { + mint_key: wrapped_mint_key, }, &program_id, ); diff --git a/solana/modules/token_bridge/program/tests/common.rs b/solana/modules/token_bridge/program/tests/common.rs index 8b66195d..07e48670 100644 --- a/solana/modules/token_bridge/program/tests/common.rs +++ b/solana/modules/token_bridge/program/tests/common.rs @@ -381,7 +381,7 @@ mod helpers { ) } - pub fn complete_transfer_native( + pub fn complete_native( client: &RpcClient, program: &Pubkey, bridge: &Pubkey, diff --git a/solana/modules/token_bridge/program/tests/integration.rs b/solana/modules/token_bridge/program/tests/integration.rs index 6d246eb2..50f59d03 100644 --- a/solana/modules/token_bridge/program/tests/integration.rs +++ b/solana/modules/token_bridge/program/tests/integration.rs @@ -293,7 +293,7 @@ fn test_transfer_native(context: &mut Context) -> () { } fn test_transfer_wrapped(context: &mut Context, token_account: Pubkey) -> () { - println!("Transfer Wrapped"); + println!("TransferWrapped"); use token_bridge::{ accounts::ConfigAccount, types::Config, @@ -401,7 +401,7 @@ fn test_transfer_native_in(context: &mut Context) -> () { let (vaa, _, _) = common::generate_vaa([0u8; 32], 2, message, nonce, 1); let message_key = common::post_vaa(client, bridge, payer, vaa.clone()).unwrap(); - common::complete_transfer_native( + common::complete_native( client, token_bridge, bridge, @@ -414,7 +414,7 @@ fn test_transfer_native_in(context: &mut Context) -> () { } fn test_transfer_wrapped_in(context: &mut Context, to: Pubkey) -> () { - println!("TransferWrapped"); + println!("TransferWrappedIn"); use token_bridge::{ accounts::ConfigAccount, types::Config,