Skip to content

Commit

Permalink
squash commits from branch wthdraw-spl-to-new-account
Browse files Browse the repository at this point in the history
  • Loading branch information
brewmaster012 committed Oct 10, 2024
1 parent 705831d commit dc790a7
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 85 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,4 @@ brew install gnu-tar
# Put this in ~/.zshrc
export PATH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH"
```
see https://solana.stackexchange.com/questions/4499/blockstore-error-when-starting-solana-test-validator-on-macos-13-0-1/16319#16319
see https://solana.stackexchange.com/questions/4499/blockstore-error-when-starting-solana-test-validator-on-macos-13-0-1/16319#16319
2 changes: 1 addition & 1 deletion programs/protocol-contracts-solana/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ idl-build = ["anchor-lang/idl-build"]

[dependencies]
anchor-lang = { version = "=0.30.0" }
anchor-spl = { version = "=0.30.0" , features = ["idl-build"]}
anchor-spl = { version = "=0.30.0", features = ["idl-build"] }
anchor-syn = "=0.30.0"
spl-associated-token-account = "3.0.2"
solana-program = "=1.18.15"
97 changes: 91 additions & 6 deletions programs/protocol-contracts-solana/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use anchor_lang::prelude::*;
use anchor_lang::system_program;
use anchor_spl::associated_token::get_associated_token_address;
use anchor_spl::associated_token::{get_associated_token_address, AssociatedToken};
use anchor_spl::token::{transfer, transfer_checked, Mint, Token, TokenAccount};
use solana_program::keccak::hash;
use solana_program::program::invoke;
use solana_program::secp256k1_recover::secp256k1_recover;
use solana_program::sysvar::{rent::Rent, Sysvar};
use spl_associated_token_account::instruction::create_associated_token_account;
use std::mem::size_of;

#[error_code]
Expand Down Expand Up @@ -97,6 +100,10 @@ pub mod gateway {
Ok(())
}

pub fn initialize_rent_payer(_ctx: Context<InitializeRentPayer>) -> Result<()> {
Ok(())
}

// deposit SOL into this program and the `receiver` on ZetaChain zEVM
// will get corresponding ZRC20 credit.
// amount: amount of lamports (10^-9 SOL) to deposit
Expand Down Expand Up @@ -267,7 +274,7 @@ pub mod gateway {
concatenated_buffer.extend_from_slice(&nonce.to_be_bytes());
concatenated_buffer.extend_from_slice(&amount.to_be_bytes());
concatenated_buffer.extend_from_slice(&ctx.accounts.mint_account.key().to_bytes());
concatenated_buffer.extend_from_slice(&ctx.accounts.to.key().to_bytes());
concatenated_buffer.extend_from_slice(&ctx.accounts.recipient_ata.key().to_bytes());
require!(
message_hash == hash(&concatenated_buffer[..]).to_bytes(),
Errors::MessageHashMismatch
Expand All @@ -286,18 +293,77 @@ pub mod gateway {
let pda_ata = get_associated_token_address(&pda.key(), &ctx.accounts.mint_account.key());
require!(
pda_ata == ctx.accounts.pda_ata.to_account_info().key(),
Errors::SPLAtaAndMintAddressMismatch
Errors::SPLAtaAndMintAddressMismatch,
);

let token = &ctx.accounts.token_program;
let signer_seeds: &[&[&[u8]]] = &[&[b"meta", &[ctx.bumps.pda]]];
// make sure that ctx.accounts.recipient_ata is ATA (PDA account of token program)
let recipient_ata = get_associated_token_address(
&ctx.accounts.recipient.key(),
&ctx.accounts.mint_account.key(),
);
require!(
recipient_ata == ctx.accounts.recipient_ata.to_account_info().key(),
Errors::SPLAtaAndMintAddressMismatch,
);

// test whether the recipient_ata is created or not; if not, create it
let recipient_ata_account = ctx.accounts.recipient_ata.to_account_info();
if recipient_ata_account.lamports() == 0
|| *recipient_ata_account.owner == ctx.accounts.system_program.key()
{
// if lamports of recipient_ata_account is 0 or its owner being system program then it's not created
msg!(
"Creating associated token account {:?} for recipient {:?}...",
recipient_ata_account.key(),
ctx.accounts.recipient.key(),
);
let signer_info = &ctx.accounts.signer.to_account_info();
let bal0 = signer_info.lamports();
invoke(
&create_associated_token_account(
ctx.accounts.signer.to_account_info().key,
ctx.accounts.recipient.to_account_info().key,
ctx.accounts.mint_account.to_account_info().key,
ctx.accounts.token_program.key,
),
&[
ctx.accounts.mint_account.to_account_info().clone(),
ctx.accounts.recipient_ata.clone(),
ctx.accounts.recipient.to_account_info().clone(),
ctx.accounts.signer.to_account_info().clone(),
ctx.accounts.system_program.to_account_info().clone(),
ctx.accounts.token_program.to_account_info().clone(),
ctx.accounts
.associated_token_program
.to_account_info()
.clone(),
],
)?;
let bal1 = signer_info.lamports();

msg!("Associated token account for recipient created!");
msg!(
"Refunding the rent paid by the signer {:?}",
ctx.accounts.signer.to_account_info().key
);

let rent_payer_info = ctx.accounts.rent_payer_pda.to_account_info();
rent_payer_info.sub_lamports(bal0 - bal1)?;
signer_info.add_lamports(bal0 - bal1)?;
msg!(
"Signer refunded the ATA account creation rent amount {:?} lamports",
bal0 - bal1
);
}

let xfer_ctx = CpiContext::new_with_signer(
token.to_account_info(),
anchor_spl::token::TransferChecked {
from: ctx.accounts.pda_ata.to_account_info(),
mint: ctx.accounts.mint_account.to_account_info(),
to: ctx.accounts.to.to_account_info(),
to: ctx.accounts.recipient_ata.to_account_info(),
authority: pda.to_account_info(),
},
signer_seeds,
Expand Down Expand Up @@ -393,15 +459,22 @@ pub struct WithdrawSPLToken<'info> {
#[account(mut, seeds = [b"meta"], bump)]
pub pda: Account<'info, Pda>,

#[account(mut, token::mint = mint_account, token::authority = pda)]
#[account(mut, associated_token::mint = mint_account, associated_token::authority = pda)]
pub pda_ata: Account<'info, TokenAccount>, // associated token address of PDA

pub mint_account: Account<'info, Mint>,

pub recipient: SystemAccount<'info>,
/// CHECK: recipient_ata might not have been created; avoid checking its content.
/// the validation will be done in the instruction processor.
#[account(mut)]
pub to: Account<'info, TokenAccount>,
pub recipient_ata: AccountInfo<'info>,

#[account(mut, seeds = [b"rent-payer"], bump)]
pub rent_payer_pda: Account<'info, RentPayerPda>,
pub token_program: Program<'info, Token>,
pub associated_token_program: Program<'info, AssociatedToken>,
pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
Expand Down Expand Up @@ -473,6 +546,15 @@ pub struct Unwhitelist<'info> {
pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct InitializeRentPayer<'info> {
#[account(init, payer = authority, space = 8, seeds = [b"rent-payer"], bump)]
pub rent_payer_pda: Account<'info, RentPayerPda>,
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}

#[account]
pub struct Pda {
nonce: u64, // ensure that each signature can only be used once
Expand All @@ -485,6 +567,9 @@ pub struct Pda {
#[account]
pub struct WhitelistEntry {}

#[account]
pub struct RentPayerPda {}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading

0 comments on commit dc790a7

Please sign in to comment.