Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions candy-machine/program/Cargo.lock

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

4 changes: 2 additions & 2 deletions candy-machine/program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[workspace]
[package]
name = "mpl-candy-machine"
version = "3.1.3"
version = "3.1.4"
description = "NFT Candy Machine v2: programmatic and trustless NFT drops."
authors = ["Jordan Prince", "Metaplex Developers <dev@metaplex.com>"]
repository = "https://github.com/metaplex-foundation/metaplex-program-library"
Expand All @@ -28,4 +28,4 @@ spl-associated-token-account = { version = "1.0.3", features = [
] }
anchor-spl = "=0.21.0"
solana-program = "1.9.6"
solana-gateway = "0.1.1"
solana-gateway = { git = "https://github.com/identity-com/on-chain-identity-gateway.git", rev = "f58a874ce1e435063e091392dfe4b4874f5a71cb" }
84 changes: 38 additions & 46 deletions candy-machine/program/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
pub mod utils;

use solana_program::sysvar::{instructions::get_instruction_relative, SysvarId};
use {
crate::utils::{
assert_initialized, assert_is_ata, assert_keys_equal, assert_owned_by,
Expand Down Expand Up @@ -31,10 +30,13 @@ use {
},
utils::{assert_derivation, create_or_allocate_account_raw},
},
solana_gateway::state::{GatewayTokenAccess, InPlaceGatewayToken},
solana_program::sysvar::{instructions::get_instruction_relative, SysvarId},
spl_token::state::Mint,
std::{cell::RefMut, ops::Deref, str::FromStr},
};
anchor_lang::declare_id!("cndy3Z4yapfJBmL3ShUp5exZKqR3z33thTzeNMm2gRZ");
// 10 minutes
const EXPIRE_OFFSET: i64 = 10 * 60;
const PREFIX: &str = "candy_machine";
// here just in case solana removes the var
Expand Down Expand Up @@ -90,17 +92,26 @@ pub mod candy_machine {
return Err(ErrorCode::GatewayTokenMissing.into());
}
let gateway_token_info = &ctx.remaining_accounts[remaining_accounts_counter];
let gateway_token = ::solana_gateway::borsh::try_from_slice_incomplete::<
::solana_gateway::state::GatewayToken,
>(*gateway_token_info.data.borrow())?;
// stores the expire_time before the verification, since the verification
// will update the expire_time of the token and we won't be able to
// calculate the creation time
let expire_time = gateway_token
.expire_time
.ok_or(ErrorCode::GatewayTokenExpireTimeInvalid)?
as i64;
remaining_accounts_counter += 1;

// Eval function used in the gateway CPI
let eval_function = |token: &InPlaceGatewayToken<&[u8]>| match (
&candy_machine.data,
token.expire_time(),
) {
(
CandyMachineData {
go_live_date: Some(go_live_date),
whitelist_mint_settings: Some(WhitelistMintSettings { presale, .. }),
..
},
Some(expire_time),
) if !*presale && expire_time < go_live_date + EXPIRE_OFFSET => {
Err(ErrorCode::GatewayTokenExpireTimeInvalid.into())
}
_ => Ok(()),
};

if gatekeeper.expire_on_use {
if ctx.remaining_accounts.len() <= remaining_accounts_counter {
return Err(ErrorCode::GatewayAppMissing.into());
Expand All @@ -112,47 +123,23 @@ pub mod candy_machine {
}
let network_expire_feature = &ctx.remaining_accounts[remaining_accounts_counter];
remaining_accounts_counter += 1;
::solana_gateway::Gateway::verify_and_expire_token(
::solana_gateway::Gateway::verify_and_expire_token_with_eval(
gateway_app.clone(),
gateway_token_info.clone(),
payer.deref().clone(),
&gatekeeper.gatekeeper_network,
network_expire_feature.clone(),
eval_function,
)?;
} else {
::solana_gateway::Gateway::verify_gateway_token_account_info(
::solana_gateway::Gateway::verify_gateway_token_with_eval(
gateway_token_info,
&payer.key(),
&gatekeeper.gatekeeper_network,
None,
eval_function,
)?;
}
// verifies that the gatway token was not created before the candy
// machine go_live_date (avoids pre-solving the captcha)
match candy_machine.data.go_live_date {
Some(val) => {
if (expire_time - EXPIRE_OFFSET) < val {
if let Some(ws) = &candy_machine.data.whitelist_mint_settings {
// when dealing with whitelist, the expire_time can be
// before the go_live_date only if presale enabled
if !ws.presale {
msg!(
"Invalid gateway token: calculated creation time {} and go_live_date {}",
expire_time - EXPIRE_OFFSET,
val);
return Err(ErrorCode::GatewayTokenExpireTimeInvalid.into());
}
} else {
msg!(
"Invalid gateway token: calculated creation time {} and go_live_date {}",
expire_time - EXPIRE_OFFSET,
val);
return Err(ErrorCode::GatewayTokenExpireTimeInvalid.into());
}
}
}
None => {}
}
}

if let Some(ws) = &candy_machine.data.whitelist_mint_settings {
Expand Down Expand Up @@ -440,10 +427,7 @@ pub mod candy_machine {

let discriminator = &previous_instruction.data[0..8];
if discriminator != [211, 57, 6, 167, 15, 219, 35, 251] {
msg!(
"Transaction had ix with data {:?}",
discriminator
);
msg!("Transaction had ix with data {:?}", discriminator);
return Err(ErrorCode::SuspiciousTransaction.into());
}

Expand All @@ -452,11 +436,15 @@ pub mod candy_machine {
let mint_ix_metadata = mint_ix_accounts[4].pubkey;
let signer = mint_ix_accounts[6].pubkey;
let candy_key = ctx.accounts.candy_machine.key();
let metadata = ctx.accounts.metadata.key();
let metadata = ctx.accounts.metadata.key();
let payer = ctx.accounts.payer.key();

if &signer != &payer {
msg!("Signer with pubkey {} does not match the mint ix Signer with pubkey {}", mint_ix_cm, candy_key);
msg!(
"Signer with pubkey {} does not match the mint ix Signer with pubkey {}",
mint_ix_cm,
candy_key
);
return Err(ErrorCode::SuspiciousTransaction.into());
}
if &mint_ix_cm != &candy_key {
Expand All @@ -478,7 +466,11 @@ pub mod candy_machine {
return Err(ErrorCode::MismatchedCollectionMint.into());
}
let seeds = [b"collection".as_ref(), candy_key.as_ref()];
let bump = assert_derivation(&candy_machine::id(), &collection_pda.to_account_info(), &seeds)?;
let bump = assert_derivation(
&candy_machine::id(),
&collection_pda.to_account_info(),
&seeds,
)?;
let signer_seeds = [b"collection".as_ref(), candy_key.as_ref(), &[bump]];
let set_collection_infos = vec![
ctx.accounts.metadata.to_account_info(),
Expand Down