remove transfer state accounts, introduce posted message persistence
Change-Id: I34a8006dae5cb1a315dc0af297d9025d1e500fcb
This commit is contained in:
parent
d09eb150e7
commit
6a6ba06c0c
|
@ -33,9 +33,6 @@ pub enum Error {
|
|||
/// The deserialization of the GuardianSet state returned something besides State::GuardianSet.
|
||||
#[error("ExpectedGuardianSet")]
|
||||
ExpectedGuardianSet,
|
||||
/// State is uninitialized.
|
||||
#[error("State is unititialized")]
|
||||
UninitializedState,
|
||||
/// The program address provided doesn't match the value generated by the program.
|
||||
#[error("InvalidProgramAddress")]
|
||||
InvalidProgramAddress,
|
||||
|
@ -112,7 +109,6 @@ impl PrintProgramError for Error {
|
|||
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"),
|
||||
|
|
|
@ -121,6 +121,7 @@ impl Bridge {
|
|||
|
||||
// Create bridge account
|
||||
let bridge_seed = Bridge::derive_bridge_seeds();
|
||||
// Will fail if the account already exists
|
||||
Bridge::check_and_create_account::<Bridge>(
|
||||
program_id,
|
||||
accounts,
|
||||
|
@ -132,13 +133,11 @@ impl Bridge {
|
|||
)?;
|
||||
|
||||
let mut new_account_data = new_bridge_info.try_borrow_mut_data()?;
|
||||
let mut bridge: &mut Bridge = Self::unpack_unchecked(&mut new_account_data)?;
|
||||
if bridge.is_initialized {
|
||||
return Err(Error::AlreadyExists.into());
|
||||
}
|
||||
let mut bridge: &mut Bridge = Self::unpack(&mut new_account_data)?;
|
||||
|
||||
// Create guardian set account
|
||||
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>(
|
||||
program_id,
|
||||
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 guardian_info: &mut GuardianSet = Self::unpack_unchecked(&mut new_guardian_data)?;
|
||||
if guardian_info.is_initialized {
|
||||
return Err(Error::AlreadyExists.into());
|
||||
}
|
||||
let mut guardian_info: &mut GuardianSet = Self::unpack(&mut new_guardian_data)?;
|
||||
|
||||
if len_guardians > MAX_LEN_GUARDIAN_KEYS as u8 {
|
||||
return Err(ProgramError::InvalidInstructionData);
|
||||
}
|
||||
|
||||
// Initialize bridge params
|
||||
bridge.is_initialized = true;
|
||||
bridge.guardian_set_index = 0;
|
||||
bridge.config = config;
|
||||
|
||||
// Initialize the initial guardian set
|
||||
guardian_info.is_initialized = true;
|
||||
guardian_info.index = 0;
|
||||
guardian_info.creation_time = clock.unix_timestamp.as_();
|
||||
guardian_info.keys = initial_guardian_key;
|
||||
|
@ -318,6 +312,8 @@ impl Bridge {
|
|||
return Err(ProgramError::InvalidArgument);
|
||||
}
|
||||
|
||||
// Track whether the account needs initialization
|
||||
let mut initialize_account = false;
|
||||
// Prepare message/payload-specific sig_info account
|
||||
if sig_info.data_is_empty() {
|
||||
let bridge_key = Bridge::derive_bridge_id(program_id)?;
|
||||
|
@ -332,24 +328,25 @@ impl Bridge {
|
|||
&sig_seeds,
|
||||
Some(bridge_info),
|
||||
)?;
|
||||
initialize_account = true;
|
||||
} else if payload.initial_creation {
|
||||
return Err(Error::AlreadyExists.into());
|
||||
}
|
||||
|
||||
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 {
|
||||
return Err(Error::GuardianSetMismatch.into());
|
||||
}
|
||||
if sig_state.hash != payload.hash {
|
||||
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
|
||||
|
@ -449,7 +446,7 @@ impl Bridge {
|
|||
|
||||
// Load transfer account
|
||||
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
|
||||
Bridge::wrapped_burn(
|
||||
|
@ -462,7 +459,6 @@ impl Bridge {
|
|||
)?;
|
||||
|
||||
// Initialize transfer
|
||||
transfer.is_initialized = true;
|
||||
transfer.nonce = t.nonce;
|
||||
transfer.source_address = sender_account_info.key.to_bytes();
|
||||
transfer.foreign_address = t.target;
|
||||
|
@ -537,7 +533,7 @@ impl Bridge {
|
|||
|
||||
// Load transfer account
|
||||
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
|
||||
let expected_custody_id =
|
||||
|
@ -586,7 +582,6 @@ impl Bridge {
|
|||
)?;
|
||||
|
||||
// Initialize proposal
|
||||
transfer.is_initialized = true;
|
||||
transfer.amount = t.amount;
|
||||
transfer.to_chain_id = t.chain_id;
|
||||
transfer.source_address = sender_account_info.key.to_bytes();
|
||||
|
@ -804,6 +799,7 @@ impl Bridge {
|
|||
|
||||
// Check and create claim
|
||||
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>(
|
||||
program_id,
|
||||
accounts,
|
||||
|
@ -827,13 +823,9 @@ impl Bridge {
|
|||
|
||||
// Load claim account
|
||||
let mut claim_data = claim_info.try_borrow_mut_data()?;
|
||||
let claim: &mut ClaimedVAA = Bridge::unpack_unchecked(&mut claim_data)?;
|
||||
if claim.is_initialized {
|
||||
return Err(Error::VAAClaimed.into());
|
||||
}
|
||||
let claim: &mut ClaimedVAA = Bridge::unpack(&mut claim_data)?;
|
||||
|
||||
// Set claimed
|
||||
claim.is_initialized = true;
|
||||
claim.vaa_time = clock.unix_timestamp as u32;
|
||||
|
||||
Ok(())
|
||||
|
@ -870,6 +862,7 @@ impl Bridge {
|
|||
|
||||
// Check whether the new guardian set was derived correctly
|
||||
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>(
|
||||
program_id,
|
||||
accounts,
|
||||
|
@ -882,12 +875,7 @@ impl Bridge {
|
|||
|
||||
let mut guardian_set_new_data = new_guardian_info.try_borrow_mut_data()?;
|
||||
let guardian_set_new: &mut GuardianSet =
|
||||
Bridge::unpack_unchecked(&mut guardian_set_new_data)?;
|
||||
|
||||
// The new guardian set must not exist
|
||||
if guardian_set_new.is_initialized {
|
||||
return Err(Error::AlreadyExists.into());
|
||||
}
|
||||
Bridge::unpack(&mut guardian_set_new_data)?;
|
||||
|
||||
if b.new_keys.len() == 0 {
|
||||
return Err(Error::InvalidVAAFormat.into());
|
||||
|
@ -897,8 +885,6 @@ impl Bridge {
|
|||
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
|
||||
guardian_set_new.expiration_time = 0;
|
||||
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 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.chain = a.chain;
|
||||
|
||||
|
|
|
@ -2,16 +2,15 @@
|
|||
|
||||
use std::mem::size_of;
|
||||
|
||||
use primitive_types::U256;
|
||||
use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey};
|
||||
use solana_program::{program_error::ProgramError, pubkey::Pubkey};
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
use crate::instruction::MAX_PAYLOAD_SIZE;
|
||||
use crate::vaa::BodyMessage;
|
||||
use crate::{
|
||||
error::Error,
|
||||
instruction::{ForeignAddress, MAX_LEN_GUARDIAN_KEYS, MAX_VAA_SIZE},
|
||||
vaa::BodyTransfer,
|
||||
};
|
||||
use solana_program::program_pack::Pack;
|
||||
use solana_program::rent::Rent;
|
||||
|
||||
/// fee rate as a ratio
|
||||
|
@ -38,60 +37,37 @@ pub struct GuardianSet {
|
|||
pub creation_time: u32,
|
||||
/// expiration time when VAAs issued by this set are no longer valid
|
||||
pub expiration_time: u32,
|
||||
|
||||
/// Is `true` if this structure has been initialized.
|
||||
pub is_initialized: bool,
|
||||
}
|
||||
|
||||
impl IsInitialized for GuardianSet {
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.is_initialized
|
||||
}
|
||||
}
|
||||
|
||||
/// proposal to transfer tokens to a foreign chain
|
||||
/// record of a posted wormhole message
|
||||
#[repr(C)]
|
||||
pub struct TransferOutProposal {
|
||||
/// amount to transfer
|
||||
pub amount: U256,
|
||||
/// 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],
|
||||
pub struct PostedMessage {
|
||||
/// header of the posted VAA
|
||||
pub vaa_version: u8,
|
||||
/// time the vaa was submitted
|
||||
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
|
||||
pub signature_account: Pubkey,
|
||||
pub vaa_signature_account: Pubkey,
|
||||
|
||||
/// Is `true` if this structure has been initialized.
|
||||
pub is_initialized: bool,
|
||||
/// time the posted message was created
|
||||
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 {
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.is_initialized
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
impl PostedMessage {
|
||||
pub fn matches_vaa(&self, b: &BodyMessage) -> bool {
|
||||
return b.nonce == self.nonce
|
||||
&& b.emitter_address == self.emitter_address
|
||||
&& b.emitter_chain == self.emitter_chain
|
||||
&& b.data == self.payload.to_vec();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,48 +79,6 @@ pub struct ClaimedVAA {
|
|||
pub hash: [u8; 32],
|
||||
/// time the vaa was submitted
|
||||
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.
|
||||
|
@ -155,9 +89,6 @@ pub struct BridgeConfig {
|
|||
/// 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.
|
||||
pub guardian_set_expiration_time: u32,
|
||||
|
||||
/// Token program that is used for this bridge
|
||||
pub token_program: Pubkey,
|
||||
}
|
||||
|
||||
/// Bridge state.
|
||||
|
@ -169,15 +100,6 @@ pub struct Bridge {
|
|||
|
||||
/// read-only config parameters for a bridge instance.
|
||||
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
|
||||
|
@ -192,44 +114,12 @@ pub struct SignatureState {
|
|||
|
||||
/// index of the guardian set
|
||||
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
|
||||
impl Bridge {
|
||||
/// Deserializes a spl_token `Account`.
|
||||
pub fn token_account_deserialize(
|
||||
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> {
|
||||
/// Unpacks a state from a bytes buffer.
|
||||
pub fn unpack<T>(input: &mut [u8]) -> Result<&mut T, ProgramError> {
|
||||
if input.len() != size_of::<T>() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
|
@ -237,17 +127,8 @@ impl Bridge {
|
|||
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.
|
||||
pub fn unpack_immutable<T: IsInitialized>(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> {
|
||||
/// Unpacks a state from a bytes buffer.
|
||||
pub fn unpack_immutable<T>(input: &[u8]) -> Result<&T, ProgramError> {
|
||||
if input.len() != size_of::<T>() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
|
@ -284,25 +165,24 @@ impl Bridge {
|
|||
}
|
||||
|
||||
/// Calculates derived seeds for a transfer out
|
||||
pub fn derive_transfer_id_seeds(
|
||||
pub fn derive_message_seeds(
|
||||
bridge_key: &Pubkey,
|
||||
asset_chain: u8,
|
||||
asset: ForeignAddress,
|
||||
target_chain: u8,
|
||||
target_address: ForeignAddress,
|
||||
sender: ForeignAddress,
|
||||
emitter_chain: u8,
|
||||
emitter_address: ForeignAddress,
|
||||
nonce: u32,
|
||||
payload: &Vec<u8>,
|
||||
) -> Vec<Vec<u8>> {
|
||||
vec![
|
||||
"transfer".as_bytes().to_vec(),
|
||||
bridge_key.to_bytes().to_vec(),
|
||||
asset_chain.as_bytes().to_vec(),
|
||||
asset.as_bytes().to_vec(),
|
||||
target_chain.as_bytes().to_vec(),
|
||||
target_address.as_bytes().to_vec(),
|
||||
sender.as_bytes().to_vec(),
|
||||
nonce.as_bytes().to_vec(),
|
||||
[
|
||||
vec![
|
||||
"message".as_bytes().to_vec(),
|
||||
bridge_key.to_bytes().to_vec(),
|
||||
nonce.as_bytes().to_vec(),
|
||||
emitter_chain.as_bytes().to_vec(),
|
||||
emitter_address.to_vec(),
|
||||
],
|
||||
payload.chunks(32).map(|v| v.to_vec()).collect(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
|
||||
/// Calculates derived seeds for a bridge
|
||||
|
@ -310,15 +190,6 @@ impl Bridge {
|
|||
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
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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
|
||||
pub fn derive_claim_id(
|
||||
program_id: &Pubkey,
|
||||
|
@ -396,43 +258,18 @@ impl Bridge {
|
|||
.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
|
||||
pub fn derive_transfer_id(
|
||||
pub fn derive_message_id(
|
||||
program_id: &Pubkey,
|
||||
bridge_key: &Pubkey,
|
||||
asset_chain: u8,
|
||||
asset: ForeignAddress,
|
||||
target_chain: u8,
|
||||
target_address: ForeignAddress,
|
||||
user: ForeignAddress,
|
||||
slot: u32,
|
||||
emitter_chain: u8,
|
||||
emitter_address: ForeignAddress,
|
||||
nonce: u32,
|
||||
payload: &Vec<u8>,
|
||||
) -> Result<Pubkey, Error> {
|
||||
Ok(Self::derive_key(
|
||||
program_id,
|
||||
&Self::derive_transfer_id_seeds(
|
||||
bridge_key,
|
||||
asset_chain,
|
||||
asset,
|
||||
target_chain,
|
||||
target_address,
|
||||
user,
|
||||
slot,
|
||||
),
|
||||
&Self::derive_message_seeds(bridge_key, emitter_chain, emitter_address, nonce, payload),
|
||||
)?
|
||||
.0)
|
||||
}
|
||||
|
@ -486,12 +323,7 @@ impl Bridge {
|
|||
pub fn transfer_fee() -> u64 {
|
||||
// Pay for 2 signature state and Claimed VAA rents + 2 * guardian tx fees
|
||||
// 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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue