Skip to content

Commit

Permalink
feat: add freeze_nft contract
Browse files Browse the repository at this point in the history
  • Loading branch information
quanghuynguyen1902 committed Jan 31, 2023
1 parent 1fa5405 commit f19c265
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 2 deletions.
6 changes: 4 additions & 2 deletions Anchor.toml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
seeds = false
skip-lint = false
[programs.localnet]
contract_tip_bot = "3J1FznG6CXjV9HqQrvfaxLtN4vqbkNdFu7Gr3G3yVH2g"
superteam_dao_contract = "9fHpouSqNrqBKLka9WeUXkRuh2Qt97nvqtP1Km99LKXb"
freeze_nft_contract = "CQamCKHdgid5vgpRvuc88GQCFXvifPUYRTUmpgv3bDuG"
[programs.devnet]
contract_tip_bot = "3J1FznG6CXjV9HqQrvfaxLtN4vqbkNdFu7Gr3G3yVH2g"
superteam_dao_contract = "9fHpouSqNrqBKLka9WeUXkRuh2Qt97nvqtP1Km99LKXb"
freeze_nft_contract = "CQamCKHdgid5vgpRvuc88GQCFXvifPUYRTUmpgv3bDuG"

[registry]
url = "https://api.apr.dev"
Expand Down
131 changes: 131 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions programs/freeze-nft-contract/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "freeze-nft-contract"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"

[lib]
crate-type = ["cdylib", "lib"]
name = "freeze_nft_contract"

[features]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
cpi = ["no-entrypoint"]
default = []

[dependencies]
anchor-lang = { version = "0.26.0", features = ["init-if-needed"] }
anchor-spl = { version = "0.26.0", features = ["default", "spl-token"] }
mpl-token-metadata = { version="~1.7.0", features = [ "no-entrypoint" ] }
2 changes: 2 additions & 0 deletions programs/freeze-nft-contract/Xargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
11 changes: 11 additions & 0 deletions programs/freeze-nft-contract/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use anchor_lang::prelude::*;

pub const PUBKEY_SIZE: usize = std::mem::size_of::<Pubkey>();
pub const BOOL_SIZE: usize = std::mem::size_of::<bool>();
pub const I64_SIZE: usize = std::mem::size_of::<i64>();
pub const U64_SIZE: usize = std::mem::size_of::<u64>();
pub const VERSION: i8 = 1;
pub const FREEZE_SEED: &[u8] = b"freeze";
pub const META_PREFIX: &[u8] = b"metadata";
pub const EDITION_PREFIX: &[u8] = b"edition";

11 changes: 11 additions & 0 deletions programs/freeze-nft-contract/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use anchor_lang::prelude::*;

#[error_code]
pub enum ErrorCodes {
#[msg("InvalidMint")]
InvalidMint,
#[msg("InvalidOwner")]
InvalidOwner,
#[msg("InvalidAmount")]
InvalidAmount,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use anchor_lang::prelude::*;
use anchor_lang::solana_program::program::invoke_signed;
use anchor_spl::token::{self, Mint, Token, TokenAccount, Approve};
use mpl_token_metadata::{id as metadata_id, instruction::freeze_delegated_account};
use mpl_token_metadata::state::{Metadata, TokenMetadataAccount};

use crate::schemas::Authority;

use crate::constants::*;
use crate::error::*;

#[derive(Accounts)]
pub struct FreezeNft<'info> {
#[account(mut)]
pub payer: Signer<'info>,

#[account(
init,
seeds = [FREEZE_SEED.as_ref(), payer.key().as_ref(), nft_mint.key().as_ref()],
bump,
payer = payer,
space = Authority::space()
)]
pub authority: Account<'info, Authority>,

pub nft_mint: Account<'info, Mint>,

/// CHECK: metadata from token meta program.
#[account(
seeds = [META_PREFIX.as_ref(), mpl_token_metadata::id().as_ref(), nft_mint.key().as_ref()],
seeds::program = mpl_token_metadata::id(),
bump,
)]
pub nft_metadata: AccountInfo<'info>,

#[account(mut,
constraint = ata.mint == nft_mint.key() @ ErrorCodes::InvalidMint,
constraint = ata.owner == payer.key() @ ErrorCodes::InvalidOwner
)]
pub ata: Account<'info, TokenAccount>,

/// CHECK: edition from token meta program.
#[account(
seeds = [META_PREFIX.as_ref(), metadata_id().as_ref(), nft_mint.key().as_ref(), EDITION_PREFIX.as_ref()],
seeds::program = metadata_id(),
bump,
)]
pub edition: AccountInfo<'info>,

/// CHECK: metaplex program. this will be checked in the cpi call of freeze_delegated_account
pub metadata_program: UncheckedAccount<'info>,
pub system_program: Program<'info, System>,
pub token_program: Program<'info, Token>,
pub rent: Sysvar<'info, Rent>,
}

pub fn handler(
ctx: Context<FreezeNft>
) -> Result<()> {
let metadata = Metadata::from_account_info(&ctx.accounts.nft_metadata.to_account_info())?;
// let collection = metadata.collection.unwrap();
// let collection_key = collection.key;
require!(
metadata.mint == ctx.accounts.nft_mint.key(),
ErrorCodes::InvalidMint
);

let payer = ctx.accounts.payer.key();
let nft_mint_key = ctx.accounts.nft_mint.key();
let authority_bump = *ctx.bumps.get("authority").unwrap();
let authority_seeds = &[
FREEZE_SEED.as_ref(),
payer.as_ref(),
nft_mint_key.as_ref(),
&[authority_bump],
];

if ctx.accounts.ata.amount > 0 {
// Approve with offer PDA
token::approve(ctx.accounts.into_approve_context(), 1)?;

// Freeze with offer PDA
invoke_signed(
&freeze_delegated_account(
metadata_id(),
ctx.accounts.authority.key(),
ctx.accounts.ata.key(),
ctx.accounts.edition.key(),
ctx.accounts.nft_mint.key(),
),
&[
ctx.accounts.authority.to_account_info(),
ctx.accounts.ata.to_account_info(),
ctx.accounts.edition.to_account_info(),
ctx.accounts.nft_mint.to_account_info(),
ctx.accounts.metadata_program.to_account_info(),
ctx.accounts.token_program.to_account_info(),
ctx.accounts.system_program.to_account_info(),
],
&[authority_seeds],
)?;
} else {
return Err(ErrorCodes::InvalidAmount.into());
}
Ok(())
}

impl<'info> FreezeNft<'info> {
fn into_approve_context(&self) -> CpiContext<'_, '_, '_, 'info, Approve<'info>> {
let cpi_accounts = Approve {
to: self.ata.to_account_info().clone(),
delegate: self.authority.to_account_info().clone(),
authority: self.payer.to_account_info().clone(),
};
CpiContext::new(self.token_program.to_account_info().clone(), cpi_accounts)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod freeze_nft;

pub use freeze_nft::*;
3 changes: 3 additions & 0 deletions programs/freeze-nft-contract/src/instructions/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod delegated_authority;

pub use delegated_authority::*;
23 changes: 23 additions & 0 deletions programs/freeze-nft-contract/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use anchor_lang::prelude::*;
pub mod schemas;
pub mod instructions;
pub mod constants;
pub mod error;

use crate::constants::*;
use crate::error::*;

use instructions::*;
use schemas::*;

declare_id!("CQamCKHdgid5vgpRvuc88GQCFXvifPUYRTUmpgv3bDuG");

#[program]
pub mod freeze_nft_contract {
use super::*;

pub fn freeze_nft(ctx: Context<FreezeNft>) -> Result<()> {
freeze_nft::handler(ctx);
Ok(())
}
}
Loading

0 comments on commit f19c265

Please sign in to comment.