ITS ALIVE. solana purchase works
This commit is contained in:
parent
35c47cab60
commit
5b6dd035e1
|
@ -24,3 +24,11 @@ pub struct Redeemer {}
|
|||
pub struct MintInfo {
|
||||
pub mint: Pubkey
|
||||
}
|
||||
|
||||
#[account]
|
||||
pub struct Receipt {
|
||||
pub amt_to_mint: u64,
|
||||
pub foreign_receipient: [u8; 32],
|
||||
pub foreign_chain: u16,
|
||||
pub claimed: bool
|
||||
}
|
|
@ -6,7 +6,7 @@ use crate::wormhole::*;
|
|||
use crate::constant::*;
|
||||
use std::str::FromStr;
|
||||
use anchor_spl::token::ID as spl_id;
|
||||
|
||||
use crate::*;
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Initialize<'info>{
|
||||
|
@ -82,6 +82,7 @@ pub struct RegisterChain<'info> {
|
|||
pub emitter_acc: Account<'info, EmitterAddrAccount>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct SubmitForeignPurchase<'info> {
|
||||
#[account(mut)]
|
||||
|
@ -93,6 +94,16 @@ pub struct SubmitForeignPurchase<'info> {
|
|||
bump,
|
||||
)]
|
||||
pub config: Account<'info, Config>,
|
||||
#[account(
|
||||
init,
|
||||
seeds = [
|
||||
vaa_hash(core_bridge_vaa.clone()).as_slice()
|
||||
],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = 64
|
||||
)]
|
||||
pub receipt: Account<'info, Receipt>,
|
||||
|
||||
// Fetch the VAA
|
||||
/// CHECK: Checked in lib.rs because it requires some fancy hashing
|
||||
|
@ -187,20 +198,37 @@ pub struct SubmitForeignPurchase<'info> {
|
|||
)]
|
||||
pub mint_authority_wrapped: AccountInfo<'info>,
|
||||
pub rent_account: Sysvar<'info, Rent>,
|
||||
/// CHECK: Make sure this is the right token bridge account
|
||||
/// CHECK: Make sure this is the right core bridge account
|
||||
#[account(
|
||||
constraint = token_bridge_program.key() == Pubkey::from_str(TOKEN_BRIDGE_ADDRESS).unwrap()
|
||||
constraint = core_bridge.key() == Pubkey::from_str(CORE_BRIDGE_ADDRESS).unwrap()
|
||||
)]
|
||||
pub token_bridge_program: AccountInfo<'info>,
|
||||
pub core_bridge: AccountInfo<'info>,
|
||||
/// CHECK: SPL Program should be actual SPL Program
|
||||
#[account(
|
||||
constraint = spl_program.key() == spl_id
|
||||
)]
|
||||
pub spl_program: AccountInfo<'info>,
|
||||
|
||||
/// CHECK: Make sure this is the right token bridge account
|
||||
#[account(
|
||||
constraint = token_bridge.key() == Pubkey::from_str(TOKEN_BRIDGE_ADDRESS).unwrap()
|
||||
)]
|
||||
pub token_bridge: AccountInfo<'info>
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct ClaimForeignPurchase<'info> {
|
||||
#[account(mut)]
|
||||
pub payer: Signer<'info>,
|
||||
pub system_program: Program<'info, System>,
|
||||
#[account(
|
||||
mut,
|
||||
seeds = [b"config"],
|
||||
bump,
|
||||
)]
|
||||
pub config: Account<'info, Config>,
|
||||
#[account(mut)]
|
||||
pub receipt: Account<'info, Receipt>,
|
||||
|
||||
|
||||
// Mint SOL#T SPL tokens to Contract PDA
|
||||
|
@ -209,6 +237,7 @@ pub struct SubmitForeignPurchase<'info> {
|
|||
#[account(
|
||||
seeds=[b"mint_authority"],
|
||||
bump,
|
||||
mut
|
||||
)]
|
||||
pub xmint_authority: Account<'info, MintInfo>,
|
||||
/// CHECK: TODO: Check if owned by SPL program
|
||||
|
@ -219,7 +248,7 @@ pub struct SubmitForeignPurchase<'info> {
|
|||
// P1 Portal Transfer to Recepient
|
||||
#[account(
|
||||
seeds = [
|
||||
b"mint",
|
||||
xmint_token_mint.key().to_bytes().as_slice(),
|
||||
],
|
||||
bump,
|
||||
seeds::program = Pubkey::from_str(TOKEN_BRIDGE_ADDRESS).unwrap(),
|
||||
|
@ -255,6 +284,7 @@ pub struct SubmitForeignPurchase<'info> {
|
|||
)]
|
||||
/// CHECK: The seeds constraint should check validity
|
||||
pub core_bridge_config: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
pub xmint_transfer_msg_key: Signer<'info>,
|
||||
#[account(
|
||||
seeds=[
|
||||
|
@ -292,4 +322,27 @@ pub struct SubmitForeignPurchase<'info> {
|
|||
constraint = core_bridge.key() == Pubkey::from_str(CORE_BRIDGE_ADDRESS).unwrap()
|
||||
)]
|
||||
pub core_bridge: AccountInfo<'info>,
|
||||
|
||||
|
||||
|
||||
/// CHECK: SPL Program should be actual SPL Program
|
||||
#[account(
|
||||
constraint = spl_program.key() == spl_id
|
||||
)]
|
||||
pub spl_program: AccountInfo<'info>,
|
||||
#[account(
|
||||
mut,
|
||||
seeds = [b"config"],
|
||||
bump,
|
||||
seeds::program = Pubkey::from_str(TOKEN_BRIDGE_ADDRESS).unwrap()
|
||||
)]
|
||||
/// CHECK: Token Bridge Config
|
||||
pub token_bridge_config: AccountInfo<'info>,
|
||||
pub rent_account: Sysvar<'info, Rent>,
|
||||
|
||||
/// CHECK: Make sure this is the right token bridge account
|
||||
#[account(
|
||||
constraint = token_bridge.key() == Pubkey::from_str(TOKEN_BRIDGE_ADDRESS).unwrap()
|
||||
)]
|
||||
pub token_bridge: AccountInfo<'info>
|
||||
}
|
|
@ -9,4 +9,7 @@ pub enum XmintError {
|
|||
|
||||
#[msg("Posted VAA Emitter Chain ID or Address Mismatch")]
|
||||
VAAEmitterMismatch,
|
||||
|
||||
#[msg("Receipt already claimed!")]
|
||||
ReceiptClaimed,
|
||||
}
|
|
@ -4,8 +4,7 @@ use mpl_token_metadata::ID as metadata_program_id;
|
|||
use anchor_lang::solana_program::program::invoke_signed;
|
||||
use anchor_lang::solana_program::instruction::{Instruction, AccountMeta};
|
||||
use anchor_lang::solana_program::{sysvar::rent, system_program};
|
||||
use anchor_spl::token::{ID as spl_id, mint_to};
|
||||
use anchor_spl::token::MintTo;
|
||||
use anchor_spl::token::{ID as spl_id, mint_to, approve, MintTo, Approve};
|
||||
|
||||
use sha3::Digest;
|
||||
use byteorder::{
|
||||
|
@ -97,17 +96,11 @@ pub mod solana {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
//Submit Foreign Purchase
|
||||
pub fn submit_foreign_purchase(ctx:Context<SubmitForeignPurchase>) -> Result<()> {
|
||||
// Fetch the VAA
|
||||
//Hash a VAA Extract and derive a VAA Key
|
||||
let vaa = PostedMessageData::try_from_slice(&ctx.accounts.core_bridge_vaa.data.borrow())?.0;
|
||||
let serialized_vaa = serialize_vaa(&vaa);
|
||||
|
||||
let mut h = sha3::Keccak256::default();
|
||||
h.write(serialized_vaa.as_slice()).unwrap();
|
||||
let vaa_hash: [u8; 32] = h.finalize().into();
|
||||
let vaa_hash: [u8; 32] = vaa_hash(ctx.accounts.core_bridge_vaa.clone());
|
||||
|
||||
let (vaa_key, _) = Pubkey::find_program_address(&[
|
||||
b"PostedVAA",
|
||||
|
@ -129,7 +122,6 @@ pub mod solana {
|
|||
|
||||
|
||||
|
||||
|
||||
// Complete Transfer of P3 on Portal
|
||||
let complete_wrapped_ix = Instruction {
|
||||
program_id: Pubkey::from_str(TOKEN_BRIDGE_ADDRESS).unwrap(),
|
||||
|
@ -147,7 +139,7 @@ pub mod solana {
|
|||
AccountMeta::new_readonly(ctx.accounts.mint_authority_wrapped.key(), false),
|
||||
AccountMeta::new_readonly(rent::id(), false),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
AccountMeta::new_readonly(ctx.accounts.token_bridge_program.key(), false),
|
||||
AccountMeta::new_readonly(ctx.accounts.core_bridge.key(), false),
|
||||
AccountMeta::new_readonly(spl_id, false),
|
||||
],
|
||||
data: (
|
||||
|
@ -170,7 +162,7 @@ pub mod solana {
|
|||
ctx.accounts.mint_authority_wrapped.to_account_info(),
|
||||
ctx.accounts.rent_account.to_account_info(),
|
||||
ctx.accounts.system_program.to_account_info(),
|
||||
ctx.accounts.token_bridge_program.to_account_info(),
|
||||
ctx.accounts.core_bridge.to_account_info(),
|
||||
ctx.accounts.spl_program.to_account_info()
|
||||
];
|
||||
|
||||
|
@ -185,18 +177,24 @@ pub mod solana {
|
|||
&[&complete_p3_seeds[..]]
|
||||
)?;
|
||||
|
||||
|
||||
|
||||
|
||||
// Mint SOL#T SPL tokens to Contract PDA
|
||||
|
||||
//// Figure out how many tokens to mint based on p3 payload
|
||||
let payload: PayloadTransferWithPayload = PayloadTransferWithPayload::deserialize(&mut vaa.payload.as_slice())?;
|
||||
let amt_to_mint:u64 = payload.amount.as_u64() * 100;
|
||||
ctx.accounts.receipt.amt_to_mint = payload.amount.as_u64() * 100;
|
||||
ctx.accounts.receipt.foreign_chain = vaa.emitter_chain;
|
||||
ctx.accounts.receipt.foreign_receipient = payload.payload.as_slice().try_into().unwrap();
|
||||
ctx.accounts.receipt.claimed = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn claim_foreign_purchase(ctx:Context<ClaimForeignPurchase>) -> Result<()> {
|
||||
if ctx.accounts.receipt.claimed {
|
||||
return err!(XmintError::ReceiptClaimed);
|
||||
}
|
||||
|
||||
let mint_seeds:&[&[u8]] = &[
|
||||
b"mint_authority",
|
||||
&[*ctx.bumps.get("mint_authority").unwrap()]
|
||||
&[*ctx.bumps.get("xmint_authority").unwrap()]
|
||||
];
|
||||
|
||||
mint_to(
|
||||
|
@ -210,7 +208,21 @@ pub mod solana {
|
|||
program: ctx.accounts.spl_program.to_account_info(),
|
||||
signer_seeds: &[&mint_seeds[..]]
|
||||
},
|
||||
amt_to_mint
|
||||
ctx.accounts.receipt.amt_to_mint
|
||||
)?;
|
||||
|
||||
// Delgate transfer authority to Token Bridge for the newly minted tokens
|
||||
approve(
|
||||
CpiContext::new_with_signer(
|
||||
ctx.accounts.spl_program.to_account_info(),
|
||||
Approve {
|
||||
to: ctx.accounts.xmint_ata_account.to_account_info(),
|
||||
delegate: ctx.accounts.token_bridge_authority_signer.to_account_info(),
|
||||
authority: ctx.accounts.xmint_authority.to_account_info()
|
||||
},
|
||||
&[&mint_seeds[..]]
|
||||
),
|
||||
ctx.accounts.receipt.amt_to_mint
|
||||
)?;
|
||||
|
||||
// Transfer tokens from Contract PDA to P1 on Portal
|
||||
|
@ -242,10 +254,10 @@ pub mod solana {
|
|||
crate::portal::Instruction::TransferNative,
|
||||
TransferNativeData {
|
||||
nonce: ctx.accounts.config.nonce,
|
||||
amount: amt_to_mint,
|
||||
amount: ctx.accounts.receipt.amt_to_mint,
|
||||
fee: 0,
|
||||
target_address: payload.payload.as_slice().try_into().unwrap(),
|
||||
target_chain: vaa.emitter_chain
|
||||
target_address: ctx.accounts.receipt.foreign_receipient,
|
||||
target_chain: ctx.accounts.receipt.foreign_chain
|
||||
}
|
||||
).try_to_vec()?
|
||||
};
|
||||
|
@ -276,7 +288,7 @@ pub mod solana {
|
|||
// Signer Seeds
|
||||
let xmint_authority_seeds:&[&[u8]] = &[
|
||||
b"mint_authority",
|
||||
&[*ctx.bumps.get("mint_authority").unwrap()]
|
||||
&[*ctx.bumps.get("xmint_authority").unwrap()]
|
||||
];
|
||||
|
||||
invoke_signed(
|
||||
|
@ -286,6 +298,7 @@ pub mod solana {
|
|||
)?;
|
||||
|
||||
ctx.accounts.config.nonce += 1;
|
||||
ctx.accounts.receipt.claimed = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -304,3 +317,12 @@ pub fn serialize_vaa(vaa: &MessageData) -> Vec<u8> {
|
|||
v.write(&vaa.payload).unwrap();
|
||||
v.into_inner()
|
||||
}
|
||||
|
||||
pub fn vaa_hash(vaa: AccountInfo) -> [u8; 32] {
|
||||
let vaa = PostedMessageData::try_from_slice(&vaa.data.borrow()).unwrap().0;
|
||||
let serialized_vaa = serialize_vaa(&vaa);
|
||||
let mut h = sha3::Keccak256::default();
|
||||
h.write(serialized_vaa.as_slice()).unwrap();
|
||||
let vaa_hash: [u8; 32] = h.finalize().into();
|
||||
return vaa_hash;
|
||||
}
|
||||
|
|
|
@ -488,7 +488,7 @@ export async function submitForeignPurchase(src:string, target:string, vaa:strin
|
|||
);
|
||||
|
||||
// P1 Portal Transfer back to Recepient Accounts
|
||||
const tokenBridgeMintCustody = findProgramAddressSync([Buffer.from("mint")], tokenBridgePubKey)[0];
|
||||
const tokenBridgeMintCustody = findProgramAddressSync([xmintTokenMint.toBuffer()], tokenBridgePubKey)[0];
|
||||
const tokenBridgeAuthoritySigner = findProgramAddressSync([Buffer.from("authority_signer")], tokenBridgePubKey)[0];
|
||||
const tokenBridgeCustodySigner = findProgramAddressSync([Buffer.from("custody_signer")], tokenBridgePubKey)[0];
|
||||
const coreBridgeConfig = findProgramAddressSync([Buffer.from("Bridge")], coreBridgePubKey)[0];
|
||||
|
@ -500,7 +500,11 @@ export async function submitForeignPurchase(src:string, target:string, vaa:strin
|
|||
], coreBridgePubKey)[0];
|
||||
const coreBridgeFeeCollector = findProgramAddressSync([Buffer.from("fee_collector")], coreBridgePubKey)[0];
|
||||
|
||||
const tx = await xmint.methods
|
||||
// need to split the following into two because Solana account limit
|
||||
const receiptAcc = findProgramAddressSync([ Buffer.from(vaaHash, "hex") ], xmint.programId)[0];
|
||||
|
||||
// Submit Foreign Purchase
|
||||
const submitTx = await xmint.methods
|
||||
.submitForeignPurchase()
|
||||
.accounts({
|
||||
payer: srcKey.publicKey,
|
||||
|
@ -509,6 +513,7 @@ export async function submitForeignPurchase(src:string, target:string, vaa:strin
|
|||
coreBridgeVaa: coreBridgeVaaKey,
|
||||
processedVaa: processedVaaKey,
|
||||
emitterAcc: emitterAddressAcc,
|
||||
receipt: receiptAcc,
|
||||
|
||||
tokenBridgeConfig: tokenBridgeConfigAcc,
|
||||
tokenBridgeClaimKey: tokenBridgeClaimAcc,
|
||||
|
@ -519,7 +524,32 @@ export async function submitForeignPurchase(src:string, target:string, vaa:strin
|
|||
wethMintWrappedMeta: wethWrappedMeta,
|
||||
mintAuthorityWrapped: mintAuthorityWrapped,
|
||||
rentAccount: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||
tokenBridgeProgram: tokenBridgePubKey,
|
||||
coreBridge: coreBridgePubKey,
|
||||
splProgram: TOKEN_PROGRAM_ID,
|
||||
|
||||
tokenBridge: tokenBridgePubKey
|
||||
})
|
||||
.preInstructions([
|
||||
anchor.web3.ComputeBudgetProgram.requestUnits({
|
||||
units: 1400000,
|
||||
additionalFee: 0,
|
||||
})
|
||||
])
|
||||
.rpc();
|
||||
|
||||
await new Promise((r) => setTimeout(r, 16000)); //wait for accounts to finialize
|
||||
|
||||
// Claim Foreign Purchase
|
||||
const claimTx = await xmint.methods
|
||||
.claimForeignPurchase()
|
||||
.accounts({
|
||||
payer: srcKey.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
config: configAcc,
|
||||
receipt: receiptAcc,
|
||||
|
||||
rentAccount: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||
tokenBridgeConfig: tokenBridgeConfigAcc,
|
||||
splProgram: TOKEN_PROGRAM_ID,
|
||||
|
||||
xmintTokenMint: xmintTokenMint,
|
||||
|
@ -535,7 +565,9 @@ export async function submitForeignPurchase(src:string, target:string, vaa:strin
|
|||
tokenBridgeSequenceKey: tokenBridgeSequenceKey,
|
||||
coreBridgeFeeCollector: coreBridgeFeeCollector,
|
||||
clock: anchor.web3.SYSVAR_CLOCK_PUBKEY,
|
||||
coreBridge: coreBridgePubKey
|
||||
coreBridge: coreBridgePubKey,
|
||||
|
||||
tokenBridge: tokenBridgePubKey
|
||||
})
|
||||
.preInstructions([
|
||||
anchor.web3.ComputeBudgetProgram.requestUnits({
|
||||
|
@ -546,7 +578,7 @@ export async function submitForeignPurchase(src:string, target:string, vaa:strin
|
|||
.signers([transferMsgKey])
|
||||
.rpc();
|
||||
|
||||
const sfpVaa = await fetchVaa(src, tx, true);
|
||||
const sfpVaa = await fetchVaa(src, claimTx, true);
|
||||
console.log(sfpVaa);
|
||||
return sfpVaa;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue