remove transfer state accounts, introduce posted message persistence

Change-Id: I34a8006dae5cb1a315dc0af297d9025d1e500fcb
This commit is contained in:
Hendrik Hofstadt 2021-04-15 11:36:29 +02:00
parent d09eb150e7
commit 6a6ba06c0c
3 changed files with 71 additions and 258 deletions

View File

@ -33,9 +33,6 @@ pub enum Error {
/// The deserialization of the GuardianSet state returned something besides State::GuardianSet. /// The deserialization of the GuardianSet state returned something besides State::GuardianSet.
#[error("ExpectedGuardianSet")] #[error("ExpectedGuardianSet")]
ExpectedGuardianSet, ExpectedGuardianSet,
/// State is uninitialized.
#[error("State is unititialized")]
UninitializedState,
/// The program address provided doesn't match the value generated by the program. /// The program address provided doesn't match the value generated by the program.
#[error("InvalidProgramAddress")] #[error("InvalidProgramAddress")]
InvalidProgramAddress, InvalidProgramAddress,
@ -112,7 +109,6 @@ impl PrintProgramError for Error {
Error::ExpectedAccount => msg!("Error: ExpectedAccount"), Error::ExpectedAccount => msg!("Error: ExpectedAccount"),
Error::ExpectedBridge => msg!("Error: ExpectedBridge"), Error::ExpectedBridge => msg!("Error: ExpectedBridge"),
Error::ExpectedGuardianSet => msg!("Error: ExpectedGuardianSet"), Error::ExpectedGuardianSet => msg!("Error: ExpectedGuardianSet"),
Error::UninitializedState => msg!("Error: State is unititialized"),
Error::InvalidProgramAddress => msg!("Error: InvalidProgramAddress"), Error::InvalidProgramAddress => msg!("Error: InvalidProgramAddress"),
Error::InvalidVAAFormat => msg!("Error: InvalidVAAFormat"), Error::InvalidVAAFormat => msg!("Error: InvalidVAAFormat"),
Error::InvalidVAASignature => msg!("Error: InvalidVAASignature"), Error::InvalidVAASignature => msg!("Error: InvalidVAASignature"),

View File

@ -121,6 +121,7 @@ impl Bridge {
// Create bridge account // Create bridge account
let bridge_seed = Bridge::derive_bridge_seeds(); let bridge_seed = Bridge::derive_bridge_seeds();
// Will fail if the account already exists
Bridge::check_and_create_account::<Bridge>( Bridge::check_and_create_account::<Bridge>(
program_id, program_id,
accounts, accounts,
@ -132,13 +133,11 @@ impl Bridge {
)?; )?;
let mut new_account_data = new_bridge_info.try_borrow_mut_data()?; let mut new_account_data = new_bridge_info.try_borrow_mut_data()?;
let mut bridge: &mut Bridge = Self::unpack_unchecked(&mut new_account_data)?; let mut bridge: &mut Bridge = Self::unpack(&mut new_account_data)?;
if bridge.is_initialized {
return Err(Error::AlreadyExists.into());
}
// Create guardian set account // Create guardian set account
let guardian_seed = Bridge::derive_guardian_set_seeds(new_bridge_info.key, 0); let guardian_seed = Bridge::derive_guardian_set_seeds(new_bridge_info.key, 0);
// Will fail if the account already exists
Bridge::check_and_create_account::<GuardianSet>( Bridge::check_and_create_account::<GuardianSet>(
program_id, program_id,
accounts, accounts,
@ -150,22 +149,17 @@ impl Bridge {
)?; )?;
let mut new_guardian_data = new_guardian_info.try_borrow_mut_data().map_err(|_| ProgramError::AccountBorrowFailed)?; let mut new_guardian_data = new_guardian_info.try_borrow_mut_data().map_err(|_| ProgramError::AccountBorrowFailed)?;
let mut guardian_info: &mut GuardianSet = Self::unpack_unchecked(&mut new_guardian_data)?; let mut guardian_info: &mut GuardianSet = Self::unpack(&mut new_guardian_data)?;
if guardian_info.is_initialized {
return Err(Error::AlreadyExists.into());
}
if len_guardians > MAX_LEN_GUARDIAN_KEYS as u8 { if len_guardians > MAX_LEN_GUARDIAN_KEYS as u8 {
return Err(ProgramError::InvalidInstructionData); return Err(ProgramError::InvalidInstructionData);
} }
// Initialize bridge params // Initialize bridge params
bridge.is_initialized = true;
bridge.guardian_set_index = 0; bridge.guardian_set_index = 0;
bridge.config = config; bridge.config = config;
// Initialize the initial guardian set // Initialize the initial guardian set
guardian_info.is_initialized = true;
guardian_info.index = 0; guardian_info.index = 0;
guardian_info.creation_time = clock.unix_timestamp.as_(); guardian_info.creation_time = clock.unix_timestamp.as_();
guardian_info.keys = initial_guardian_key; guardian_info.keys = initial_guardian_key;
@ -318,6 +312,8 @@ impl Bridge {
return Err(ProgramError::InvalidArgument); return Err(ProgramError::InvalidArgument);
} }
// Track whether the account needs initialization
let mut initialize_account = false;
// Prepare message/payload-specific sig_info account // Prepare message/payload-specific sig_info account
if sig_info.data_is_empty() { if sig_info.data_is_empty() {
let bridge_key = Bridge::derive_bridge_id(program_id)?; let bridge_key = Bridge::derive_bridge_id(program_id)?;
@ -332,24 +328,25 @@ impl Bridge {
&sig_seeds, &sig_seeds,
Some(bridge_info), Some(bridge_info),
)?; )?;
initialize_account = true;
} else if payload.initial_creation { } else if payload.initial_creation {
return Err(Error::AlreadyExists.into()); return Err(Error::AlreadyExists.into());
} }
let mut sig_state_data = sig_info.try_borrow_mut_data()?; let mut sig_state_data = sig_info.try_borrow_mut_data()?;
let mut sig_state: &mut SignatureState = Self::unpack_unchecked(&mut sig_state_data)?; let mut sig_state: &mut SignatureState = Self::unpack(&mut sig_state_data)?;
if sig_state.is_initialized { if initialize_account {
sig_state.guardian_set_index = guardian_set.index;
sig_state.hash = payload.hash;
} else {
// If the account already existed, check that the parameters match
if sig_state.guardian_set_index != guardian_set.index { if sig_state.guardian_set_index != guardian_set.index {
return Err(Error::GuardianSetMismatch.into()); return Err(Error::GuardianSetMismatch.into());
} }
if sig_state.hash != payload.hash { if sig_state.hash != payload.hash {
return Err(ProgramError::InvalidArgument); return Err(ProgramError::InvalidArgument);
} }
} else {
sig_state.is_initialized = true;
sig_state.guardian_set_index = guardian_set.index;
sig_state.hash = payload.hash;
} }
// Write sigs of checked addresses into sig_state // Write sigs of checked addresses into sig_state
@ -449,7 +446,7 @@ impl Bridge {
// Load transfer account // Load transfer account
let mut transfer_data = transfer_info.try_borrow_mut_data()?; let mut transfer_data = transfer_info.try_borrow_mut_data()?;
let mut transfer: &mut TransferOutProposal = Self::unpack_unchecked(&mut transfer_data)?; let mut transfer: &mut TransferOutProposal = Self::unpack(&mut transfer_data)?;
// Burn tokens // Burn tokens
Bridge::wrapped_burn( Bridge::wrapped_burn(
@ -462,7 +459,6 @@ impl Bridge {
)?; )?;
// Initialize transfer // Initialize transfer
transfer.is_initialized = true;
transfer.nonce = t.nonce; transfer.nonce = t.nonce;
transfer.source_address = sender_account_info.key.to_bytes(); transfer.source_address = sender_account_info.key.to_bytes();
transfer.foreign_address = t.target; transfer.foreign_address = t.target;
@ -537,7 +533,7 @@ impl Bridge {
// Load transfer account // Load transfer account
let mut transfer_data = transfer_info.try_borrow_mut_data()?; let mut transfer_data = transfer_info.try_borrow_mut_data()?;
let mut transfer: &mut TransferOutProposal = Self::unpack_unchecked(&mut transfer_data)?; let mut transfer: &mut TransferOutProposal = Self::unpack(&mut transfer_data)?;
// Check that custody account was derived correctly // Check that custody account was derived correctly
let expected_custody_id = let expected_custody_id =
@ -586,7 +582,6 @@ impl Bridge {
)?; )?;
// Initialize proposal // Initialize proposal
transfer.is_initialized = true;
transfer.amount = t.amount; transfer.amount = t.amount;
transfer.to_chain_id = t.chain_id; transfer.to_chain_id = t.chain_id;
transfer.source_address = sender_account_info.key.to_bytes(); transfer.source_address = sender_account_info.key.to_bytes();
@ -804,6 +799,7 @@ impl Bridge {
// Check and create claim // Check and create claim
let claim_seeds = Bridge::derive_claim_seeds(bridge_info.key, vaa.signature_body()?); let claim_seeds = Bridge::derive_claim_seeds(bridge_info.key, vaa.signature_body()?);
// Will fail if the Claim exists i.e. the VAA has already been claimed
Bridge::check_and_create_account::<ClaimedVAA>( Bridge::check_and_create_account::<ClaimedVAA>(
program_id, program_id,
accounts, accounts,
@ -827,13 +823,9 @@ impl Bridge {
// Load claim account // Load claim account
let mut claim_data = claim_info.try_borrow_mut_data()?; let mut claim_data = claim_info.try_borrow_mut_data()?;
let claim: &mut ClaimedVAA = Bridge::unpack_unchecked(&mut claim_data)?; let claim: &mut ClaimedVAA = Bridge::unpack(&mut claim_data)?;
if claim.is_initialized {
return Err(Error::VAAClaimed.into());
}
// Set claimed // Set claimed
claim.is_initialized = true;
claim.vaa_time = clock.unix_timestamp as u32; claim.vaa_time = clock.unix_timestamp as u32;
Ok(()) Ok(())
@ -870,6 +862,7 @@ impl Bridge {
// Check whether the new guardian set was derived correctly // Check whether the new guardian set was derived correctly
let guardian_seed = Bridge::derive_guardian_set_seeds(bridge_info.key, b.new_index); let guardian_seed = Bridge::derive_guardian_set_seeds(bridge_info.key, b.new_index);
// Will fail if the guardianset already exists
Bridge::check_and_create_account::<GuardianSet>( Bridge::check_and_create_account::<GuardianSet>(
program_id, program_id,
accounts, accounts,
@ -882,12 +875,7 @@ impl Bridge {
let mut guardian_set_new_data = new_guardian_info.try_borrow_mut_data()?; let mut guardian_set_new_data = new_guardian_info.try_borrow_mut_data()?;
let guardian_set_new: &mut GuardianSet = let guardian_set_new: &mut GuardianSet =
Bridge::unpack_unchecked(&mut guardian_set_new_data)?; Bridge::unpack(&mut guardian_set_new_data)?;
// The new guardian set must not exist
if guardian_set_new.is_initialized {
return Err(Error::AlreadyExists.into());
}
if b.new_keys.len() == 0 { if b.new_keys.len() == 0 {
return Err(Error::InvalidVAAFormat.into()); return Err(Error::InvalidVAAFormat.into());
@ -897,8 +885,6 @@ impl Bridge {
return Err(Error::InvalidVAAFormat.into()); return Err(Error::InvalidVAAFormat.into());
} }
// Set values on the new guardian set
guardian_set_new.is_initialized = true;
// Force the new guardian set to not expire // Force the new guardian set to not expire
guardian_set_new.expiration_time = 0; guardian_set_new.expiration_time = 0;
guardian_set_new.index = b.new_index; guardian_set_new.index = b.new_index;
@ -1107,9 +1093,8 @@ impl Bridge {
)?; )?;
let mut wrapped_meta_data = wrapped_meta_info.try_borrow_mut_data()?; let mut wrapped_meta_data = wrapped_meta_info.try_borrow_mut_data()?;
let wrapped_meta: &mut WrappedAssetMeta = Bridge::unpack_unchecked(&mut wrapped_meta_data)?; let wrapped_meta: &mut WrappedAssetMeta = Bridge::unpack(&mut wrapped_meta_data)?;
wrapped_meta.is_initialized = true;
wrapped_meta.address = a.address; wrapped_meta.address = a.address;
wrapped_meta.chain = a.chain; wrapped_meta.chain = a.chain;

View File

@ -2,16 +2,15 @@
use std::mem::size_of; use std::mem::size_of;
use primitive_types::U256; use solana_program::{program_error::ProgramError, pubkey::Pubkey};
use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey};
use zerocopy::AsBytes; use zerocopy::AsBytes;
use crate::instruction::MAX_PAYLOAD_SIZE;
use crate::vaa::BodyMessage;
use crate::{ use crate::{
error::Error, error::Error,
instruction::{ForeignAddress, MAX_LEN_GUARDIAN_KEYS, MAX_VAA_SIZE}, instruction::{ForeignAddress, MAX_LEN_GUARDIAN_KEYS, MAX_VAA_SIZE},
vaa::BodyTransfer,
}; };
use solana_program::program_pack::Pack;
use solana_program::rent::Rent; use solana_program::rent::Rent;
/// fee rate as a ratio /// fee rate as a ratio
@ -38,60 +37,37 @@ pub struct GuardianSet {
pub creation_time: u32, pub creation_time: u32,
/// expiration time when VAAs issued by this set are no longer valid /// expiration time when VAAs issued by this set are no longer valid
pub expiration_time: u32, pub expiration_time: u32,
/// Is `true` if this structure has been initialized.
pub is_initialized: bool,
} }
impl IsInitialized for GuardianSet { /// record of a posted wormhole message
fn is_initialized(&self) -> bool {
self.is_initialized
}
}
/// proposal to transfer tokens to a foreign chain
#[repr(C)] #[repr(C)]
pub struct TransferOutProposal { pub struct PostedMessage {
/// amount to transfer /// header of the posted VAA
pub amount: U256, pub vaa_version: u8,
/// chain id to transfer to
pub to_chain_id: u8,
/// address the transfer was initiated from
pub source_address: ForeignAddress,
/// address on the foreign chain to transfer to
pub foreign_address: ForeignAddress,
/// asset that is being transferred
pub asset: AssetMeta,
/// nonce of the transfer
pub nonce: u32,
/// vaa to unlock the tokens on the foreign chain
/// it is +1 byte long to make space for the termination byte
pub vaa: [u8; MAX_VAA_SIZE + 1],
/// time the vaa was submitted /// time the vaa was submitted
pub vaa_time: u32, pub vaa_time: u32,
/// time the lockup was created
pub lockup_time: u32,
/// times the proposal has been poked
pub poke_counter: u8,
/// Account where signatures are stored /// Account where signatures are stored
pub signature_account: Pubkey, pub vaa_signature_account: Pubkey,
/// Is `true` if this structure has been initialized. /// time the posted message was created
pub is_initialized: bool, pub submission_time: u32,
/// unique nonce for this message
pub nonce: u32,
/// emitter of the message
pub emitter_chain: u8,
/// emitter of the message
pub emitter_address: ForeignAddress,
/// message payload
pub payload: [u8; MAX_PAYLOAD_SIZE],
} }
impl IsInitialized for TransferOutProposal { impl PostedMessage {
fn is_initialized(&self) -> bool { pub fn matches_vaa(&self, b: &BodyMessage) -> bool {
self.is_initialized return b.nonce == self.nonce
} && b.emitter_address == self.emitter_address
} && b.emitter_chain == self.emitter_chain
&& b.data == self.payload.to_vec();
impl TransferOutProposal {
pub fn matches_vaa(&self, b: &BodyTransfer) -> bool {
return b.amount == self.amount
&& b.target_address == self.foreign_address
&& b.target_chain == self.to_chain_id
&& b.asset == self.asset;
} }
} }
@ -103,48 +79,6 @@ pub struct ClaimedVAA {
pub hash: [u8; 32], pub hash: [u8; 32],
/// time the vaa was submitted /// time the vaa was submitted
pub vaa_time: u32, pub vaa_time: u32,
/// Is `true` if this structure has been initialized.
pub is_initialized: bool,
}
impl IsInitialized for ClaimedVAA {
fn is_initialized(&self) -> bool {
self.is_initialized
}
}
/// metadata tracking for wrapped assets
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct WrappedAssetMeta {
/// chain id of the native chain of this asset
pub chain: u8,
/// address of the asset on the native chain
pub address: ForeignAddress,
/// Is `true` if this structure has been initialized.
pub is_initialized: bool,
}
impl IsInitialized for WrappedAssetMeta {
fn is_initialized(&self) -> bool {
self.is_initialized
}
}
/// Metadata about an asset
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct AssetMeta {
/// Address of the token
pub address: ForeignAddress,
/// Chain of the token
pub chain: u8,
/// Number of decimals of the token
pub decimals: u8,
} }
/// Config for a bridge. /// Config for a bridge.
@ -155,9 +89,6 @@ pub struct BridgeConfig {
/// This guarantees that VAAs issued by that set can still be submitted for a certain period. /// This guarantees that VAAs issued by that set can still be submitted for a certain period.
/// In this period we still trust the old guardian set. /// In this period we still trust the old guardian set.
pub guardian_set_expiration_time: u32, pub guardian_set_expiration_time: u32,
/// Token program that is used for this bridge
pub token_program: Pubkey,
} }
/// Bridge state. /// Bridge state.
@ -169,15 +100,6 @@ pub struct Bridge {
/// read-only config parameters for a bridge instance. /// read-only config parameters for a bridge instance.
pub config: BridgeConfig, pub config: BridgeConfig,
/// Is `true` if this structure has been initialized.
pub is_initialized: bool,
}
impl IsInitialized for Bridge {
fn is_initialized(&self) -> bool {
self.is_initialized
}
} }
/// Signature state /// Signature state
@ -192,44 +114,12 @@ pub struct SignatureState {
/// index of the guardian set /// index of the guardian set
pub guardian_set_index: u32, pub guardian_set_index: u32,
/// Is `true` if this structure has been initialized.
pub is_initialized: bool,
}
impl IsInitialized for SignatureState {
fn is_initialized(&self) -> bool {
self.is_initialized
}
} }
/// Implementation of serialization functions /// Implementation of serialization functions
impl Bridge { impl Bridge {
/// Deserializes a spl_token `Account`. /// Unpacks a state from a bytes buffer.
pub fn token_account_deserialize( pub fn unpack<T>(input: &mut [u8]) -> Result<&mut T, ProgramError> {
info: &AccountInfo,
) -> Result<spl_token::state::Account, Error> {
Ok(spl_token::state::Account::unpack(&mut info.data.borrow_mut())
.map_err(|_| Error::ExpectedAccount)?)
}
/// Deserializes a spl_token `Mint`.
pub fn mint_deserialize(info: &AccountInfo) -> Result<spl_token::state::Mint, Error> {
Ok(spl_token::state::Mint::unpack(&mut info.data.borrow_mut())
.map_err(|_| Error::ExpectedToken)?)
}
/// Unpacks a state from a bytes buffer while assuring that the state is initialized.
pub fn unpack<T: IsInitialized>(input: &mut [u8]) -> Result<&mut T, ProgramError> {
let mut_ref: &mut T = Self::unpack_unchecked(input)?;
if !mut_ref.is_initialized() {
return Err(Error::UninitializedState.into());
}
Ok(mut_ref)
}
/// Unpacks a state from a bytes buffer without checking that the state is initialized.
pub fn unpack_unchecked<T: IsInitialized>(input: &mut [u8]) -> Result<&mut T, ProgramError> {
if input.len() != size_of::<T>() { if input.len() != size_of::<T>() {
return Err(ProgramError::InvalidAccountData); return Err(ProgramError::InvalidAccountData);
} }
@ -237,17 +127,8 @@ impl Bridge {
Ok(unsafe { &mut *(&mut input[0] as *mut u8 as *mut T) }) Ok(unsafe { &mut *(&mut input[0] as *mut u8 as *mut T) })
} }
/// Unpacks a state from a bytes buffer while assuring that the state is initialized. /// Unpacks a state from a bytes buffer.
pub fn unpack_immutable<T: IsInitialized>(input: &[u8]) -> Result<&T, ProgramError> { pub fn unpack_immutable<T>(input: &[u8]) -> Result<&T, ProgramError> {
let mut_ref: &T = Self::unpack_unchecked_immutable(input)?;
if !mut_ref.is_initialized() {
return Err(Error::UninitializedState.into());
}
Ok(mut_ref)
}
/// Unpacks a state from a bytes buffer without checking that the state is initialized.
pub fn unpack_unchecked_immutable<T: IsInitialized>(input: &[u8]) -> Result<&T, ProgramError> {
if input.len() != size_of::<T>() { if input.len() != size_of::<T>() {
return Err(ProgramError::InvalidAccountData); return Err(ProgramError::InvalidAccountData);
} }
@ -284,25 +165,24 @@ impl Bridge {
} }
/// Calculates derived seeds for a transfer out /// Calculates derived seeds for a transfer out
pub fn derive_transfer_id_seeds( pub fn derive_message_seeds(
bridge_key: &Pubkey, bridge_key: &Pubkey,
asset_chain: u8, emitter_chain: u8,
asset: ForeignAddress, emitter_address: ForeignAddress,
target_chain: u8,
target_address: ForeignAddress,
sender: ForeignAddress,
nonce: u32, nonce: u32,
payload: &Vec<u8>,
) -> Vec<Vec<u8>> { ) -> Vec<Vec<u8>> {
vec![ [
"transfer".as_bytes().to_vec(), vec![
bridge_key.to_bytes().to_vec(), "message".as_bytes().to_vec(),
asset_chain.as_bytes().to_vec(), bridge_key.to_bytes().to_vec(),
asset.as_bytes().to_vec(), nonce.as_bytes().to_vec(),
target_chain.as_bytes().to_vec(), emitter_chain.as_bytes().to_vec(),
target_address.as_bytes().to_vec(), emitter_address.to_vec(),
sender.as_bytes().to_vec(), ],
nonce.as_bytes().to_vec(), payload.chunks(32).map(|v| v.to_vec()).collect(),
] ]
.concat()
} }
/// Calculates derived seeds for a bridge /// Calculates derived seeds for a bridge
@ -310,15 +190,6 @@ impl Bridge {
vec!["bridge".as_bytes().to_vec()] vec!["bridge".as_bytes().to_vec()]
} }
/// Calculates derived seeds for a custody account
pub fn derive_custody_seeds<'a>(bridge: &Pubkey, mint: &Pubkey) -> Vec<Vec<u8>> {
vec![
"custody".as_bytes().to_vec(),
bridge.to_bytes().to_vec(),
mint.to_bytes().to_vec(),
]
}
/// Calculates derived seeds for a claim /// Calculates derived seeds for a claim
pub fn derive_claim_seeds<'a>(bridge: &Pubkey, body: Vec<u8>) -> Vec<Vec<u8>> { pub fn derive_claim_seeds<'a>(bridge: &Pubkey, body: Vec<u8>) -> Vec<Vec<u8>> {
[ [
@ -356,15 +227,6 @@ impl Bridge {
Ok(Self::derive_key(program_id, &Self::derive_bridge_seeds())?.0) Ok(Self::derive_key(program_id, &Self::derive_bridge_seeds())?.0)
} }
/// Calculates a derived address for a custody account
pub fn derive_custody_id(
program_id: &Pubkey,
bridge: &Pubkey,
mint: &Pubkey,
) -> Result<Pubkey, Error> {
Ok(Self::derive_key(program_id, &Self::derive_custody_seeds(bridge, mint))?.0)
}
/// Calculates a derived address for a claim account /// Calculates a derived address for a claim account
pub fn derive_claim_id( pub fn derive_claim_id(
program_id: &Pubkey, program_id: &Pubkey,
@ -396,43 +258,18 @@ impl Bridge {
.0) .0)
} }
/// Calculates a derived seeds for a wrapped asset
pub fn derive_wrapped_asset_id(
program_id: &Pubkey,
bridge_key: &Pubkey,
asset_chain: u8,
asset_decimal: u8,
asset: ForeignAddress,
) -> Result<Pubkey, Error> {
Ok(Self::derive_key(
program_id,
&Self::derive_wrapped_asset_seeds(bridge_key, asset_chain, asset_decimal, asset),
)?
.0)
}
/// Calculates a derived address for a transfer out /// Calculates a derived address for a transfer out
pub fn derive_transfer_id( pub fn derive_message_id(
program_id: &Pubkey, program_id: &Pubkey,
bridge_key: &Pubkey, bridge_key: &Pubkey,
asset_chain: u8, emitter_chain: u8,
asset: ForeignAddress, emitter_address: ForeignAddress,
target_chain: u8, nonce: u32,
target_address: ForeignAddress, payload: &Vec<u8>,
user: ForeignAddress,
slot: u32,
) -> Result<Pubkey, Error> { ) -> Result<Pubkey, Error> {
Ok(Self::derive_key( Ok(Self::derive_key(
program_id, program_id,
&Self::derive_transfer_id_seeds( &Self::derive_message_seeds(bridge_key, emitter_chain, emitter_address, nonce, payload),
bridge_key,
asset_chain,
asset,
target_chain,
target_address,
user,
slot,
),
)? )?
.0) .0)
} }
@ -486,12 +323,7 @@ impl Bridge {
pub fn transfer_fee() -> u64 { pub fn transfer_fee() -> u64 {
// Pay for 2 signature state and Claimed VAA rents + 2 * guardian tx fees // Pay for 2 signature state and Claimed VAA rents + 2 * guardian tx fees
// This will pay for this transfer and ~10 inbound ones // This will pay for this transfer and ~10 inbound ones
Rent::default().minimum_balance((size_of::<SignatureState>() + size_of::<ClaimedVAA>()) * 2) + Self::VAA_TX_FEE * 2 Rent::default().minimum_balance((size_of::<SignatureState>() + size_of::<ClaimedVAA>()) * 2)
+ Self::VAA_TX_FEE * 2
} }
} }
/// Check is a token state is initialized
pub trait IsInitialized {
/// Is initialized
fn is_initialized(&self) -> bool;
}