Skip to content

Commit

Permalink
somewhat reducing code duplication in Solana Token Bridge rewrite (#3411
Browse files Browse the repository at this point in the history
)
  • Loading branch information
nonergodic authored and a5-pickle committed Nov 7, 2023
1 parent 68ffe1f commit 779c88b
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 256 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,40 +109,7 @@ impl<'info>
fn order_account_infos<'a>(
account_infos: &'a [AccountInfo<'info>],
) -> Result<Vec<AccountInfo<'info>>> {
const NUM_ACCOUNTS: usize = 14;
const CORE_BRIDGE_PROGRAM_IDX: usize = NUM_ACCOUNTS - 1;
const SYSTEM_PROGRAM_IDX: usize = CORE_BRIDGE_PROGRAM_IDX - 1;

let mut infos = account_infos.to_vec();

// This check is inclusive because Core Bridge program, System program and Token program can
// be in any order.
if infos.len() >= NUM_ACCOUNTS {
// System program needs to exist in these account infos.
let system_program_idx = infos
.iter()
.position(|info| info.key() == anchor_lang::system_program::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure System program is in the right index.
if system_program_idx != SYSTEM_PROGRAM_IDX {
infos.swap(SYSTEM_PROGRAM_IDX, system_program_idx);
}

// Core Bridge program needs to exist in these account infos.
let core_bridge_program_idx = infos
.iter()
.position(|info| info.key() == core_bridge_program::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure Token program is in the right index.
if core_bridge_program_idx != CORE_BRIDGE_PROGRAM_IDX {
infos.swap(CORE_BRIDGE_PROGRAM_IDX, core_bridge_program_idx);
}
}

// Done.
Ok(infos)
utils::fix_account_order(account_infos, 14, false, true)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub use native::*;
mod wrapped;
pub use wrapped::*;

use crate::{error::TokenBridgeError, state::RegisteredEmitter};
use crate::{utils::fix_account_order, error::TokenBridgeError, state::RegisteredEmitter};
use anchor_lang::prelude::*;
use core_bridge_program::{
legacy::utils::LegacyAnchorized,
Expand Down Expand Up @@ -107,35 +107,5 @@ pub fn validate_token_transfer_vaa(
pub fn order_complete_transfer_account_infos<'info>(
account_infos: &[AccountInfo<'info>],
) -> Result<Vec<AccountInfo<'info>>> {
const NUM_ACCOUNTS: usize = 13;
const TOKEN_PROGRAM_IDX: usize = NUM_ACCOUNTS - 1;
const SYSTEM_PROGRAM_IDX: usize = TOKEN_PROGRAM_IDX - 1;

let mut infos = account_infos.to_vec();
if infos.len() >= NUM_ACCOUNTS {
// System program needs to exist in these account infos.
let system_program_idx = infos
.iter()
.position(|info| info.key() == anchor_lang::system_program::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure System program is in the right index.
if system_program_idx != SYSTEM_PROGRAM_IDX {
infos.swap(SYSTEM_PROGRAM_IDX, system_program_idx);
}

// Token program needs to exist in these account infos.
let token_program_idx = infos
.iter()
.position(|info| info.key() == anchor_spl::token::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure Token program is in the right index.
if token_program_idx != TOKEN_PROGRAM_IDX {
infos.swap(TOKEN_PROGRAM_IDX, token_program_idx);
}
}

// Done.
Ok(infos)
fix_account_order(account_infos, 13, true, false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub use native::*;
mod wrapped;
pub use wrapped::*;

use crate::{error::TokenBridgeError, legacy::state::RegisteredEmitter};
use crate::{error::TokenBridgeError, legacy::state::RegisteredEmitter, utils::fix_account_order};
use anchor_lang::prelude::*;
use core_bridge_program::{
legacy::utils::LegacyAnchorized,
Expand Down Expand Up @@ -86,37 +86,5 @@ pub fn validate_token_transfer_with_payload_vaa(
pub fn order_complete_transfer_with_payload_account_infos<'info>(
account_infos: &[AccountInfo<'info>],
) -> Result<Vec<AccountInfo<'info>>> {
const NUM_ACCOUNTS: usize = 14;
const TOKEN_PROGRAM_IDX: usize = NUM_ACCOUNTS - 1;
const SYSTEM_PROGRAM_IDX: usize = TOKEN_PROGRAM_IDX - 1;

let mut infos = account_infos.to_vec();

// This check is inclusive because System program and Token program can be in any order.
if infos.len() >= NUM_ACCOUNTS {
// System program needs to exist in these account infos.
let system_program_idx = infos
.iter()
.position(|info| info.key() == anchor_lang::system_program::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure System program is in the right index.
if system_program_idx != SYSTEM_PROGRAM_IDX {
infos.swap(SYSTEM_PROGRAM_IDX, system_program_idx);
}

// Token program needs to exist in these account infos.
let token_program_idx = infos
.iter()
.position(|info| info.key() == anchor_spl::token::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure Token program is in the right index.
if token_program_idx != TOKEN_PROGRAM_IDX {
infos.swap(TOKEN_PROGRAM_IDX, token_program_idx);
}
}

// Done.
Ok(infos)
fix_account_order(account_infos, 14, true, false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ pub struct CreateOrUpdateWrapped<'info> {
/// CHECK: Posted VAA account, which will be read via zero-copy deserialization in the
/// instruction handler, which also checks this account discriminator (so there is no need to
/// check PDA seeds here).
#[account(
constraint = try_attestation(&vaa, |attestation| attestation.token_chain())?
!= core_bridge_sdk::SOLANA_CHAIN @ TokenBridgeError::NativeAsset,
)]
vaa: AccountInfo<'info>,

/// CHECK: Account representing that a VAA has been consumed. Seeds are checked when
Expand All @@ -48,12 +52,12 @@ pub struct CreateOrUpdateWrapped<'info> {
#[account(
init_if_needed,
payer = payer,
mint::decimals = try_attestation_decimals(&vaa)?,
mint::decimals = try_attestation(&vaa, |att| cap_decimals(att.decimals()))?,
mint::authority = mint_authority,
seeds = [
WRAPPED_MINT_SEED_PREFIX,
try_attestation_token_chain_bytes(&vaa)?.as_ref(),
try_attestation_token_address(&vaa)?.as_ref(),
try_attestation(&vaa, |att| att.token_chain())?.to_be_bytes().as_ref(),
try_attestation(&vaa, |att| att.token_address())?.as_ref(),
],
bump,
)]
Expand Down Expand Up @@ -128,45 +132,6 @@ impl<'info> core_bridge_program::legacy::utils::ProcessLegacyInstruction<'info,
const ANCHOR_IX_FN: fn(Context<Self>, EmptyArgs) -> Result<()> = create_or_update_wrapped;
}

fn try_attestation_decimals(vaa_acc_info: &AccountInfo) -> Result<u8> {
let vaa = core_bridge_sdk::VaaAccount::load(vaa_acc_info)?;
let msg = TokenBridgeMessage::try_from(vaa.try_payload()?)
.map_err(|_| TokenBridgeError::InvalidTokenBridgePayload)?;
msg.attestation()
.map(|attestation| cap_decimals(attestation.decimals()))
.ok_or(error!(TokenBridgeError::InvalidTokenBridgeVaa))
}

fn try_attestation_token_chain_bytes(vaa_acc_info: &AccountInfo) -> Result<[u8; 2]> {
let vaa = core_bridge_sdk::VaaAccount::load(vaa_acc_info)?;
let msg = TokenBridgeMessage::try_from(vaa.try_payload()?)
.map_err(|_| TokenBridgeError::InvalidTokenBridgePayload)?;

let token_chain = msg
.attestation()
.map(|attestation| attestation.token_chain())
.ok_or(error!(TokenBridgeError::InvalidTokenBridgeVaa))?;

// This token must have originated from another network.
require_neq!(
token_chain,
core_bridge_sdk::SOLANA_CHAIN,
TokenBridgeError::NativeAsset
);

// Done.
Ok(token_chain.to_be_bytes())
}

fn try_attestation_token_address(vaa_acc_info: &AccountInfo) -> Result<[u8; 32]> {
let vaa = core_bridge_sdk::VaaAccount::load(vaa_acc_info)?;
let msg = TokenBridgeMessage::try_from(vaa.try_payload()?)
.map_err(|_| TokenBridgeError::InvalidTokenBridgePayload)?;
msg.attestation()
.map(|attestation| attestation.token_address())
.ok_or(error!(TokenBridgeError::InvalidTokenBridgeVaa))
}

impl<'info> CreateOrUpdateWrapped<'info> {
fn constraints(ctx: &Context<Self>) -> Result<()> {
let vaa = &ctx.accounts.vaa;
Expand Down Expand Up @@ -374,14 +339,18 @@ fn handle_update_wrapped(ctx: Context<CreateOrUpdateWrapped>) -> Result<()> {
}
}

fn cap_decimals(decimals: u8) -> u8 {
if decimals > MAX_DECIMALS {
MAX_DECIMALS
} else {
decimals
}
fn try_attestation<F, T>(vaa_acc_info: &AccountInfo, func: F) -> Result<T>
where F: FnOnce(&Attestation) -> T {
let vaa = core_bridge_sdk::VaaAccount::load(vaa_acc_info)?;
let msg = TokenBridgeMessage::try_from(vaa.try_payload()?)
.map_err(|_| TokenBridgeError::InvalidTokenBridgePayload)?;
msg.attestation()
.map(func)
.ok_or(error!(TokenBridgeError::InvalidTokenBridgeVaa))
}

fn cap_decimals(decimals: u8) -> u8 { std::cmp::min(decimals, MAX_DECIMALS) }

struct FixedMeta {
symbol: String,
name: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pub use wrapped::*;

use anchor_lang::prelude::*;

use crate::utils::fix_account_order;

/// The Anchor context orders the accounts as:
///
/// 1. `payer`
Expand Down Expand Up @@ -33,50 +35,5 @@ use anchor_lang::prelude::*;
pub(super) fn order_transfer_tokens_account_infos<'info>(
account_infos: &[AccountInfo<'info>],
) -> Result<Vec<AccountInfo<'info>>> {
const NUM_ACCOUNTS: usize = 17;
const CORE_BRIDGE_PROGRAM_IDX: usize = NUM_ACCOUNTS - 1;
const TOKEN_PROGRAM_IDX: usize = CORE_BRIDGE_PROGRAM_IDX - 1;
const SYSTEM_PROGRAM_IDX: usize = TOKEN_PROGRAM_IDX - 1;

let mut infos = account_infos.to_vec();

// This check is inclusive because Core Bridge program, System program and Token program can
// be in any order.
if infos.len() >= NUM_ACCOUNTS {
// System program needs to exist in these account infos.
let system_program_idx = infos
.iter()
.position(|info| info.key() == anchor_lang::system_program::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure System program is in the right index.
if system_program_idx != SYSTEM_PROGRAM_IDX {
infos.swap(SYSTEM_PROGRAM_IDX, system_program_idx);
}

// Token program needs to exist in these account infos.
let token_program_idx = infos
.iter()
.position(|info| info.key() == anchor_spl::token::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure Token program is in the right index.
if token_program_idx != TOKEN_PROGRAM_IDX {
infos.swap(TOKEN_PROGRAM_IDX, token_program_idx);
}

// Core Bridge program needs to exist in these account infos.
let core_bridge_program_idx = infos
.iter()
.position(|info| info.key() == core_bridge_program::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure Token program is in the right index.
if core_bridge_program_idx != CORE_BRIDGE_PROGRAM_IDX {
infos.swap(CORE_BRIDGE_PROGRAM_IDX, core_bridge_program_idx);
}
}

// Done.
Ok(infos)
fix_account_order(account_infos, 17, true, true)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pub use wrapped::*;

use anchor_lang::prelude::*;

use crate::utils::fix_account_order;

/// The Anchor context orders the accounts as:
///
/// 1. `payer`
Expand Down Expand Up @@ -34,50 +36,5 @@ use anchor_lang::prelude::*;
pub(super) fn order_transfer_tokens_with_payload_account_infos<'info>(
account_infos: &[AccountInfo<'info>],
) -> Result<Vec<AccountInfo<'info>>> {
const NUM_ACCOUNTS: usize = 18;
const CORE_BRIDGE_PROGRAM_IDX: usize = NUM_ACCOUNTS - 1;
const TOKEN_PROGRAM_IDX: usize = CORE_BRIDGE_PROGRAM_IDX - 1;
const SYSTEM_PROGRAM_IDX: usize = TOKEN_PROGRAM_IDX - 1;

let mut infos = account_infos.to_vec();

// This check is inclusive because Core Bridge program, System program and Token program can
// be in any order.
if infos.len() >= NUM_ACCOUNTS {
// System program needs to exist in these account infos.
let system_program_idx = infos
.iter()
.position(|info| info.key() == anchor_lang::system_program::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure System program is in the right index.
if system_program_idx != SYSTEM_PROGRAM_IDX {
infos.swap(SYSTEM_PROGRAM_IDX, system_program_idx);
}

// Token program needs to exist in these account infos.
let token_program_idx = infos
.iter()
.position(|info| info.key() == anchor_spl::token::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure Token program is in the right index.
if token_program_idx != TOKEN_PROGRAM_IDX {
infos.swap(TOKEN_PROGRAM_IDX, token_program_idx);
}

// Core Bridge program needs to exist in these account infos.
let core_bridge_program_idx = infos
.iter()
.position(|info| info.key() == core_bridge_program::ID)
.ok_or(error!(ErrorCode::InvalidProgramId))?;

// Make sure Token program is in the right index.
if core_bridge_program_idx != CORE_BRIDGE_PROGRAM_IDX {
infos.swap(CORE_BRIDGE_PROGRAM_IDX, core_bridge_program_idx);
}
}

// Done.
Ok(infos)
fix_account_order(account_infos, 18, true, true)
}
Loading

0 comments on commit 779c88b

Please sign in to comment.