Skip to content

Commit

Permalink
solana: fix various program bugs; add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
a5-pickle committed Aug 3, 2023
1 parent c5d0770 commit f6e0bc2
Show file tree
Hide file tree
Showing 12 changed files with 1,127 additions and 267 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub struct DepositWormholeTbtc<'info> {
tbtc_config: UncheckedAccount<'info>,

/// CHECK: TBTC program requires this account.
minter_info: UncheckedAccount<'info>,
tbtc_minter_info: UncheckedAccount<'info>,

token_program: Program<'info, token::Token>,
tbtc_program: Program<'info, tbtc::Tbtc>,
Expand Down Expand Up @@ -102,7 +102,7 @@ pub fn deposit_wormhole_tbtc(ctx: Context<DepositWormholeTbtc>, amount: u64) ->
tbtc::cpi::accounts::Mint {
mint: ctx.accounts.tbtc_mint.to_account_info(),
config: ctx.accounts.tbtc_config.to_account_info(),
minter_info: ctx.accounts.minter_info.to_account_info(),
minter_info: ctx.accounts.tbtc_minter_info.to_account_info(),
minter: custodian.to_account_info(),
recipient_token: ctx.accounts.recipient_token.to_account_info(),
token_program: ctx.accounts.token_program.to_account_info(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub struct Initialize<'info> {
init,
payer = authority,
token::mint = wrapped_tbtc_mint,
token::authority = authority,
token::authority = custodian,
seeds = [b"wrapped-token"],
bump
)]
Expand All @@ -59,14 +59,13 @@ pub struct Initialize<'info> {
)]
token_bridge_sender: AccountInfo<'info>,

/// CHECK: This account is needed for the Token Bridge program. This PDA is specifically used to
/// sign for transferring via Token Bridge program with a message.
#[account(
seeds = [token_bridge::SEED_PREFIX_REDEEMER],
bump,
)]
token_bridge_redeemer: AccountInfo<'info>,

// /// CHECK: This account is needed for the Token Bridge program. This PDA is specifically used to
// /// sign for transferring via Token Bridge program with a message.
// #[account(
// seeds = [token_bridge::SEED_PREFIX_REDEEMER],
// bump,
// )]
// token_bridge_redeemer: AccountInfo<'info>,
system_program: Program<'info, System>,
token_program: Program<'info, token::Token>,
}
Expand All @@ -80,8 +79,8 @@ pub fn initialize(ctx: Context<Initialize>, minting_limit: u64) -> Result<()> {
wrapped_tbtc_token: ctx.accounts.wrapped_tbtc_token.key(),
token_bridge_sender: ctx.accounts.token_bridge_sender.key(),
token_bridge_sender_bump: ctx.bumps["token_bridge_sender"],
token_bridge_redeemer: ctx.accounts.token_bridge_sender.key(),
token_bridge_redeemer_bump: ctx.bumps["token_bridge_redeemer"],
// token_bridge_redeemer: ctx.accounts.token_bridge_redeemer.key(),
// token_bridge_redeemer_bump: ctx.bumps["token_bridge_redeemer"],
minting_limit,
minted_amount: 0,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub struct ReceiveTbtc<'info> {
has_one = wrapped_tbtc_token,
has_one = wrapped_tbtc_mint,
has_one = tbtc_mint,
has_one = token_bridge_redeemer,
//has_one = token_bridge_redeemer,
)]
custodian: Account<'info, Custodian>,

Expand All @@ -38,11 +38,18 @@ pub struct ReceiveTbtc<'info> {
/// transfer. By checking whether this account exists is a short-circuit way of bailing out
/// early if this transfer has already been redeemed (as opposed to letting the Token Bridge
/// instruction fail).
#[account(mut)]
token_bridge_claim: AccountInfo<'info>,

/// Custody account.
#[account(mut)]
wrapped_tbtc_token: Box<Account<'info, token::TokenAccount>>,

/// This mint is owned by the Wormhole Token Bridge program. This PDA address is stored in the
/// custodian account.
#[account(mut)]
wrapped_tbtc_mint: Box<Account<'info, token::Mint>>,

#[account(mut)]
tbtc_mint: Box<Account<'info, token::Mint>>,

Expand Down Expand Up @@ -83,17 +90,14 @@ pub struct ReceiveTbtc<'info> {
/// CHECK: This account is needed for the TBTC program.
tbtc_minter_info: UncheckedAccount<'info>,

/// CHECK: This account is needed for the Token Bridge program.
wrapped_tbtc_mint: UncheckedAccount<'info>,

/// CHECK: This account is needed for the Token Bridge program.
token_bridge_config: UncheckedAccount<'info>,

/// CHECK: This account is needed for the Token Bridge program.
token_bridge_registered_emitter: UncheckedAccount<'info>,

/// CHECK: This account is needed for the Token Bridge program.
token_bridge_redeemer: UncheckedAccount<'info>,
//token_bridge_redeemer: UncheckedAccount<'info>,

/// CHECK: This account is needed for the Token Bridge program.
token_bridge_wrapped_asset: UncheckedAccount<'info>,
Expand All @@ -105,9 +109,9 @@ pub struct ReceiveTbtc<'info> {
rent: UncheckedAccount<'info>,

tbtc_program: Program<'info, tbtc::Tbtc>,
associated_token_program: Program<'info, associated_token::AssociatedToken>,
token_bridge_program: Program<'info, TokenBridge>,
core_bridge_program: Program<'info, CoreBridge>,
associated_token_program: Program<'info, associated_token::AssociatedToken>,
token_program: Program<'info, token::Token>,
system_program: Program<'info, System>,
}
Expand Down Expand Up @@ -164,7 +168,7 @@ pub fn receive_tbtc(ctx: Context<ReceiveTbtc>, _message_hash: [u8; 32]) -> Resul
.token_bridge_registered_emitter
.to_account_info(),
to: wrapped_tbtc_token.to_account_info(),
redeemer: ctx.accounts.token_bridge_redeemer.to_account_info(),
redeemer: ctx.accounts.custodian.to_account_info(),
wrapped_mint: wrapped_tbtc_mint.to_account_info(),
wrapped_metadata: ctx.accounts.token_bridge_wrapped_asset.to_account_info(),
mint_authority: ctx.accounts.token_bridge_mint_authority.to_account_info(),
Expand All @@ -175,7 +179,7 @@ pub fn receive_tbtc(ctx: Context<ReceiveTbtc>, _message_hash: [u8; 32]) -> Resul
},
&[&[
token_bridge::SEED_PREFIX_REDEEMER,
&[ctx.accounts.custodian.token_bridge_redeemer_bump],
&[ctx.accounts.custodian.bump],
]],
))?;

Expand All @@ -195,6 +199,8 @@ pub fn receive_tbtc(ctx: Context<ReceiveTbtc>, _message_hash: [u8; 32]) -> Resul
// We send Wormhole tBTC OR mint canonical tBTC. We do not want to send dust. Sending Wormhole
// tBTC is an exceptional situation and we want to keep it simple.
if updated_minted_amount > ctx.accounts.custodian.minting_limit {
msg!("Insufficient minted amount. Sending Wormhole tBTC instead");

let ata = &ctx.accounts.recipient_wrapped_token;

// Create associated token account for recipient if it doesn't exist already.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct SendTbtcGateway<'info> {
has_one = wrapped_tbtc_mint,
has_one = tbtc_mint,
has_one = token_bridge_sender,
// has_one = tbtc_minter_info, TODO: add this guy to custodian
)]
custodian: Account<'info, Custodian>,

Expand All @@ -26,9 +27,11 @@ pub struct SendTbtcGateway<'info> {
gateway_info: Account<'info, GatewayInfo>,

/// Custody account.
#[account(mut)]
wrapped_tbtc_token: Box<Account<'info, token::TokenAccount>>,

/// CHECK: This account is needed for the Token Bridge program.
#[account(mut)]
wrapped_tbtc_mint: UncheckedAccount<'info>,

#[account(mut)]
Expand Down Expand Up @@ -149,6 +152,7 @@ pub fn send_tbtc_gateway(ctx: Context<SendTbtcGateway>, args: SendTbtcGatewayArg
let custodian = &ctx.accounts.custodian;

// Finally transfer wrapped tBTC with the recipient encoded as this transfer's message.
// TODO: fix bug here: InvalidSigner(GZqbpJ4J1d4TwEG76fnQk48za4JE2FA13qaqWF8h1rvs)
token_bridge::transfer_wrapped_with_payload(
CpiContext::new_with_signer(
ctx.accounts.token_bridge_program.to_account_info(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ pub struct SendTbtcWrapped<'info> {
custodian: Account<'info, Custodian>,

/// Custody account.
#[account(mut)]
wrapped_tbtc_token: Box<Account<'info, token::TokenAccount>>,

/// CHECK: This account is needed for the Token Bridge program.
#[account(mut)]
wrapped_tbtc_mint: UncheckedAccount<'info>,

#[account(mut)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anchor_lang::prelude::*;
use wormhole_anchor_sdk::token_bridge;

#[account]
#[derive(Debug, InitSpace)]
Expand All @@ -11,13 +12,13 @@ pub struct Custodian {
pub wrapped_tbtc_token: Pubkey,
pub token_bridge_sender: Pubkey,
pub token_bridge_sender_bump: u8,
pub token_bridge_redeemer: Pubkey,
pub token_bridge_redeemer_bump: u8,

// pub token_bridge_redeemer: Pubkey,
// pub token_bridge_redeemer_bump: u8,
pub minting_limit: u64,
pub minted_amount: u64,
}

impl Custodian {
pub const SEED_PREFIX: &'static [u8] = b"custodian";
/// TODO: This is an undesirable pattern in the Token Bridge due to how transfers are redeemed.
pub const SEED_PREFIX: &'static [u8] = token_bridge::SEED_PREFIX_REDEEMER;
}
21 changes: 8 additions & 13 deletions cross-chain/solana/tests/01__tbtc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
getConfigPDA,
getGuardianPDA,
getGuardiansPDA,
getMinterPDA,
getMinterInfoPDA,
getMintersPDA,
getTokenPDA,
maybeAuthorityAnd,
Expand Down Expand Up @@ -95,7 +95,7 @@ async function checkPaused(program: Program<Tbtc>, paused: boolean) {
}

async function checkMinter(program: Program<Tbtc>, minter) {
const minterInfoPDA = getMinterPDA(minter.publicKey);
const minterInfoPDA = getMinterInfoPDA(minter.publicKey);
let minterInfo = await program.account.minterInfo.fetch(minterInfoPDA);

expect(minterInfo.minter).to.eql(minter.publicKey);
Expand Down Expand Up @@ -343,12 +343,7 @@ describe("tbtc", () => {
await checkState(authority, 1, 0, 0);

// Transfer lamports to imposter.
await transferLamports(
program.provider.connection,
authority.payer,
impostorKeys.publicKey,
1000000000
);
await transferLamports(authority.payer, impostorKeys.publicKey, 1000000000);
// await web3.sendAndConfirmTransaction(
// program.provider.connection,
// new web3.Transaction().add(
Expand All @@ -374,7 +369,7 @@ describe("tbtc", () => {

it("mint", async () => {
await checkState(authority, 1, 0, 0);
const minterInfoPDA = getMinterPDA(minterKeys.publicKey);
const minterInfoPDA = getMinterInfoPDA(minterKeys.publicKey);
await checkMinter(program, minterKeys);

// await setupMint(program, authority, recipientKeys);
Expand All @@ -401,7 +396,7 @@ describe("tbtc", () => {

it("won't mint", async () => {
await checkState(authority, 1, 0, 1000);
const minterInfoPDA = getMinterPDA(minterKeys.publicKey);
const minterInfoPDA = getMinterInfoPDA(minterKeys.publicKey);
await checkMinter(program, minterKeys);

// await setupMint(program, authority, recipientKeys);
Expand All @@ -426,7 +421,7 @@ describe("tbtc", () => {

it("use two minters", async () => {
await checkState(authority, 1, 0, 1000);
const minterInfoPDA = getMinterPDA(minterKeys.publicKey);
const minterInfoPDA = getMinterInfoPDA(minterKeys.publicKey);
await checkMinter(program, minterKeys);
const minter2InfoPDA = await addMinter(authority, minter2Keys.publicKey);
await checkMinter(program, minter2Keys);
Expand Down Expand Up @@ -475,15 +470,15 @@ describe("tbtc", () => {

it("remove minter", async () => {
await checkState(authority, 2, 0, 1500);
const minter2InfoPDA = getMinterPDA(minter2Keys.publicKey);
const minter2InfoPDA = getMinterInfoPDA(minter2Keys.publicKey);
await checkMinter(program, minter2Keys);
await removeMinter(program, authority, minter2Keys, minter2InfoPDA);
await checkState(authority, 1, 0, 1500);
});

it("won't remove minter", async () => {
await checkState(authority, 1, 0, 1500);
const minterInfoPDA = getMinterPDA(minterKeys.publicKey);
const minterInfoPDA = getMinterInfoPDA(minterKeys.publicKey);
await checkMinter(program, minterKeys);

try {
Expand Down
Loading

0 comments on commit f6e0bc2

Please sign in to comment.