Derive Wrapped Mint/Tokens

Change-Id: Ic530013e1932daef382cd89b9f14d1069c4006b0
This commit is contained in:
Reisen 2021-07-29 18:21:53 +00:00 committed by David Paryente
parent 108a4a2ff9
commit 0a669111dd
10 changed files with 83 additions and 42 deletions

View File

@ -2,6 +2,7 @@ use solitaire::*;
use solana_program::{ use solana_program::{
program::invoke_signed, program::invoke_signed,
pubkey::Pubkey,
sysvar::{ sysvar::{
clock::Clock, clock::Clock,
rent::Rent, rent::Rent,
@ -20,6 +21,7 @@ use crate::{
}, },
error::Error::{ error::Error::{
InvalidFeeRecipient, InvalidFeeRecipient,
InvalidGovernanceKey,
InvalidGovernanceWithdrawal, InvalidGovernanceWithdrawal,
InvalidGuardianSetUpgrade, InvalidGuardianSetUpgrade,
}, },
@ -30,8 +32,27 @@ use crate::{
GovernancePayloadUpgrade, GovernancePayloadUpgrade,
}, },
vaa::ClaimableVAA, 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)] #[derive(FromAccounts)]
pub struct UpgradeContract<'b> { pub struct UpgradeContract<'b> {
/// Payer for account creation (vaa-claim) /// Payer for account creation (vaa-claim)
@ -76,6 +97,7 @@ pub fn upgrade_contract(
accs: &mut UpgradeContract, accs: &mut UpgradeContract,
_data: UpgradeContractData, _data: UpgradeContractData,
) -> Result<()> { ) -> Result<()> {
verify_governance(&accs.vaa)?;
accs.vaa.verify(ctx.program_id)?; accs.vaa.verify(ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?; accs.vaa.claim(ctx, accs.payer.key)?;
@ -135,6 +157,7 @@ pub fn upgrade_guardian_set(
return Err(InvalidGuardianSetUpgrade.into()); return Err(InvalidGuardianSetUpgrade.into());
} }
verify_governance(&accs.vaa)?;
accs.vaa.verify(ctx.program_id)?; accs.vaa.verify(ctx.program_id)?;
accs.guardian_set_old.verify_derivation( accs.guardian_set_old.verify_derivation(
ctx.program_id, ctx.program_id,
@ -196,6 +219,7 @@ impl<'b> InstructionContext<'b> for SetFees<'b> {
pub struct SetFeesData {} pub struct SetFeesData {}
pub fn set_fees(ctx: &ExecutionContext, accs: &mut SetFees, _data: SetFeesData) -> Result<()> { pub fn set_fees(ctx: &ExecutionContext, accs: &mut SetFees, _data: SetFeesData) -> Result<()> {
verify_governance(&accs.vaa)?;
accs.vaa.verify(ctx.program_id)?; accs.vaa.verify(ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?; accs.vaa.claim(ctx, accs.payer.key)?;
accs.bridge.config.fee = accs.vaa.fee.as_u64(); accs.bridge.config.fee = accs.vaa.fee.as_u64();
@ -240,6 +264,7 @@ pub fn transfer_fees(
return Err(InvalidFeeRecipient.into()); return Err(InvalidFeeRecipient.into());
} }
verify_governance(&accs.vaa)?;
accs.vaa.verify(ctx.program_id)?; accs.vaa.verify(ctx.program_id)?;
if accs if accs

View File

@ -6,7 +6,6 @@ use crate::{
error::Error::{ error::Error::{
InvalidGovernanceAction, InvalidGovernanceAction,
InvalidGovernanceChain, InvalidGovernanceChain,
InvalidGovernanceKey,
InvalidGovernanceModule, InvalidGovernanceModule,
VAAAlreadyExecuted, VAAAlreadyExecuted,
}, },
@ -162,20 +161,6 @@ impl<'b, T: DeserializePayload> ClaimableVAA<'b, T> {
pub fn verify(&self, program_id: &Pubkey) -> Result<()> { pub fn verify(&self, program_id: &Pubkey) -> Result<()> {
trace!("Seq: {}", self.message.meta().sequence); 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 // Verify that the claim account is derived correctly
self.claim.verify_derivation( self.claim.verify_derivation(
program_id, program_id,

View File

@ -54,14 +54,17 @@ impl<'b, const State: AccountState> Seeded<&WrappedDerivationData> for WrappedMi
pub type WrappedTokenMeta<'b, const State: AccountState> = Data<'b, WrappedMeta, { State }>; 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 }> for WrappedTokenMeta<'b, { State }>
{ {
fn seeds(data: &WrappedDerivationData) -> Vec<Vec<u8>> { fn seeds(data: &WrappedMetaDerivationData) -> Vec<Vec<u8>> {
vec![ vec![
String::from("meta").as_bytes().to_vec(), String::from("meta").as_bytes().to_vec(),
data.token_chain.to_be_bytes().to_vec(), data.mint_key.to_bytes().to_vec(),
data.token_address.to_vec(),
] ]
} }
} }

View File

@ -90,14 +90,14 @@ pub fn complete_native(
accs.custody.verify_derivation(ctx.program_id, &derivation_data)?; accs.custody.verify_derivation(ctx.program_id, &derivation_data)?;
// Verify mints // Verify mints
if accs.mint.info().key != accs.to.info().key { if *accs.mint.info().key != accs.to.mint {
return Err(InvalidMint.into()); 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()); return Err(InvalidMint.into());
} }
if &accs.custody.owner != accs.custody_signer.key { if *accs.custody_signer.key != accs.custody.owner {
return Err(InvalidMint.into()); return Err(WrongAccountOwner.into());
} }
// Verify VAA // Verify VAA
@ -109,6 +109,7 @@ pub fn complete_native(
} }
// Prevent vaa double signing // Prevent vaa double signing
accs.vaa.verify(ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?; accs.vaa.claim(ctx, accs.payer.key)?;
let mut amount = accs.vaa.amount.as_u64(); 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)?; accs.mint.verify_derivation(ctx.program_id, &derivation_data)?;
// Verify mints // Verify mints
if accs.mint.info().key != accs.to.info().key { if *accs.mint.info().key != accs.to.mint {
return Err(InvalidMint.into()); return Err(InvalidMint.into());
} }
accs.vaa.verify(ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?; accs.vaa.claim(ctx, accs.payer.key)?;
// Mint tokens // Mint tokens

View File

@ -4,6 +4,7 @@ use crate::{
Endpoint, Endpoint,
EndpointDerivationData, EndpointDerivationData,
MintSigner, MintSigner,
WrappedMetaDerivationData,
WrappedDerivationData, WrappedDerivationData,
WrappedMint, WrappedMint,
WrappedTokenMeta, 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> { impl<'b> InstructionContext<'b> for CreateWrapped<'b> {
} }
@ -84,11 +93,14 @@ pub fn create_wrapped(
) -> Result<()> { ) -> Result<()> {
let derivation_data: WrappedDerivationData = (&*accs).into(); let derivation_data: WrappedDerivationData = (&*accs).into();
accs.mint.verify_derivation(ctx.program_id, &derivation_data)?; 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(); let derivation_data: EndpointDerivationData = (&*accs).into();
accs.chain_registration.verify_derivation(ctx.program_id, &derivation_data)?; accs.chain_registration.verify_derivation(ctx.program_id, &derivation_data)?;
accs.vaa.verify(ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?; accs.vaa.claim(ctx, accs.payer.key)?;
// Create mint account // Create mint account

View File

@ -40,7 +40,7 @@ use std::ops::{
}; };
// Confirm that a ClaimableVAA came from the correct chain, signed by the right emitter. // 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 where
T: DeserializePayload, T: DeserializePayload,
{ {
@ -49,7 +49,6 @@ where
"{}", "{}",
Pubkey::new_from_array(vaa.message.meta().emitter_address) 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. // 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 { if expected_emitter != current_emitter || vaa.message.meta().emitter_chain != CHAIN_ID_SOLANA {
Err(InvalidGovernanceKey.into()) Err(InvalidGovernanceKey.into())
@ -99,7 +98,8 @@ pub fn upgrade_contract(
accs: &mut UpgradeContract, accs: &mut UpgradeContract,
_data: UpgradeContractData, _data: UpgradeContractData,
) -> Result<()> { ) -> Result<()> {
verify_claim(&accs.vaa)?; verify_governance(&accs.vaa);
accs.vaa.verify(&ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?; accs.vaa.claim(ctx, accs.payer.key)?;
@ -154,6 +154,8 @@ pub fn register_chain(
accs.endpoint.verify_derivation(ctx.program_id, &derivation_data)?; accs.endpoint.verify_derivation(ctx.program_id, &derivation_data)?;
// Claim VAA // Claim VAA
verify_governance(&accs.vaa);
accs.vaa.verify(&ctx.program_id)?;
accs.vaa.claim(ctx, accs.payer.key)?; accs.vaa.claim(ctx, accs.payer.key)?;
// Create endpoint // Create endpoint

View File

@ -8,6 +8,7 @@ use crate::{
EmitterAccount, EmitterAccount,
MintSigner, MintSigner,
WrappedDerivationData, WrappedDerivationData,
WrappedMetaDerivationData,
WrappedMint, WrappedMint,
WrappedTokenMeta, WrappedTokenMeta,
}, },
@ -123,10 +124,11 @@ pub fn transfer_native(
) -> Result<()> { ) -> Result<()> {
// Verify that the custody account is derived correctly // Verify that the custody account is derived correctly
let derivation_data: CustodyAccountDerivationData = (&*accs).into(); 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 // Verify mints
if accs.mint.info().key != accs.from.info().key { if accs.from.mint != *accs.mint.info().key {
return Err(TokenBridgeError::InvalidMint.into()); 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> { impl<'b> InstructionContext<'b> for TransferWrapped<'b> {
} }
@ -271,8 +281,11 @@ pub fn transfer_wrapped(
} }
// Verify that meta is correct // Verify that meta is correct
accs.wrapped_meta let derivation_data: WrappedMetaDerivationData = (&*accs).into();
.verify_derivation(ctx.program_id, &(&*accs).into())?; accs.wrapped_meta.verify_derivation(
ctx.program_id,
&derivation_data,
)?;
// Burn tokens // Burn tokens
let burn_ix = spl_token::instruction::burn( let burn_ix = spl_token::instruction::burn(

View File

@ -10,6 +10,7 @@ use crate::{
EndpointDerivationData, EndpointDerivationData,
MintSigner, MintSigner,
WrappedDerivationData, WrappedDerivationData,
WrappedMetaDerivationData,
WrappedMint, WrappedMint,
WrappedTokenMeta, WrappedTokenMeta,
}, },
@ -215,9 +216,8 @@ pub fn create_wrapped(
&program_id, &program_id,
); );
let mint_meta_key = WrappedTokenMeta::<'_, { AccountState::Uninitialized }>::key( let mint_meta_key = WrappedTokenMeta::<'_, { AccountState::Uninitialized }>::key(
&WrappedDerivationData { &WrappedMetaDerivationData {
token_chain: payload.token_chain, mint_key,
token_address: payload.token_address,
}, },
&program_id, &program_id,
); );
@ -395,9 +395,8 @@ pub fn transfer_wrapped(
&program_id, &program_id,
); );
let wrapped_meta_key = WrappedTokenMeta::<'_, { AccountState::Uninitialized }>::key( let wrapped_meta_key = WrappedTokenMeta::<'_, { AccountState::Uninitialized }>::key(
&WrappedDerivationData { &WrappedMetaDerivationData {
token_chain, mint_key: wrapped_mint_key,
token_address,
}, },
&program_id, &program_id,
); );

View File

@ -381,7 +381,7 @@ mod helpers {
) )
} }
pub fn complete_transfer_native( pub fn complete_native(
client: &RpcClient, client: &RpcClient,
program: &Pubkey, program: &Pubkey,
bridge: &Pubkey, bridge: &Pubkey,

View File

@ -293,7 +293,7 @@ fn test_transfer_native(context: &mut Context) -> () {
} }
fn test_transfer_wrapped(context: &mut Context, token_account: Pubkey) -> () { fn test_transfer_wrapped(context: &mut Context, token_account: Pubkey) -> () {
println!("Transfer Wrapped"); println!("TransferWrapped");
use token_bridge::{ use token_bridge::{
accounts::ConfigAccount, accounts::ConfigAccount,
types::Config, 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 (vaa, _, _) = common::generate_vaa([0u8; 32], 2, message, nonce, 1);
let message_key = common::post_vaa(client, bridge, payer, vaa.clone()).unwrap(); let message_key = common::post_vaa(client, bridge, payer, vaa.clone()).unwrap();
common::complete_transfer_native( common::complete_native(
client, client,
token_bridge, token_bridge,
bridge, bridge,
@ -414,7 +414,7 @@ fn test_transfer_native_in(context: &mut Context) -> () {
} }
fn test_transfer_wrapped_in(context: &mut Context, to: Pubkey) -> () { fn test_transfer_wrapped_in(context: &mut Context, to: Pubkey) -> () {
println!("TransferWrapped"); println!("TransferWrappedIn");
use token_bridge::{ use token_bridge::{
accounts::ConfigAccount, accounts::ConfigAccount,
types::Config, types::Config,