4

I am very new to Solana. I have a client's rust Program, it mint NFTs and allow admin who deployed the Solana Program to change the price. I have to add functionality to change the Sol price once X amount of NFTs is minted or the current sale time ended. Any code snippet that might be helpful for me or from where to get started?

Deployed Program on Devnet: https://explorer.solana.com/address/BkdiSpTX4Kumr92TZtxZnQWsNH4sjnjs1hTfzXdV8Uef?cluster=devnet

This is my first time reading rust code. I think that's the code in smart contract that i need to focus on.

      ctx: Context<MintNFT>,
      creator_key: Pubkey,
      // _uri: String,
      title: String,
      _nonce_minting: u8,
      _nonce_user_minting: u8,
  ) -> ProgramResult {
          // set user minting info
      let mut _max_num = ctx.accounts.minting_account.bl_max;
      let mut _price = ctx.accounts.minting_account.bl_price;
      let mut _state = 3;

//sale type 1: OG (pre-sale before whitelist sale)
      match ctx.accounts.minting_account.og_list.iter().position(|og| { *og == ctx.accounts.payer.key().to_string() }) {
              Some(_index) => {
                  _max_num = ctx.accounts.minting_account.og_max;
                  _price = ctx.accounts.minting_account.og_price;
                  _state = 1;
              }
              None => {}
          } 

//sale type 2: WL(white list sale)
      match ctx.accounts.minting_account.wl_list.iter().position(|og| { *og == ctx.accounts.payer.key.key().to_string() }) {
              Some(_index) => {
                  _max_num = ctx.accounts.minting_account.wl_max;
                  _price = ctx.accounts.minting_account.wl_price;
                  _state = 2;
              }
              None => {}
          } 

//sale type 3: bl (public sale)
      match ctx.accounts.minting_account.bl_list.iter().position(|og| { *og == ctx.accounts.payer.key.key().to_string() }) {
              Some(_index) => {
                  _state = 5;
              }
              None => {}
          } 
      
      if ctx.accounts.minting_account.max_teacher <= ctx.accounts.minting_account.cur_num
          || ctx.accounts.minting_account.cur_stage != _state || ctx.accounts.user_minting_counter_account.cur_num >= _max_num {
          return Err(MyError::InvalidOperation.into());
      }
      // msg!("Jerry!");
      // msg!(&_price.to_string());
      // **ctx.accounts.payer.to_account_info().try_borrow_mut_lamports()? -= _price;
      // **ctx.accounts.owner.to_account_info().try_borrow_mut_lamports()? += _price;
      msg!("Initializing Mint Ticket");
      let cpi_accounts = MintTo {
          mint: ctx.accounts.mint.to_account_info(),
          to: ctx.accounts.token_account.to_account_info(),
          authority: ctx.accounts.payer.to_account_info(),
      };
      msg!("CPI Accounts Assigned");
      let cpi_program = ctx.accounts.token_program.to_account_info();
      msg!("CPI Program Assigned");
      let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
      msg!("CPI Context Assigned");
      token::mint_to(cpi_ctx, 1)?;
      msg!("Token Minted !!!");
      let account_info = vec![
          ctx.accounts.metadata.to_account_info(),
          ctx.accounts.mint.to_account_info(),
          ctx.accounts.mint_authority.to_account_info(),
          ctx.accounts.payer.to_account_info(),
          ctx.accounts.token_metadata_program.to_account_info(),
          ctx.accounts.token_program.to_account_info(),
          ctx.accounts.system_program.to_account_info(),
          ctx.accounts.rent.to_account_info(),
      ];
      msg!("Account Info Assigned");
      let creator = vec![
          mpl_token_metadata::state::Creator {
              address: creator_key,
              verified: false,
              share: 100,
          },
          mpl_token_metadata::state::Creator {
              address: ctx.accounts.mint_authority.key(),
              verified: false,
              share: 0,
          },
      ];
      
      let new_uri = format!("{}{}{}",ctx.accounts.minting_account.base_uri, ctx.accounts.minting_account.cur_num , ".json");

      msg!("Creator Assigned");
      let symbol = std::string::ToString::to_string("symb");
      invoke(
          &create_metadata_accounts_v2(
              ctx.accounts.token_metadata_program.key(),
              ctx.accounts.metadata.key(),
              ctx.accounts.mint.key(),
              ctx.accounts.mint_authority.key(),
              ctx.accounts.payer.key(),
              ctx.accounts.payer.key(),
              title,
              symbol,
              new_uri,
              Some(creator),
              1,
              true,
              false,
              None,
              None,
          ),
          account_info.as_slice(),
      )?;
      msg!("Metadata Account Created !!!");
      let master_edition_infos = vec![
          ctx.accounts.master_edition.to_account_info(),
          ctx.accounts.mint.to_account_info(),
          ctx.accounts.mint_authority.to_account_info(),
          ctx.accounts.payer.to_account_info(),
          ctx.accounts.metadata.to_account_info(),
          ctx.accounts.token_metadata_program.to_account_info(),
          ctx.accounts.token_program.to_account_info(),
          ctx.accounts.system_program.to_account_info(),
          ctx.accounts.rent.to_account_info(),
      ];
      msg!("Master Edition Account Infos Assigned");
      invoke(
          &create_master_edition_v3(
              ctx.accounts.token_metadata_program.key(),
              ctx.accounts.master_edition.key(),
              ctx.accounts.mint.key(),
              ctx.accounts.payer.key(),
              ctx.accounts.mint_authority.key(),
              ctx.accounts.metadata.key(),
              ctx.accounts.payer.key(),
              Some(0),
          ),
          master_edition_infos.as_slice(),
      )?;
      msg!("Master Edition Nft Minted !!!");
      ctx.accounts.user_minting_counter_account.cur_num += 1;
      ctx.accounts.minting_account.cur_num += 1;
      Ok(())
  }

}
#[derive(Accounts)]
#[instruction(_nonce_minting: u8)] 

1 Answer 1

4

Change the Sol price once X amount of NFTs is minted or the current sale time ended. You have a global counter of minted NFTs - ctx.accounts.minting_account.cur_num. So to change price once X amount of NFTs is minted, you should also check this cur_num and depending on the amount of minted NFTs, modify the price. For the time u have timestamps. For example:

let cur_num = ctx.accounts.minting_account.cur_num.clone();
// If more than 1000 NFTs were minted, we double the price
if cur_num > 1000 {
_price = _price * 2;
};
// If some timestamp was passed, we triple the price
if Clock::get().unwrap().unix_timestamp > 16_655_521_949 {
_price = _price * 3;
};
// If timestamp === 
msg!(&_price.to_string());
**ctx.accounts.payer.to_account_info().try_borrow_mut_lamports()? -= _price;
**ctx.accounts.owner.to_account_info().try_borrow_mut_lamports()? += _price;

So here is the basic - u compare current time and current amount of minted NFTs. Now u could extend your however u want.

You store mint configuration in MintingAccount, so you should consider adjusting it and add some additional data you need.

For example, for timestamps, you could add

pub og_end_timestamp: i64,
pub wl_end_timestamp: i64,
pub public_end_timestamp: i64

to your MintingAccount struct, so the program will have access to the timestamps of end of the mint process. And with this info you might do what you want to - as far as u asked about the price, once the sale ended:

let public_end_timestamp = ctx.accounts.minting_account.public_end_timestamp;
let current_timestamp: i64 = Clock::get().unwrap().unix_timestamp;
if public_end_timestamp < current_timestamp {
_price = _price * 2;
};

Same about amounts of minted NFTs. You could add any amount barriers u want to, for example, you could add something like that to your MintingAccount:

pub total_minted_stages: Vec<TotalMintedStage>,

where TotalMintedStage is

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct TotalMintedStage {
    pub min_minted_nfts: u64,
    pub max_minted_nfts: u64,
    pub price: u64
}

And so with this additional info in ur MintingAccount, you might iterate over the list of those TotalMintedStages and find the one (if exists) that is the best for you:

let cur_num = ctx.accounts.minting_account.cur_num.clone();
// Find any stage that is matching current amount of minted NFTs
match ctx.accounts.minting_account.total_minted_stages.iter().position(|stage| { *stage.min_minted_nfts <= cur_num && *stage.max_minted_nfts >= cur_num }) {
              Some(index) => {
// And if found - modify the price
                  _price = ctx.accounts.minting_account.total_minted_stages[index].price;
              }
              None => {}
          } 

So here are just some examples of how u could do it. But it's always up to you!

And I believe github examples and Anchor, Rust, Solana & Metaplex docs will be the most helpful for u.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.